# -*- coding: utf-8 -*-
""" capellaScript   (c) Paul Villiger
>>> Ligaturbehandlung in capella

    
<<<

History:  26.04.2020 - Beta
          06.05.2020 - Speicherung der Eingabe, Bereichsauswahl

"""


from xml.dom.minidom import NodeList
from xml.dom.minidom import parseString


doc = parseString(u'<score/>')

charSeparator = u'\u200c'
ligaturList = [ ['ff',  u'\ufb00', 'f%sf'    % charSeparator],
                ['fi',  u'\ufb01', 'f%si'    % charSeparator],
                ['fl',  u'\ufb02', 'f%sl'    % charSeparator],
                ['ffi', u'\ufb03', 'f%sf%si' % (charSeparator, charSeparator)],
                ['ffl', u'\ufb04', 'f%sf%sl' % (charSeparator, charSeparator)],
                ['ft',  u'\ufb05', 'f%st'    % charSeparator]
              ]


def getCursorRange():
    sel = curSelection()
    (sy1,st1,vo1,ob1),(sy2,st2,vo2,ob2) = sel
    sel = (min(sy1,sy12), min(st1,st2),min(vo1,vo2),min(ob1,ob2)),(max(sy1,sy2), max(st1,st2),max(vo1,vo2),max(ob1,ob2))
    (sy1,st1,vo1,ob1),(sy2,st2,vo2,ob2) = sel
    
    if ob2 > ob1: # sonst wird Zeichen hinter rechtem Cursor auch bearbeitet
        ob2 -= 1
        sel = (sy1,st1,vo1,ob1),(sy2,st2,vo2,ob2)
    if sel == 0:
        messageBox('Fehler', 'keine aktive Partitur')
        return (0,0,0,0),(0,0,0,0)
    if sel[0][0:3] <> sel[1][0:3]: # mehrere Stimmen markiert -> alle Noten
        ob1 = 0
        ob2 = 999
    if sel[0][0:2] <> sel[1][0:2]: # mehrere Notenzeilen markiert -> alle Stimmen
        vo1 = 0
        vo2 = 999
    if sel[0][0] <> sel[1][0]: # mehrere Systeme markiert -> alle Notenzeilen
        st1 = 0
        st2 = 999
    sel = (sy1,st1,vo1,ob1),(sy2,st2,vo2,ob2)
    return sel

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 removeLigatures(text):
    t = text
    t = t.replace(charSeparator, '')
    for lig1, lig2, lig3 in ligaturList:
        t = t.replace(lig2, lig1)
    return t

def replaceLigatures(text):
    t = text
    for lig1, lig2, lig3 in ligaturList:
        t = t.replace(lig1, lig2)
    return t

def separateLigatures(text):
    t = text
    for lig1, lig2, lig3 in ligaturList:
        t = t.replace(lig1, lig3)
    return t

def changeLigatures(obj):
    
    if selectType in [0, 1]:
        for text in obj.getElementsByTagName('text'):
            cont = ''
            for content in text.getElementsByTagName('content'):
                if content.firstChild:
                    cont = content.firstChild.nodeValue
                    cont = removeLigatures(cont)
                    if selectLigatur == 1:
                        cont = replaceLigatures(cont)
                    if selectLigatur == 2:
                        cont = separateLigatures(cont)
                    content.removeChild(content.firstChild)
                    textNode = doc.createTextNode(cont)
                    content.appendChild(textNode)

    if selectType in [0, 2]:
        for lyric in obj.getElementsByTagName('lyric'):
            for verse in lyric.getElementsByTagName('verse'):
                if verse.firstChild:
                    cont = verse.firstChild.nodeValue
                    cont = removeLigatures(cont)
                    if selectLigatur == 1:
                        cont = replaceLigatures(cont)
                    if selectLigatur == 2:
                        cont = separateLigatures(cont)
                    verse.removeChild(verse.firstChild)
                    textNode = doc.createTextNode(cont)
                    verse.appendChild(textNode)


