"""
All <notation> elements defined in MusicXML. The lyrics show the notation assigned to each note.
"""

from pathlib import Path

from musicscore import Score, Chord, C, E, G
from unittest import TestCase
from musicscore.util import XML_DYNAMIC_CLASSES
from musicxml.xmlelement.xmlelement import (
    XMLFermata,
    XMLArpeggiate,
    XMLNonArpeggiate,
    XMLAccidentalMark,
    XMLAccent,
    XMLStrongAccent,
    XMLStaccato,
    XMLTenuto,
    XMLStaccatissimo,
    XMLSpiccato,
    XMLScoop,
    XMLPlop,
    XMLDoit,
    XMLFalloff,
    XMLBreathMark,
    XMLCaesura,
    XMLStress,
    XMLUnstress,
    XMLTrillMark,
    XMLTurn,
    XMLDelayedTurn,
    XMLInvertedTurn,
    XMLShake,
    XMLWavyLine,
    XMLDetachedLegato,
    XMLMordent,
    XMLInvertedMordent,
    XMLSchleifer,
    XMLTremolo,
    XMLUpBow,
    XMLDownBow,
    XMLHarmonic,
    XMLNatural,
    XMLArtificial,
    XMLBasePitch,
    XMLTouchingPitch,
    XMLSoundingPitch,
    XMLOpenString,
    XMLFingering,
    XMLThumbPosition,
    XMLPluck,
    XMLDoubleTongue,
    XMLTripleTongue,
    XMLStopped,
    XMLSnapPizzicato,
    XMLFret,
    XMLString,
    XMLPullOff,
    XMLHammerOn,
    XMLBend,
    XMLBendAlter,
    XMLWithBar,
    XMLPreBend,
    XMLRelease,
    XMLTap,
    XMLHeel,
    XMLToe,
    XMLFingernails,
    XMLF,
    XMLPpp,
    XMLSfp,
    XMLOtherDynamics,
)


class TestLily321(TestCase):
    def test_lily_321_Notations(self):
        score = Score()
        part = score.add_part("p1")

        xml_notations = [
            XMLFermata(),
            XMLFermata("normal"),
            XMLFermata("angled"),
            XMLFermata("square"),
            XMLFermata(type="inverted"),
            XMLArpeggiate(),
            XMLNonArpeggiate(),
            XMLAccidentalMark("double-sharp"),
            XMLAccent(),
            XMLStrongAccent(),
            XMLStaccato(),
            XMLTenuto(),
            XMLDetachedLegato(),
            XMLStaccatissimo(),
            XMLSpiccato(),
            XMLScoop(),
            XMLPlop(),
            XMLDoit(),
            XMLFalloff(),
            XMLBreathMark(),
            XMLCaesura(),
            XMLStress(),
            XMLUnstress(),
            None,
            XMLTrillMark(),
            XMLTurn(),
            XMLDelayedTurn(),
            XMLInvertedTurn(),
            XMLShake(),
            [
                XMLWavyLine(type="start"),
                XMLWavyLine(type="continue"),
                XMLWavyLine(type="stop"),
            ],
            XMLMordent(),
            XMLInvertedMordent(),
            XMLSchleifer(),
            XMLTremolo(3),
            (XMLTurn(), XMLAccidentalMark("natural", placement="below")),
            (
                XMLTurn(),
                XMLAccidentalMark("sharp"),
                XMLAccidentalMark("three-quarters-flat"),
            ),
            XMLUpBow(),
            XMLDownBow(),
            XMLHarmonic(),
        ]

        harmonics = [XMLHarmonic() for _ in range(6)]
        harmonics[0].add_child(XMLNatural())
        harmonics[2].add_child(XMLArtificial())
        harmonics[3].add_child(XMLNatural())
        harmonics[3].add_child(XMLBasePitch())
        harmonics[4].add_child(XMLNatural())
        harmonics[4].add_child(XMLTouchingPitch())
        harmonics[5].add_child(XMLNatural())
        harmonics[5].add_child(XMLSoundingPitch())

        xml_notations += harmonics

        xml_notations += [XMLOpenString(), XMLThumbPosition()]

        fingerings = [XMLFingering() for _ in range(7)]
        fingerings[1].value_ = "1"
        fingerings[2].value_ = "2"
        fingerings[3].value_ = "3"
        fingerings[4].value_ = "4"
        fingerings[5].value_ = "5"
        fingerings[5].value_ = "something"
        fingerings.append((XMLFingering("2"), XMLFingering("3"), XMLFingering("5")))

        xml_notations += fingerings

        xml_notations += [
            XMLPluck(),
            XMLPluck("a"),
            XMLThumbPosition(),
            XMLDoubleTongue(),
            XMLTripleTongue(),
            XMLStopped(),
            XMLSnapPizzicato(),
            XMLFret(0),
            XMLFret(1),
            XMLString(1),
            XMLString(5),
            [XMLHammerOn(type="start"), XMLHammerOn(type="stop")],
            [XMLPullOff(type="start"), XMLPullOff(type="stop")],
        ]

        bends = [XMLBend() for _ in range(4)]
        bends[0].add_child(XMLBendAlter(3))
        bends[1].add_child(XMLBendAlter(3))
        bends[1].add_child(XMLWithBar())
        bends[2].add_child(XMLBendAlter(0.5))
        bends[2].add_child(XMLPreBend())
        bends[3].add_child(XMLBendAlter(3.5))
        bends[3].add_child(XMLRelease())

        xml_notations += bends

        xml_notations += [
            XMLTap(),
            XMLTap(hand="left"),
            XMLHeel(),
            XMLToe(),
            XMLFingernails(),
            None,
            None,
            None,
            XMLF(),
            XMLPpp(),
            XMLSfp(),
            XMLOtherDynamics("sfffz"),
            (XMLStrongAccent(), XMLStaccato()),
        ]

        for n in xml_notations:
            if n is None:
                ch = Chord(0, 1)
                part.add_chord(ch)
            elif isinstance(n, XMLNonArpeggiate):
                ch = Chord([C(5), E(5), G(5)], 1)
                ch.add_lyric("XMLNonArpeggiate not implemented")
                part.add_chord(ch)
            elif isinstance(n, XMLArpeggiate):
                ch = Chord([C(5), E(5), G(5)], 1)
                ch.add_x(n)
                part.add_chord(ch)
            elif isinstance(n, XMLAccidentalMark):
                ch = Chord(C(5), 1)
                ch.add_x(n, parent_type="notation")
                part.add_chord(ch)
            elif isinstance(n, list):
                for x in n:
                    ch = Chord(C(5), 1)
                    ch.add_x(x)
                    part.add_chord(ch)
            elif isinstance(n, tuple):
                ch = Chord(C(5), 1)
                for x in n:
                    if isinstance(x, XMLAccidentalMark):
                        ch.add_x(x, parent_type="ornament")
                    else:
                        ch.add_x(x)
                part.add_chord(ch)
            elif n.__class__ in XML_DYNAMIC_CLASSES:
                ch = Chord(C(5), 1)
                ch.add_x(n, parent_type="notation", placement="below")
                part.add_chord(ch)
            else:
                ch = Chord(C(5), 1)
                ch.add_x(n)
                part.add_chord(ch)

        objects = (XMLStaccato(), XMLAccent(), XMLTenuto())
        placements = ["above", "below", "below"]
        ch = Chord(60, 1)
        for o, p in zip(objects, placements):
            ch.add_x(o, placement=p)
            # print(o.placement)
        part.add_chord(ch)

        xml_path = Path(__file__).with_suffix(".xml")
        score.export_xml(xml_path)
