# -*- coding: ISO-8859-1 -*-
""" capellaScript -- (c) Paul Villiger
>>> Articulation Editor

Mit diesem Skript werden Artikulationen über den Liedtext eingegeben.||
Vorgehen:|
1. Erste Strophe Liedtext "Freimachen"|
2. Bestehende Artikulationen in Liedtext übernehmen|
3. Liedtext editieren|
4. Artikulationen aus Liedtext übernehmen|
5. Erste Strophe Liedtext "Löschen"||
Abkürzungen: s - Staccato, S - Staccatissimo, t - Tenuto, T - Tenuto Staccato, a - normaler Akzent, A - starker Akzent, b - weicher Schlag (Beat), B - starker Schlag||
Bestehende Artikulationen löschen: Ist der Liedtext leer, wird die Artikulation gelöscht.|
Liedtext überschreiben: Vorhandener Liedtext wird ohne Warnung überschrieben.
    
<<<

History: 23.07.2010 Erstausgabe
         06.09.2010 Skriptfehler bei Abbruch

"""
german = ("de", {
    'dialogHeader'      :   ' Articulation Editor ',
    'regUndo'           :   'Articulation Editor',
    'actionSelect'      :   'Aktion auswählen',
    'radio_1'           :   '1. Liedtext leere Strophe einfügen',
    'radio_2'           :   '2. Artikulationen in Liedtext übernehmen',
    'radio_3'           :   '3. Artikulationen aus Liedtext übernehmen',
    'radio_4'           :   '4. Liedtext Strophe 1 löschen',
    'removeExisting'    :   'Bestehende Artikulationen löschen',
    'overwriteLyric'    :   'Liedtext überschreiben?',
    'warning'           :   ' Warnung ',
    'lyricNotEmpty'     :   'Liedtext 1. Strophe ist nicht leer!'
    
    
    } )

try:
    exec('from %s import translations' % ( translationModule() ))
    translations.append(german)
    setLanguages(translations)
except:
    def tr(s):
        return german[1].get(s, "???")
#-------------------------------------------------------------------
    
from xml.dom.minidom import parseString, NodeList, Node, Element
from caplib.rational import Rational
from caplib.capDOM import ScoreChange
import tempfile, string, new

articulationDefinition = {'s' : 'staccato',
                          'S' : 'staccatissimo',
                          't' : 'tenuto',
                          'T' : 'staccato tenuto',
                          'a' : 'normalAccent',
                          'A' : 'strongAccent',
                          'b' : 'weakBeat',
                          'B' : 'strongBeat'
                          }

def latin1(u):
    return u.encode('Latin-1')

doc = parseString('<score/>')

def gotoChild(self, name, new=False):
    newEl = None
    if new:
        pass
    else:
        for child in self.childNodes:
            if child.nodeType == child.ELEMENT_NODE and child.tagName == name:
                newEl = child
                break
    if newEl == None:
        newEl = doc.createElement(name)
        self.appendChild(newEl)
    return newEl
Node.gotoChild = new.instancemethod(gotoChild,None,Node)

def getElementObjects(objList):  # returns a List
    newList = NodeList()
    for n in range(objList.length):
        if objList[n].nodeType == objList[n].ELEMENT_NODE:
            newList.append(objList[n])
    return newList


# ----------------------------------------------------------------
def shiftLyrics(score,down=True):
    if down:
        increment = -1
        toRemove = '-1'
    else:
        increment = 1
        toRemove = '9'
        
    for system in score.getElementsByTagName('system'):
        for staff in system.getElementsByTagName('staff'):
            for voice in staff.getElementsByTagName('voice'):
                noteObjects = voice.gotoChild('noteObjects')
                obj = noteObjects.firstChild
                while obj:
                    if obj.nodeType == obj.ELEMENT_NODE:
                        for lyric in obj.getElementsByTagName('lyric'):
                            for verse in obj.getElementsByTagName('verse'):
                                i = int(verse.getAttribute('i'))
                                verse.setAttribute('i',str(i + increment))
                            for verse in obj.getElementsByTagName('verse'):
                                if verse.getAttribute('i') == toRemove:
                                    verse.parentNode.removeChild(verse)
                            if not lyric.getElementsByTagName('verse'):
                                lyric.parentNode.removeChild(lyric)
                    obj = obj.nextSibling


