class IndexedNode(Node):

    """same as node, except the children section have their own indexes. to be used in nodes like Piece and Part, as both have
    children which have indexes applied to them in xml"""

    def __init__(self, **kwargs):
        Node.__init__(self, **kwargs)
        self.__delattr__("children")
        self.children = {}
        '''dictionary of children attached to this node'''

    def PopChild(self, key):
        if key in self.children:
            return self.children.pop(key)

    def GetChildrenIndexes(self):
        return list(self.children.keys())

    def GetChild(self, index):
        if index in self.children:
            return self.children[index]

    def AddChild(self, item, index=-1):
        if index == -1:
            index = len(self.children) - 1
        self.children[index] = item def BackwardSearch(cls_type, node, index, depth=0, start_index=0):
    '''
    Helper method which backwards-recursively searches for objects
    :param cls_type: class type of the object we are in search of
    :param node: object instance to start at
    :param index: number of the object to look for e.g <cls_type> num 1
    :param depth: current depth in the tree
    :param start_index: index to start with in children
    :return: object <index> of <cls_type>
    '''
    counter = depth
    if isinstance(node, cls_type):
        counter += 1
        if counter == index:
            return node
    if node is None:
        return None
    else:
        children = node.GetChildrenIndexes()
        if len(children) == 0 and isinstance(node, cls_type):
            return counter
        else:
            children.reverse()
            for child in children:
                result = Search(
                    cls_type,
                    node.GetChild(child),
                    index,
                    depth=counter)
                if isinstance(result, int):
                    counter = result
                    if counter == index:
                        return node.GetChild(child)
                if isinstance(result, cls_type):
                    return result
            if isinstance(node, cls_type):
                if counter == index:
                    return node
                else:
                    return counter def Search(cls_type, node, index, depth=0, start_index=0):
    '''
    recursive method that goes through finding the "index"th object of cls_type. outside of piecetree
    so that it can be used by any node
    :param cls_type: class type of the object we are in search of
    :param node: object instance to start at
    :param index: number of the object to look for e.g <cls_type> num 1
    :param depth: current depth in the tree
    :param start_index: index to start with in children
    :return: object <index> of <cls_type>
    '''
    counter = depth
    if isinstance(node, cls_type):
        counter += 1
        if counter == index:
            return node
    if node is None:
        return None
    else:
        children = node.GetChildrenIndexes()
        if len(children) == 0 and isinstance(node, cls_type):
            return counter
        else:
            for child in children:
                result = Search(
                    cls_type,
                    node.GetChild(child),
                    index,
                    depth=counter)
                if isinstance(result, int):
                    counter = result
                    if counter == index:
                        return node.GetChild(child)
                if isinstance(result, cls_type):
                    return result
            if isinstance(node, cls_type):
                if counter == index:
                    return node
                else:
                    return counter class VoiceNode(Node):

    def __init__(self):
        Node.__init__(self, rules=[NoteNode.NoteNode, NoteNode.Placeholder])
        self.note_total = 0
        self.note_types = []

    def addNoteDuration(self, duration):
        self.note_total += duration
        self.note_types.append(duration)

    def removeNoteDuration(self, duration):
        self.note_total -= duration
        self.note_types.remove(duration)

    def GetAllNoteTypes(self):
        """ method to collect all note values from each node

        :return: list of note values
        """
        return self.note_types

    def RunNoteChecks(self):
        children = self.GetChildrenIndexes()
        previous = None
        for child in range(len(children)):
            note = self.GetChild(children[child])
            item = note.GetItem()
            if item is not None and isinstance(note, NoteNode.NoteNode):
                # look for arpeggiates or non-arpeggiates, and update the note's childnodes
                # used where a note is part of a chord (usually the case in
                # arpeggiates)
                arpeg = item.Search(Arpeggiate)
                narpeg = item.Search(NonArpeggiate)
                if arpeg is not None or narpeg is not None:
                    note.UpdateArpeggiates()

                # now look for gracenotes
                result = item.Search(GraceNote)
                if result is not None and previous is None:
                    # if this is the first note in the bar, it must be the
                    # first gracenote
                    result.first = True

                if len(children) == child + 1:
                    # if we're at the last note...
                    if result is not None:
                        # same check as arpeggiates - handles the case where
                        # notes are part of a chord
                        note.CheckForGraceNotes()

                    # look for timemods
                    if hasattr(item, "timeMod"):
                        result = item.Search(Tuplet)
                        if result is None:
                            item.close_timemod = True
                        if previous is not None:
                            if hasattr(previous.GetItem(), "timeMod"):
                                item.timeMod.first = False
                            else:
                                item.timeMod.first = True
                        else:
                            item.timeMod.first = True
                    else:
                        item.close_timemod = False
                else:
                    # otherwise check the next item for gracenotes and time
                    # mods
                    next = self.GetChild(children[child + 1])
                    next_item = next.GetItem()
                    if next_item is not None and isinstance(
                            next,
                            NoteNode.NoteNode):
                        result = item.Search(GraceNote)
                        next_result = next_item.Search(GraceNote)
                        if result is not None:
                            if next_result is None:
                                note.CheckForGraceNotes()
                            else:
                                result.last = False
                                next_result.first = False
                        if hasattr(item, "timeMod"):
                            res = item.Search(Tuplet)

                            if not hasattr(
                                    next_item,
                                    "timeMod") and res is None:
                                item.close_timemod = True
                            else:
                                item.close_timemod = False

                            # not sure if checking next and previous is
                            # necessary?
                            if previous is not None and isinstance(
                                    previous,
                                    NoteNode.NoteNode):
                                if hasattr(previous.GetItem(), "timeMod"):
                                    item.timeMod.first = False
                                else:
                                    item.timeMod.first = True
                            else:
                                item.timeMod.first = True
            previous = note

    def toLily(self):
        '''
        Method which converts the object instance, its attributes and children to a string of lilypond code

        :return: str of lilypond code
        '''

        lilystring = ""
        children = self.GetChildrenIndexes()
        total = self.note_total
        counter = 0
        for child in range(len(children)):
            note = self.GetChild(children[child])
            item = note.GetItem()
            if item is not None:
                item.autoBeam = self.autoBeam
            if hasattr(note, "duration"):
                try:
                    counter += int(note.duration)
                except:
                    if note.duration == "\\longa":
                        counter += 0.25
                    if note.duration == "\\breve":
                        counter += 0.5
            if counter > total / 2:
                if hasattr(self, "mid_barline"):
                    lilystring += self.mid_barline.toLily()
                    self.__delattr__("mid_barline")
            if hasattr(self, "rest") and hasattr(self, "total"):
                lilystring += "R" + self.total
            else:
                lilystring += note.toLily() + " "
        return lilystring class DirectionNode(SelfNode):
    pass class ExpressionNode(SelfNode):
    pass class KeyNode(Node):

    def __init__(self):
        Node.__init__(self, limit=-1)

    def toLily(self):
        lstring = ""
        if self.item is not None:
            lstring += self.item.toLily()
        return lstring class ClefNode(KeyNode):
    pass class NoteNode(Node):

    """Node which encapsulates the Note class.


    Optional inputs are minimal on this one as info about the note itself is stored in the Note class.


    In order to maintain lilypond's output flow, Notes have a specific child order:

        - left: Expression (dynamic or other expressive thing that has to be attached to a note)

        - middle: Any other notes, if this note is part of a chord

        - right: direction (anything that's not a note or expression)"""

    def __init__(self, **kwargs):
        if "duration" in kwargs:
            self.duration = kwargs["duration"]
        Node.__init__(
            self,
            rules=[
                OtherNodes.DirectionNode,
                OtherNodes.ExpressionNode,
                NoteNode],
            limit=3)
        if self.item is None:
            self.item = Note.Note()

    def Find(self, node_type, item_type):
        '''
        method for finding specific types of notation from nodes.
        will currently return the first one it encounters because this method's only really intended
        for some types of notation for which the exact value doesn't really
        matter.


        :param node_type: the type of node to look under

        :param item_type: the type of item (notation) being searched for

        :return: first item_type object encountered
        '''

        if node_type == OtherNodes.DirectionNode:
            child = self.GetChild(len(self.children) - 1)
            while child is not None and not isinstance(
                    child.GetItem(),
                    item_type):
                if child.GetItem().__class__.__name__ == item_type.__name__:
                    return True
                child = child.GetChild(0)
        if node_type == OtherNodes.ExpressionNode:
            child = self.GetChild(len(self.children) - 2)
            while child is not None and not isinstance(
                    child.GetItem(),
                    item_type):
                if child.GetItem().__class__.__name__ == item_type.__name__:
                    return True
                child = child.GetChild(0)

    def SetGrace(self):
        if self.item.Search(GraceNote) is None:
            self.item.addNotation(GraceNote())

    def SetLast(self):
        result = self.item.Search(GraceNote)
        if result is not None:
            result.last = True

    def UpdateArpeggiates(self, type="start"):
        '''
        method which searches for all arpeggiates and updates the top one of each chord to be a start,
        and the bottom one to be a stop ready for lilypond output
        :param type:
        :return:
        '''
        result = self.item.Search(Arpeggiate)
        if result is not None:
            if type == "start":
                result.type = type
            child = self.GetChild(0)
            if child is not None:
                if child.item.Search(Arpeggiate) is None:
                    new_obj = copy.deepcopy(result)
                    new_obj.type = "none"
                    child.GetItem().addNotation(new_obj)
                if child is not None and hasattr(child, "UpdateArpeggiates"):
                    child.UpdateArpeggiates(type="stop")
            else:
                result.type = type
        else:
            result = self.item.Search(NonArpeggiate)
            if result is not None:
                if type == "start":
                    result.type = type
                child = self.GetChild(0)
                if child is not None:
                    search = child.item.Search(NonArpeggiate)
                    if search is None:
                        cpy = copy.deepcopy(result)
                        cpy.type = "none"
                        child.item.addNotation(cpy)
                    if hasattr(child, "UpdateArpeggiates"):
                        child.UpdateArpeggiates(type="bottom")
                else:
                    result.type = type

    def SetItem(self, new_item):
        Node.SetItem(self, new_item)
        if hasattr(new_item, "duration"):
            self.duration = new_item.duration
        else:
            self.duration = 0

    def CheckForGraceNotes(self):
        result = self.item.Search(GraceNote)
        if result is not None:
            first_child = self.GetChild(0)
            if isinstance(self.GetChild(0), NoteNode):
                first_child.SetGrace()
                first_child.CheckForGraceNotes()
            else:
                self.SetLast()

    def AttachDirection(self, item):
        if item.GetItem().__class__.__name__ == OctaveShift.__name__:
            self.shift = True
        if len(self.children) == 0:
            self.AttachExpression(OtherNodes.ExpressionNode())
            self.AddChild(item)
        elif 3 > len(self.children) > 0:
            if not isinstance(self.GetChild(0), NoteNode):
                if not isinstance(self.GetChild(0), OtherNodes.ExpressionNode):
                    self.AttachExpression(OtherNodes.ExpressionNode())
                dir = self.GetChild(1)
                if isinstance(dir, OtherNodes.DirectionNode):
                    parent = FindPosition(dir, item)
                    if parent is not None:
                        parent.AddChild(item)
                elif dir is None:
                    self.AddChild(item)
            elif not isinstance(self.GetChild(1), ExpressionNode):
                self.AttachExpression(ExpressionNode())
                self.AddChild(item)
        else:
            dir_node = self.GetChild(len(self.children) - 1)
            if dir_node is not None:
                if dir_node.GetItem() is None:
                    dir_node.SetItem(item.GetItem())
                else:
                    parent = FindPosition(dir_node, item)
                    if parent is not None:
                        parent.AddChild(item)
            else:
                self.AddChild(item)

    def AttachExpression(self, new_node):
        if len(self.children) > 0:
            if isinstance(self.GetChild(0), OtherNodes.DirectionNode):
                self.PositionChild(0, new_node)
            if isinstance(self.GetChild(0), NoteNode):
                second = self.GetChild(1)
                if second is None:
                    self.AddChild(new_node)
                elif isinstance(second, OtherNodes.ExpressionNode):
                    node = FindPosition(second, new_node)
                    node.AddChild(new_node)
                else:
                    self.PositionChild(1, new_node)
            elif isinstance(self.GetChild(0), OtherNodes.ExpressionNode):
                parent = self.GetChild(0)
                node = FindPosition(parent, new_node)
                node.AddChild(new_node)
        else:
            self.AddChild(new_node)

    def AttachNote(self, new_note):

        if len(self.children) > 0:
            firstchild = self.GetChild(0)
            if isinstance(firstchild, NoteNode):
                firstchild.AttachNote(new_note)
            else:
                if not isinstance(
                        new_note.GetItem(),
                        int) and not isinstance(
                        new_note.GetItem(),
                        str):
                    post, pre, wrap = new_note.GetItem().GetAllNotation()
                    [self.GetItem().addNotation(n)
                     for n in post if self.GetItem().Search(type(n)) is None]
                    [self.GetItem().addNotation(p)
                     for p in pre if self.GetItem().Search(type(p)) is None]
                    [self.GetItem().addNotation(w)
                     for w in wrap if self.GetItem().Search(type(w)) is None]
                    new_note.GetItem().FlushNotation()
                self.PositionChild(0, new_note)
        else:
            if not isinstance(
                    new_note.GetItem(),
                    int) and not isinstance(
                    new_note.GetItem(),
                    str):
                post, pre, wrap = new_note.GetItem().GetAllNotation()
                [self.GetItem().addNotation(n)
                 for n in post if self.GetItem().Search(type(n)) is None]
                [self.GetItem().addNotation(p)
                 for p in pre if self.GetItem().Search(type(p)) is None]
                [self.GetItem().addNotation(w)
                 for w in wrap if self.GetItem().Search(type(w)) is None]
                new_note.GetItem().FlushNotation()
            self.AddChild(new_note)

    def toLily(self):
        '''
        Method which converts the object instance, its attributes and children to a string of lilypond code

        :return: str of lilypond code
        '''
        lilystring = ""
        if self.item is not None:
            if not isinstance(self.GetChild(0), NoteNode):
                if hasattr(self.item, "chord") and self.item.chord:
                    self.item.chord = "stop"
            if isinstance(self.GetChild(0), NoteNode):
                if not hasattr(self.item, "chord") or not self.item.chord:
                    self.item.chord = "start"
            lilystring += self.item.toLily()
        children = self.GetChildrenIndexes()
        written = False
        for child in children:
            if self.GetChild(child) is not None:
                if isinstance(self.GetChild(child), NoteNode):
                    lilystring += " "
                return_val = self.GetChild(child).toLily()
                if isinstance(return_val, str):
                    lilystring += return_val
                else:
                    lilystring = return_val[0] + lilystring + return_val[1]
                if isinstance(child, OtherNodes.ExpressionNode):
                    written = True
                    lilystring += self.item.GetClosingNotationLilies()

        if len(children) == 0 or not written:
            lilystring += self.item.GetClosingNotationLilies()
        return lilystring

    def PositionChild(self, key, node):
        children = self.GetChildrenIndexes()
        if key in children:
            start = key
            popped = self.children[start:]
            self.children = self.children[:start]
            self.AddChild(node)
            [self.AddChild(pop) for pop in popped] class Text(BaseClass.Base):
