class xmlSet(unittest.TestCase):

    def setUp(self):
        self.fname = ""
        self.note_num = 0
        self.parser = MxmlParser.MxmlParser()
        self.folder = "/Users/charlottegodley/PycharmProjects/FYP/implementation/primaries/SampleMusicXML/testcases" def parsePiece(name):
    parser = MxmlParser.MxmlParser()
    return parser.parse(name) 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): class Barline(BaseClass.Base):
class EndingMark(BaseClass.Base):
class Transposition(BaseClass.Base):
    def __init__(self, **kwargs):
    def toLily(self):
    def __init__(self, **kwargs):
    def toLily(self):
    def __init__(self, **kwargs): class PartNode(IndexedNode):
    """
    Class representing the node holding the part.
    """

    def __init__(self, index=0):
        IndexedNode.__init__(self, rules=[StaffNode])
        self.index = index
        if self.item is None:
            self.item = Part.Part()

    def NewBeam(self, type, staff):
        staff_obj = self.getStaff(staff)
        staff_obj.NewBeam(type)

    def Backup(self, measure_id, duration=0):
        staves = self.GetChildrenIndexes()
        for staff_id in staves:
            staff = self.GetChild(staff_id)
            measure = staff.GetChild(measure_id)
            if measure is not None:
                measure.Backup(duration=duration)

    def Forward(self, measure_id, duration=0):
        staves = self.GetChildrenIndexes()
        for staff_id in staves:
            staff = self.GetChild(staff_id)
            measure = staff.GetChild(measure_id)
            if measure is not None:
                measure.Forward(duration=duration)

    def AddBarline(self, staff=1, measure=1, location="left", item=None):
        staff_obj = self.getStaff(staff)
        if staff_obj is None:
            self.AddChild(StaffNode(), staff)
            staff_obj = self.getStaff(staff)
        staff_obj.AddBarline(measure_id=measure, location=location, item=item)

    def DoBarlineChecks(self):
        staves = self.GetChildrenIndexes()
        for s in staves:
            staff = self.getStaff(s)
            staff.DoBarlineChecks()

    def CheckDivisions(self):
        staves = self.GetChildrenIndexes()
        for staff in staves:
            child = self.getStaff(staff)
            child.CheckDivisions()

    def CheckTotals(self):
        """method to calculate the maximum total lilypond value for a measure without a time signature"""
        staves = self.GetChildrenIndexes()
        for staff in staves:
            child = self.getStaff(staff)
            child.CheckTotals()

    def CheckMeasureDivisions(self, measure):
        divisions = None
        staves = self.GetChildrenIndexes()
        for staff in staves:
            measure_obj = self.getMeasure(measure, staff)
            if measure_obj is not None:
                if hasattr(measure_obj.GetItem(), "divisions"):
                    divisions = measure_obj.GetItem().divisions
                elif divisions is not None:
                    measure_obj.GetItem().divisions = divisions

    def CheckPreviousBarline(self, staff):
        """method which checks the bar before the current for changes we need to make to it's barlines"""
        measure_before_last = self.getMeasureAtPosition(-2, staff)
        last_measure = self.getMeasureAtPosition(-1, staff)
        if last_measure is not None and measure_before_last is not None:
            bline1 = measure_before_last.GetBarline("right")
            bline2 = last_measure.GetBarline("left")
            if bline1 is not None:
                if hasattr(bline1, "ending"):
                    if bline2 is not None:
                        if not hasattr(bline2, "ending"):
                            bline1.ending.type = "discontinue"
                    else:
                        bline1.ending.type = "discontinue"

    def CheckMeasureMeter(self, measure):
        meter = None
        staves = self.GetChildrenIndexes()
        for staff in staves:
            measure_obj = self.getMeasure(measure, staff)
            if measure_obj is not None:
                item = measure_obj.GetItem()
                if hasattr(item, "meter"):
                    meter = item.meter
                else:
                    if meter is not None:
                        item.meter = meter

    def setDivisions(self, measure=1, divisions=1):
        staves = self.GetChildrenIndexes()
        for staff in staves:
            measure_obj = self.getMeasure(measure, staff)
            measure_obj.GetItem().divisions = divisions

    def getMeasure(self, measure=1, staff=1):
        staff_obj = self.GetChild(staff)
        measure_obj = None
        if staff_obj is not None:
            measure_obj = staff_obj.GetChild(measure)
        return measure_obj

    def getMeasureAtPosition(self, index, staff=1):
        staff_obj = self.getStaff(staff)
        children = staff_obj.GetChildrenIndexes()
        if abs(index) <= len(children):
            return self.getMeasure(children[index], staff)

    def getMeasureIDAtPosition(self, index, staff=1):
        staff_obj = self.getStaff(staff)
        children = staff_obj.GetChildrenIndexes()
        if abs(index) <= len(children):
            return children[index]

    def getStaff(self, key):
        return self.GetChild(key)

    def addMeasure(self, item, measure=1, staff=1):
        if self.getStaff(staff) is None:
            self.AddChild(StaffNode(), staff)
        staff_obj = self.getStaff(staff)
        staff_obj.AddChild(item, measure)

    def addEmptyMeasure(self, measure=1, staff=1):
        self.addMeasure(
            MeasureNode.MeasureNode(),
            measure=measure,
            staff=staff)

    def CalculateVariable(self, name, staves):
        variables = []
        for staff in staves:
            variable = ""
            if len(name) > 0:
                lcase = name.lower()
                no_spaces = lcase.replace(' ', '')
                no_dots = no_spaces.replace('.', '')
                variable = ""
                for letter in no_dots:
                    if letter in [str(i) for i in range(10)]:
                        variable += helpers.NumbersToWords(int(letter))
                    else:
                        variable += letter
            variable += "staff" + helpers.NumbersToWords(staff)
            variables.append(variable)
        return variables

    def addKey(self, item, measure_id):
        staves = self.GetChildrenIndexes()
        for staff_id in staves:
            measure = self.getMeasure(measure_id, staff_id)
            if measure is not None:
                measure.addKey(item)
            else:
                self.addEmptyMeasure(measure_id, staff_id)
                measure = self.getMeasure(measure_id, staff_id)
                if measure is not None:
                    measure.addKey(item)

    def addClef(self, item, measure_id, staff_id, voice):
        measure = self.getMeasure(measure_id, staff_id)
        if measure is not None:
            measure.addClef(item, voice)
        else:
            self.addEmptyMeasure(measure_id, staff_id)
            measure = self.getMeasure(measure_id, staff_id)
            if measure is not None:
                measure.addClef(item)
        if item.sign == "percussion":
            self.drum = True
        else:
            self.drum = False
        if item.sign == "tab":
            self.tab = True
        else:
            self.tab = False

    def CheckIfTabStaff(self):
        if hasattr(self, "tab") and self.tab:
            return "TAB"
        if hasattr(self, "drum") and self.drum:
            return "DRUM"

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

        :return: str of lilypond code
        '''
        self.CheckDivisions()
        self.CheckTotals()
        staves = self.GetChildrenIndexes()
        name = ""
        shortname = ""
        if hasattr(self.item, "name"):
            name = self.item.name
            name = helpers.SplitString(name)
        if hasattr(self.item, "shortname"):
            shortname = helpers.SplitString(self.item.shortname)
        variables = self.CalculateVariable(str(self.index), staves)
        first_part = ""
        for staff, variable in zip(staves, variables):
            staffstring = variable
            if hasattr(
                    self.GetChild(staff),
                    "tab") and self.GetChild(staff).tab:
                staffstring += " = \\new TabStaff"
            elif hasattr(self.GetChild(staff), "drum") and self.GetChild(staff).drum:
                staffstring += " = \\drums"
            else:
                staffstring += " = \\new Staff"
            if len(staves) == 1:
                if name != "":
                    staffstring += " \with {\n"
                    staffstring += "instrumentName = " + name + " \n"
                    if shortname != "":
                        staffstring += "shortInstrumentName = " + \
                            shortname + " \n"
                    staffstring += " }"
            staffstring += "{" + self.GetChild(staff).toLily() + " }\n\n"
            first_part += staffstring

        second_part = ""
        if len(variables) > 1:
            second_part += "\\new StaffGroup "
            if name != "":
                second_part += "\with {\n"
                second_part += "instrumentName = " + name + " \n"
                second_part += " }"
            second_part += "<<"
        second_part += "\n".join(["\\" + var for var in variables])
        if len(variables) > 1:
            second_part += ">>"
        return [first_part, second_part] 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])
        self.index = 0
        self.barlines = {}
        self.items = []
        self.autoBeam = False
        if "partial" in kwargs:
            if kwargs["partial"] is not None:
                self.partial = kwargs["partial"]
        self.gap = 0

    def addWrapper(self, item):
        # method to add any notation that needs to wrap the whole bar
        self.items.append(item)

    def CalculateTransposition(self):
        scale = [
            'a',
            'bes',
            'b',
            'c',
            'cis',
            'd',
            'dis',
            'e',
            'f',
            'fis',
            'g',
            'gis']
        base = 3
        result = base
        octave_shifters = "'"
        if hasattr(self.transpose, "chromatic"):
            chromatic = int(self.transpose.chromatic)
            result = base + chromatic

        elif hasattr(self.transpose, "diatonic"):
            diatonic = int(self.transpose.diatonic)
            result = base + (diatonic * 2)

        if result < 0:
            result = (len(scale) - 1) - result
            octave_shifters = ""
        if result >= len(scale):
            result = result - (len(scale) - 1)
            octave_shifters += "'"
        lettername = scale[result]

        if hasattr(self.transpose, "octave"):
            octave = self.transpose.octave

            if octave > 0:
                octave_shifters += "".join(["'" for i in range(octave)])
            if octave < 0:
                octave_shifters = ""
                if octave < -1:
                    octave_shifters += "".join(
                        ["," for i in range(abs(octave))])
        return "\\transpose c' " + lettername + octave_shifters + " {"

    def HandleAttributes(self):
        lilystring = ""
        if hasattr(self, "newSystem"):
            lilystring += "\\break "
        if hasattr(self, "newPage"):
            lilystring += "\\pageBreak "
        if hasattr(self, "clef") and self.clef is not None:
            lilystring += self.clef.toLily() + " "
        if hasattr(self, "key") and self.key is not None:
            if not hasattr(self.key, "mode"):
                self.key.mode = "major"
            lilystring += self.key.toLily() + " "
        if hasattr(self, "meter"):
            lilystring += self.meter.toLily() + " "
        if hasattr(self, "partial") and self.partial:
            lilystring += "\\partial " + str(self.getPartialLength()) + " "
        for item in self.items:
            if not hasattr(
                item,
                "type") or (
                hasattr(
                    item,
                    "type") and item.type != "stop"):
                lilystring += item.toLily()
        return lilystring

    def HandleClosingAttributes(self):
        lstring = ""
        for item in self.items:
            if hasattr(item, "type") and item.type == "stop":
                lstring += item.toLily()

        return lstring

    def getWrapper(self, index):
        if index < len(self.items):
            return self.items[index]

    def GetTotalValue(self):
        """Gets the total value of the bar according to it's time signature"""
        value = ""
        if hasattr(self, "meter"):
            top_value = self.meter.beats
            bottom = self.meter.type
            fraction = top_value / bottom
            if fraction == 1:
                value = "1"
            else:
                if fraction > 1:
                    value = "1."
                if fraction < 1:
                    if fraction >= 0.5:
                        fraction -= 0.5
                        value = "2"
                        if fraction == 0.25:
                            value += "."
        return value

    def AddBarline(self, item, location):
        if location != "left" and location != "right" and location != "center":
            if location not in self.barlines:
                self.barlines[location] = []
            self.barlines[location].append(item)
        else:
            self.barlines[location] = item

    def GetBarline(self, location):
        if location in self.barlines:
            return self.barlines[location]

    def GetLastKey(self, voice=1):
        """key as in musical key, not index"""

        voice_obj = self.GetChild(voice)
        if voice_obj is not None:
            key = BackwardSearch(KeyNode, voice_obj, 1)
            if key is not None:
                return key
            else:
                if hasattr(self, "key"):
                    return self.key
        else:
            if hasattr(self, "key"):
                return self.key

    def addKey(self, item, voice=1):
        if not hasattr(self, "key"):
            self.key = item
        else:
            if self.GetChild(voice) is None:
                self.addVoice(VoiceNode(), voice)
            voice_obj = self.GetChild(voice)
            node = KeyNode()
            node.SetItem(item)
            if voice_obj is not None:
                voice_obj.AddChild(node)
                self.index += 1

    def GetLastClef(self, voice=1):
        if self.GetChild(voice) is None:
            self.addVoice(VoiceNode(), voice)
        voice_obj = self.GetChild(voice)
        if voice_obj is not None:
            key = BackwardSearch(ClefNode, voice_obj, 1)
            if key is not None:
                return key
            else:
                if hasattr(self, "clef"):
                    return self.clef

    def addClef(self, item, voice=1):
        '''
        method to use when adding a clef. will either add it to the node itself or add it onto the first voice's children
        list
        :param item:
        :param voice:
        :return:
        '''
        if not hasattr(self, "clef"):
            self.clef = item
        else:
            voice_obj = self.GetChild(voice)
            node = ClefNode()
            node.SetItem(item)
            if voice_obj is not None:
                voice_obj.AddChild(node)
                self.index += 1

    def CheckDivisions(self):
        children = self.GetChildrenIndexes()
        divisions = self.divisions
        for child in children:
            voice = self.GetChild(child)
            indexes = voice.GetChildrenIndexes()
            for i in indexes:
                note = voice.GetChild(i)
                item = note.GetItem()
                if item is not None:
                    item.divisions = divisions

    def Forward(self, duration=0):
        '''
        method to use when forward tag is encountered in musicXML. jumps forward in the bar by <duration>
        :param duration: number of beats to move forward
        :return:
        '''
        for voice in self.GetChildrenIndexes():
            voice_obj = self.getVoice(voice)
            if voice_obj.GetChild(self.index) is None:
                voice_obj.AddChild(NoteNode.NoteNode(duration=duration))
        self.index += 1

    def Backup(self, duration=0):
        '''
        method to use when a backup tag is encountered in musicXML. Moves back in the bar by <duration>
        :param duration:
        :return:
        '''
        total = 0
        duration_total = duration * 4
        children = self.GetChildrenIndexes()
        notes = 0
        for voice in children:
            v = self.GetChild(voice)
            indexes = v.GetChildrenIndexes()
            if len(indexes) > 1:
                indexes.reverse()
            for index in indexes:
                notes += 1
                note = v.GetChild(index)
                if hasattr(note, "duration"):
                    total += note.duration
                    if total >= duration_total:
                        break
            gap = [
                v.GetChild(i).duration for i in range(
                    0,
                    self.index -
                    notes) if hasattr(
                    v.GetChild(i),
                    "duration")]
            previous = 0
            for item in gap:
                if item == previous:
                    self.gap -= previous
                    item = item / 2
                self.gap += item
                previous = item
            #self.gap = sum([])
        self.index -= notes

    def addVoice(self, item=None, id=1):
        if item is None:
            item = VoiceNode()
        self.AddChild(item, id)
        if self.gap != 0:
            voice = self.GetChild(id)
            voice.AddChild(NoteNode.Placeholder(duration=self.gap))
            self.gap = 0

    def getVoice(self, key):
        return self.GetChild(key)

    def PositionChild(self, item, key, voice=1):
        voice_obj = self.getVoice(voice)
        children = voice_obj.GetChildrenIndexes()
        if key in children:
            start_index = key
            end_index = len(children)
            popped = []
            for index in range(start_index, end_index):
                child = voice_obj.PopChild(index)
                if child is not None:
                    popped.append(child)
            voice_obj.AddChild(item)
            [voice_obj.AddChild(p) for p in popped]

    def addNote(self, item, voice=1, increment=1, chord=False):
        shift = 0
        # get the appropriate voice
        if self.getVoice(voice) is None:
            self.addVoice(VoiceNode(), voice)
        voice_obj = self.getVoice(voice)
        last = voice_obj.GetChild(self.index - 1)
        if last is not None and hasattr(last, "shift"):
            shift = True
        # set up a basic duration: this val will only be used for a placeholder
        duration = 0
        if not isinstance(
                item,
                NoteNode.NoteNode) and not isinstance(
                item,
                NoteNode.Placeholder):
            # wrap the item in a node if it isn't wrapped already
            if hasattr(item, "duration"):
                duration = item.duration

            node = NoteNode.NoteNode(duration=duration)
            node.SetItem(item)
            if shift != 0:
                node.shift = shift
        else:
            node = item
            if hasattr(node, "duration"):
                duration = node.duration
        if not chord:
            try:
                voice_obj.addNoteDuration(int(duration))
            except:
                if duration == "\\longa":
                    voice_obj.addNoteDuration(0.25)
                if duration == "\\breve":
                    voice_obj.addNoteDuration(0.5)
            # get whatever is at the current index
            placeholder = voice_obj.GetChild(self.index)
            if isinstance(
                    placeholder,
                    NoteNode.Placeholder) and not isinstance(
                    node,
                    NoteNode.Placeholder):
                # if it's an empty placeholder, replace it with a note
                if placeholder.duration == 0:
                    if hasattr(placeholder, "shift"):
                        children = placeholder.GetChildrenIndexes()
                        # this will need some recursion if we have multiple directions attached to a placeholder,
                        # but for now this should work.
                        for c in children:
                            child = placeholder.GetChild(c)
                            if child.GetItem(
                            ).__class__.__name__ == OctaveShift.__name__:
                                i = placeholder.PopChild(c)
                                voice_obj.ReplaceChild(
                                    self.index,
                                    copy.deepcopy(i))
                                self.index += 1
                    if voice_obj.GetChild(self.index) == placeholder:
                        voice_obj.ReplaceChild(self.index, node)
                    elif voice_obj.GetChild(self.index) is not None:
                        self.PositionChild(node, self.index, voice=voice)
                    else:
                        voice_obj.AddChild(node, self.index)
                    if not isinstance(node, NoteNode.Placeholder):
                        self.index += 1

            # nothing there? add our note
            elif placeholder is None:
                voice_obj.AddChild(node)
                if not isinstance(node, NoteNode.Placeholder):
                    self.index += 1
            else:
                proposed_node = voice_obj.GetChild(self.index)
                new_duration = voice_obj.GetChild(self.index).duration
                if proposed_node.GetItem() is None:
                    if hasattr(item, "duration"):
                        new_duration = item.duration
                    if new_duration == proposed_node.duration:
                        node.SetItem(node.GetItem())
                        voice_obj.removeNoteDuration(proposed_node.duration)
                        voice_obj.ReplaceChild(self.index, node)
                    elif new_duration > proposed_node.duration:
                        proposed_node.SetItem(node.GetItem())
                        proposed_node.duration = new_duration
                        voice_obj.removeNoteDuration(proposed_node.duration)
                    elif new_duration < proposed_node.duration:
                        voice_obj.removeNoteDuration(proposed_node.duration)
                        voice_obj.removeNoteDuration(new_duration)
                        proposed_node.duration -= new_duration
                        voice_obj.addNoteDuration(proposed_node.duration)
                        voice_obj.addNoteDuration(new_duration)
                        voice_obj.AddChild(node)
                        if not isinstance(node, NoteNode.Placeholder):
                            self.index += 1
                else:
                    self.PositionChild(node, self.index, voice=voice)

        else:
            # get whatever is at the current index
            placeholder = voice_obj.GetChild(self.index - 1)
            if placeholder.GetItem() is not None:
                if hasattr(placeholder.GetItem(), "beams"):
                    node.GetItem().beams = placeholder.GetItem().beams
            if placeholder is not None:
                placeholder.AttachNote(node)

    def getPartialLength(self):
        """ method to calculate how much to give the "partial" indicator where a measure is a pickup
        :return: str which is the lilypond bar length
        """
        indexes = self.GetChildrenIndexes()
        length = 0
        divider = 0
        total = 0
        result = ""
        for v in indexes:
            voice = self.GetChild(v)
            if voice.note_total > length:
                length = voice.note_total
                note_types = voice.GetAllNoteTypes()
                if len(note_types) == 1:
                    total = length
                    result = str(total)
                else:
                    note_types.sort()
                    total = note_types[0]
                    result = str(total)
                    previous = total
                    count = 0
                    for value in note_types[1:]:
                        if previous * 2 == value:
                            result += "."
                        if previous == value:
                            if total >= previous:
                                total -= previous
                            else:
                                total -= previous / 2
                            total += previous / 2
                            value = previous / 2
                        previous = value

                    first_digit = str(int(total))
                    result = first_digit + result[1:]

        return result

    def addPlaceholder(self, duration=0, voice=1):
        holder = NoteNode.Placeholder(duration=duration)
        if self.getVoice(voice) is None:
            self.addVoice(VoiceNode(), voice)
        voice_obj = self.getVoice(voice)
        children = voice_obj.GetChildrenIndexes()
        if self.index >= len(children):
            self.addNote(holder, voice)
        else:
            self.PositionChild(holder, self.index, voice=voice)
        return None

    def addDirection(self, item, voice=1):
        wrappers = [Directions.Bracket.__name__]
        if item.__class__.__name__ in wrappers and (
            not hasattr(
                item,
                "type") or (
                hasattr(
                item,
                "type") and item.type != "start")):
            self.addWrapper(item)
            return
        if item.__class__.__name__ in wrappers and hasattr(
                item,
                "type") and item.type == "start":
            if hasattr(item, "lineType"):
                copy_obj = copy.deepcopy(item)
                copy_obj.type = ""
                item.lineType = ""
                self.addWrapper(copy_obj)

        if self.getVoice(voice) is None:
            self.addVoice(VoiceNode(), voice)
        direction_obj = DirectionNode()
        direction_obj.SetItem(item)
        voice_obj = self.getVoice(voice)
        if self.index == 0:
            finder = 0
        else:
            if item.__class__.__name__ == Directions.Pedal.__name__:
                note = voice_obj.GetChild(self.index - 1)
                if note is not None:
                    result = note.Find(DirectionNode, Directions.Pedal)
                    if result is not None:
                        self.index += 1
            finder = self.index

        note_obj = voice_obj.GetChild(finder)
        if isinstance(
                note_obj,
                NoteNode.NoteNode) or isinstance(
                note_obj,
                NoteNode.Placeholder):
            note_obj.AttachDirection(direction_obj)
        else:
            self.addPlaceholder()
            if self.index >= len(voice_obj.children):
                self.index = len(voice_obj.children) - 1
            note_obj = voice_obj.GetChild(self.index)
            if isinstance(note_obj, NoteNode.Placeholder):
                note_obj.AttachDirection(direction_obj)

    def addExpression(self, item, voice=1):
        if self.getVoice(voice) is None:
            self.addVoice(VoiceNode(), voice)
        direction_obj = ExpressionNode()
        direction_obj.SetItem(item)
        voice_obj = self.getVoice(voice)
        note_obj = voice_obj.GetChild(self.index)
        if isinstance(
                note_obj,
                NoteNode.NoteNode) or isinstance(
                note_obj,
                NoteNode.Placeholder):
            note_obj.AttachExpression(direction_obj)
        else:
            self.addPlaceholder()
            note_obj = voice_obj.GetChild(self.index)
            if isinstance(note_obj, NoteNode.Placeholder):
                note_obj.AttachExpression(direction_obj)

    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 = ""
        left_barline = self.GetBarline("left")
        other_lefts = self.GetBarline("left-1")
        if other_lefts is not None:
            for left in other_lefts:
                lilystring += left.toLily()

        if left_barline is not None:
            lilystring += left_barline.toLily()

        lilystring += self.HandleAttributes()
        voices = self.GetChildrenIndexes()

        if not hasattr(self, "value"):
            self.value = self.GetTotalValue()
        if len(voices) > 1:
            lilystring += "<<"
        for voice in voices:
            mid_barline = self.GetBarline("middle")
            v_obj = self.getVoice(voice)
            v_obj.autoBeam = self.autoBeam
            if mid_barline is not None:
                v_obj.mid_barline = mid_barline[0]
            v_obj.total = self.value
            if len(voices) > 1:
                lilystring += " % voice " + str(voice) + "\n"
                lilystring += "\\new Voice = \"" + \
                    helpers.NumbersToWords(voice) + "\"\n"
                lilystring += "{\\voice" + \
                    helpers.NumbersToWords(voice).capitalize() + " "
            lilystring += v_obj.toLily()
            if len(voices) > 1:
                lilystring += "}"
        if len(voices) > 1:
            lilystring += ">>"
        lilystring += self.HandleClosingAttributes()
        right_barline = self.GetBarline("right")
        other_rights = self.GetBarline("right-1")
        if other_rights is not None:
            for right in other_rights:
                lilystring += right.toLily()

        if right_barline is not None:
            lilystring += right_barline.toLily()
        else:
            lilystring += " | "
        return lilystring

    def CopyDirectionsAndExpressions(self, v_obj):
        child = self.GetChildrenIndexes()[0]
        voice = self.GetChild(child)
        voice_notes = v_obj.GetChildrenIndexes()
        for n in voice_notes:
            note = v_obj.GetChild(n)
            new_position = voice.GetChild(n)
            if new_position is not None:
                children_to_add = note.PopAllChildren()
                for child in children_to_add:
                    if isinstance(child, NoteNode.NoteNode):
                        new_position.AttachNote(child)
                    if isinstance(child, ExpressionNode):
                        new_position.AttachExpression(child)
                    if isinstance(child, DirectionNode):
                        new_position.AttachDirection(child)

    def RunVoiceChecks(self):
        children = self.GetChildrenIndexes()

        if len(children) > 1:
            for child in children:
                voice = self.GetChild(child)
                total = voice.note_total
                result = Search(NoteNode.NoteNode, voice, 1)
                if result is None or total == 0:
                    voice = self.PopChild(child)
                    self.CopyDirectionsAndExpressions(voice)
                voice.RunNoteChecks()
        else:
            voice = self.GetChild(1)
            if voice is not None:
                voice.RunNoteChecks() 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 Placeholder(NoteNode):

    def __init__(self, **kwargs):
        NoteNode.__init__(self, **kwargs)
        self.item = None

    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.duration > 0:
            lilystring += "r" + str(self.duration)
        return lilystring 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 ExpressionNode(SelfNode):
    pass class DirectionNode(SelfNode):
    pass
import os
from MuseParse.tests.testUsingXML.xmlSet import xmlSet, parsePiece
from MuseParse.classes.ObjectHierarchy.ItemClasses import Directions, BarlinesAndMarkers
from MuseParse.classes.ObjectHierarchy.TreeClasses.PartNode import PartNode
from MuseParse.classes.ObjectHierarchy.TreeClasses.MeasureNode import MeasureNode
from MuseParse.classes.ObjectHierarchy.TreeClasses.BaseTree import Search
from MuseParse.classes.ObjectHierarchy.TreeClasses.NoteNode import Placeholder
from MuseParse.classes.ObjectHierarchy.TreeClasses.NoteNode import NoteNode
from MuseParse.classes.ObjectHierarchy.TreeClasses.OtherNodes import ExpressionNode, DirectionNode
from MuseParse.SampleMusicXML import testcases



partname = "lines.xml"
directory = testcases.__path__._path[0]
piece = parsePiece(os.path.join(directory, partname))


class testFile(xmlSet):

    def setUp(self):
        xmlSet.setUp(self)
        self.m_num = 15
        self.p_id = "P1"
        self.p_name = "Flute"

    def testParts(self):
        global piece
        self.assertIsInstance(piece.getPart(self.p_id), PartNode)
        self.assertEqual(self.p_name, piece.getPart(self.p_id).GetItem().name)

    def testMeasures(self):
        self.assertIsInstance(
            piece.getPart(
                self.p_id).getMeasure(
                self.m_num,
                1),
            MeasureNode)


class testWedge(xmlSet):

    def setUp(self):
        if hasattr(self, "measure_id"):
            self.measure = piece.getPart(
                self.p_id).getMeasure(
                self.measure_id, 1)
        if hasattr(self, "item_id"):
            if hasattr(self, "place_id"):
                note = Search(Placeholder, self.measure, self.place_id)
            else:
                note = Search(NoteNode, self.measure, 1)
            self.item = Search(
                ExpressionNode,
                note,
                self.item_id +
                1).GetItem()

    def testInstance(self):
        if hasattr(self, "item"):
            self.assertIsInstance(self.item, Directions.Wedge)

    def testType(self):
        if hasattr(self, "type"):
            self.assertEqual(self.type, self.item.type)

    def testPlacement(self):
        if hasattr(self, "placement"):
            self.assertEqual(self.placement, self.item.placement)


class testOctaveShift(xmlSet):

    def setUp(self):
        if hasattr(self, "measure_id"):
            self.measure = piece.getPart(
                self.p_id).getMeasure(
                self.measure_id, 1)
        if hasattr(self, "item_id"):
            if hasattr(self, "note_id"):
                note = Search(NoteNode, self.measure, self.note_id)
            else:

                note = Search(NoteNode, self.measure, 1)