# END shiftLyrics()
# ----------------------------------------------------------------

def getText(node):
    for child in node.childNodes:
        if child.nodeType == child.TEXT_NODE:
            return child.data
    return ''

def setArticulation(chord, articulation):
    if articulation not in articulationDefinition:
        return
    _articulation = chord.gotoChild('articulation')
    _articulation.setAttribute('type',articulationDefinition[articulation])

def getArticulation(chord):
    articulation = ''
    for _articulation in chord.getElementsByTagName('articulation'):
        articulation = _articulation.getAttribute('type')
        for (key, value) in articulationDefinition.iteritems():
            if value == articulation:
                articulation = key
    return articulation
        
def getLyricArticulation(chord):
    articulation = ''
    for lyric in chord.getElementsByTagName('lyric'):
        for verse in lyric.getElementsByTagName('verse'):
            i = int(verse.getAttribute('i'))
            if i == 0:
                articulation = getText(verse)
                break
    return articulation

def setLyricArticulation(chord, articulation):
    lyric = chord.gotoChild('lyric')
    for verse in lyric.getElementsByTagName('verse'):
        i = int(verse.getAttribute('i'))
        if i == 0:
            verse.parentNode.removeChild(verse)
            
    verse = lyric.gotoChild('verse', True)
    verse.setAttribute('i','0')
    textNode = doc.createTextNode(articulation)
    verse.appendChild(textNode)
    
    
def removeArticulation(chord):
    for _articulation in chord.getElementsByTagName('articulation'):
        _articulation.parentNode.removeChild(_articulation)

def isLyricEmpty(score):
    for chord in score.getElementsByTagName('chord'):
        for lyric in chord.getElementsByTagName('lyric'):
            for verse in lyric.getElementsByTagName('verse'):
                i = int(verse.getAttribute('i'))
                if i == 0:
                    return False

    return True
        
# --------------- User Input ------------------------------------
uiActionSelect = Radio([tr('radio_1'),
                        tr('radio_2'),
                        tr('radio_3'),
                        tr('radio_4')], value = 0)

removeExisting = CheckBox('', value = False, width = 3)
overwriteLyric = CheckBox('', value = False, width = 3)

dlg = Dialog(tr('dialogHeader'),
             VBox([
                 HBox([uiActionSelect], text = tr('actionSelect')),
                 HBox([removeExisting, Label(tr('removeExisting'), width = 14)]),
                 HBox([overwriteLyric, Label(tr('overwriteLyric'), width = 14)]),
                 Label('')
                 ], padding = 6)
             )
if dlg.run():
    actionSelect = uiActionSelect.value()
    removeExisting = removeExisting.value()
    overwriteLyric = overwriteLyric.value()
    handlingOk = True
else:
    handlingOk = False



def changeDoc(score):
    if actionSelect == 0:
        shiftLyrics(score,down = False)
    elif actionSelect == 1:
        if not overwriteLyric:
            if not isLyricEmpty(score):
                messageBox(tr('warning'),tr('lyricNotEmpty'))
                return
        for chord in score.getElementsByTagName('chord'):
            articulation = getArticulation(chord)
            if articulation:
                setLyricArticulation(chord, articulation)
        
    elif actionSelect == 2:
        for chord in score.getElementsByTagName('chord'):
            if removeExisting:
                removeArticulation(chord)
            articulation = getLyricArticulation(chord)
            if articulation:
                setArticulation(chord, articulation)
    if actionSelect == 3:
        shiftLyrics(score, down = True)
        

class ScoreChange(ScoreChange):
    def changeScore(self, score):
        changeDoc(score)
        
if activeScore() and handlingOk:

    activeScore().registerUndo( tr('regUndo') )
    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)

    ScoreChange(tempInput, tempOutput)

    if handlingOk:
        activeScore().read(tempOutput)
        
    os.remove(tempInput)
    os.remove(tempOutput)