class CreditText(Text):
class Lyric(Text):
class Direction(Text):
class RehearsalMark(Direction):
class Forward(Direction):
class RepeatSign(Direction):
class Line(Direction):
class OctaveShift(Line):
class WavyLine(Line):
class Pedal(Line):
class Bracket(Line):
class Metronome(Direction):
class Dynamic(Direction):
class Wedge(Dynamic):
class Slur(Direction):
    def __init__(self, **kwargs):
    def get(self):
    def toLily(self):
    def __init__(self, **kwargs):
    def toLily(self):
    def __init__(self, **kwargs):
    def __init__(self, **kwargs):
    def toLily(self):
    def toLily(self):
    def __init__(self, **kwargs):
    def toLily(self):
    def __init__(self, **kwargs):
    def toLily(self):
    def __init__(self, **kwargs):
    def __init__(self, **kwargs):
    def toLily(self):
    def toLily(self):
    def __init__(self, **kwargs):
    def toLily(self):
    def __init__(self, **kwargs):
    def toLily(self):
    def __init__(self, **kwargs):
    def toLily(self):
    def get_detail(self):
    def __init__(self, **kwargs):
    def toLily(self):
    def __init__(self, **kwargs):
    def toLily(self):
    def __init__(self, **kwargs):
    def toLily(self): def SplitString(value):