def changeLigaturesVoice(voice, first, last):
    objList = getElementObjects(voice.getElementsByTagName('noteObjects')[0].childNodes)
    objNumber = 0
    for obj in objList:
        if first > objNumber or last < objNumber:
            pass
        else:
            changeLigatures(obj)
        objNumber +=1

                
                    
def changeDoc(score):

    global actLayout, doc
    doc = score.parentNode    
    (sy1, st1, vo1, ob1),(sy2, st2, vo2, ob2) = getCursorRange()

    if selectRange == 0:
        (sy1, st1, vo1, ob1),(sy2, st2, vo2, ob2) = (0,0,0,0),(999,999,999,999)  # ganze Partitur

    if selectRange in [0,2]:
        sy = 0
        for system in score.getElementsByTagName('system'):
            if sy1 <= sy <= sy2:
                st = 0
                for staff in system.getElementsByTagName('staff'):
                    if st1 <= st <= st2:
                        vo = 0
                        for voice in staff.getElementsByTagName('voice'):
                            if vo1 <= vo <= vo2:
                                changeLigaturesVoice(voice, ob1, ob2)
                            vo += 1
                    st += 1
            sy += 1
            
    if selectRange in [0,1]:
        for pageObjects in score.getElementsByTagName('pageObjects'):
            changeLigatures(pageObjects)


(sy1, st1, vo1, ob1),(sy2, st2, vo2, ob2) = getCursorRange()
select = 'Markierung:'
if sy1 <> sy2:
    select += ' System %s - %s' % (sy1+1, sy2+1)
else:
    select += ' System %s' % (sy1+1)
    if st1 <> st2:
        select += ', Notenzeile %s - %s' % (st1+1, st2+1)
    else:
        select += ', Notenzeile %s' % (st1+1)
        if vo1 <> vo2:
            select += ', Stimme %s - %s' % (vo1+1, vo2+1)
        else:
            select += ', Stimme %s' % (vo1+1)
            if ob1 <> ob2:
                select += ', Objekt %s - %s' % (ob1+1, ob2+1)
            else:
                select += ', Objekt %s' % (ob1+1)


options = ScriptOptions() 
opt = options.get()

selectLigatur = int(opt.get('selectLigatur', 0))
selectRange   = int(opt.get('selectRange', 0))
selectType    = int(opt.get('selectType', 0))

selectLigatur = Radio(['Normale Darstellung (capella)', 'Ligaturzeichen', 'Ligatur trennen'], value = selectLigatur)
selectRange   = Radio(['Ganze Partitur', 'Seitenobjekte', 'Markierung'],                      value = selectRange )
selectType    = Radio(['Einfachtext und Liedtext', 'Einfachtext', 'Liedtext'],                value = selectType ) 



dlg = Dialog('Ligatur Behandlung',
             VBox([HBox([Label('Bereich:', width= 10), selectRange]),
                   Label(''),
                   HBox([Label('Aktion:', width = 10), selectLigatur]),
                   Label(''),
                   HBox([Label('Typ:', width = 10), selectType]),
                   Label(''),
                   Label(select, width=50)
                   
                  ])
             )

ok = True
if dlg.run():
    selectLigatur = selectLigatur.value()
    selectRange   = selectRange.value()
    selectType    = selectType.value()

    opt['selectLigatur'] = selectLigatur
    opt['selectRange']   = selectRange
    opt['selectType']    = selectType
    options.set(opt)
    
else:
    ok = False
    


# Hauptprogramm:

from caplib.capDOM import ScoreChange
import tempfile

class ScoreChange(ScoreChange):
    def changeScore(self, score):
        changeDoc(score)

if activeScore() and ok:
    activeScore().registerUndo("Ligatur")
    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)
    
    ScoreChange(tempInput, tempOutput)

    activeScore().read(tempOutput)
    os.remove(tempInput)
    os.remove(tempOutput)                