def GetID(attrs, tag, val):
def NumbersToWords(number): class OctaveShift(Line):

    """
    Class representing specifically octave shifts


    # Optional inputs

        - amount: the amount to shift up/down octaves. Int, generally 8 or 15 depending on whether 1 or 2

        - type: type of shift - up/down.

    """

    def __init__(self, **kwargs):
        placement = None
        text = None
        font = None
        size = None
        type = None
        if "amount" in kwargs:
            if kwargs["amount"] is not None:
                self.amount = kwargs["amount"]
        if "placement" in kwargs:
            placement = kwargs["placement"]

        if "text" in kwargs:
            text = kwargs["text"]
        if "size" in kwargs:
            size = kwargs["size"]
        if "font" in kwargs:
            font = kwargs["font"]
        if "type" in kwargs:
            if kwargs["type"] is not None:
                type = kwargs["type"]
        Line.__init__(
            self,
            text=text,
            type=type,
            size=size,
            font=font,
            placement=placement)

    def toLily(self):
        return_val = "\n\ottava #"
        multiplier = 1
        octave = 0
        if hasattr(self, "type"):
            if self.type == "up":
                return_val += "-"

        if hasattr(self, "amount"):
            if self.amount == 8:
                octave = 1
            if self.amount == 15:
                octave = 2
        else:
            octave = 1

        return_val += str(octave) + "\n"
        if hasattr(self, "type"):
            if self.type == "stop":
                return_val = "\n\ottava #0"
        return return_val
import copy
from MuseParse.classes.ObjectHierarchy.TreeClasses.BaseTree import IndexedNode, BackwardSearch, Search
from MuseParse.classes.ObjectHierarchy.TreeClasses.VoiceNode import VoiceNode
from MuseParse.classes.ObjectHierarchy.TreeClasses.OtherNodes import DirectionNode, ExpressionNode, KeyNode, ClefNode
from MuseParse.classes.ObjectHierarchy.TreeClasses import NoteNode
from MuseParse.classes.ObjectHierarchy.ItemClasses import Directions
from MuseParse import helpers
from MuseParse.classes.ObjectHierarchy.ItemClasses.Directions import OctaveShift




class MeasureNode(IndexedNode):

    """
    Class representing the tree node for a measure.


    # Optional inputs:

        - partial: bool. Represents whether the bar is partial i.e a pickup or something


    # Optional attributes:

        - newSystem: boolean indicating to create a new system for this bar

        - newPage: boolean indicating to create a new page for this bar

        - key: Key class entry representing key sig

        - meter: meter class entry representing meter/time sig
    """

    def __init__(self, **kwargs):

        IndexedNode.__init__(self, rules=[VoiceNode])