# -*- coding: ISO-8859-1 -*-
""" capellaScript -- (c) Paul Villiger
>>> Noten_klonen

    Grafische Objekte, Farben von Noten und Kopfform einer Referenzdatei
    werden auf die ganze Partitur verteilt. Beim Klonen werden die Tonhöhe und die Vorzeichen berücksichtigt.
    Die grafischen Objekte werden mit einem SkriptTag versehen und lassen sich auch wieder löschen.

<<<
History:  20.01.2004 - Erste Version
          14.03.2004 - Kopfform kopieren und farbig -> schwarz möglich
          16.03.2004 - Kopfform auf einzelne Noten in Akkorden anwendbar, z.B. Schlagzeug
          10.08.2004 - Fehler bei transponierbaren Objekten
          23.10.2005 - Die Referenzdaten werden neu aus einer Referenzdatei gelesen.
                     - Die Einstellungen werden gesichert
          25.10.2005 - Metafiles werden übertragen
          15.11.2005 - Fehler bei Kopfform kopieren
         
"""

# import xml.dom
from xml.dom.minidom import NodeList, Node, Element
import zipfile, new
scriptTag = '21793-2'
refChordList = []
refMetaFiles= {}

# Gibt alle Elemente auf der nächsten Ebene zurück
def getChildElements(self, filter = ''):
    childElements = NodeList()
    for child in self.childNodes:
        if child.nodeType == child.ELEMENT_NODE:
            if filter == '':
                childElements.append(child)
            elif child.tagName == filter:
                childElements.append(child)
    return childElements

Node.getChildElements = new.instancemethod(getChildElements,None,Node)


def createNewChild(el, name, new=False):
    if new:
        newEl = doc.createElement(name)
        el.appendChild(newEl)
    else:
        newEl = el.getElementsByTagName(name)
        if newEl.length == 0:
            newEl = doc.createElement(name)
            el.appendChild(newEl)
        else:
            newEl = newEl[0]
    return newEl

options = ScriptOptions() 
opt = options.get()
copyDrawObjs = eval(opt.get('copyDrawObjs', 'False'))
copyColor    = eval(opt.get('copyColor', 'False'))
copyShape    = eval(opt.get('copyShape', 'False'))
deleteOldTags= eval(opt.get('deleteOldTags', 'True'))
oneStaff     = eval(opt.get('oneStaff', 'False'))

refScoreFile     = opt.get('refScoreFile','')

def getDialogValues():
    
    global copyDrawObjs, copyColor, copyShape, deleteOldTags, oneStaff, selLayout, voiceList, refScoreFile

    voiceList = activeScore().voiceList()    

    cbox1 = CheckBox('Grafikelemente kopieren', value=copyDrawObjs, width = 30, padding = 8)
    cbox2 = CheckBox('Notenfarbe kopieren', value=copyColor, padding = 8)
    cbox21 = CheckBox('Kopfform kopieren', value=copyShape, padding = 8)
    cbox3 = CheckBox('Alte Grafikelemente löschen', value=deleteOldTags, padding = 8)
    cbox4 = CheckBox('Änderung nur in dieser Stimme   ',value=oneStaff, padding = 8)
    combobox4 = ComboBox(voiceList, value=0, width=20, padding = 8)
    hbox4 = HBox([cbox4, combobox4], padding = 8)
    lab5 = Label('', padding = 8)
        
    vbox1 = VBox([cbox1, cbox2, cbox21, cbox3, hbox4, lab5], padding = 8)

    lab1 = Label('Auswahl :', width = 8, padding = 8)

    hbox1 = HBox([lab1, vbox1], padding = 8)    
    
    dlg = Dialog('--- Noten klonen ---', hbox1)

    if dlg.run():
        copyDrawObjs = cbox1.value() == 1
        copyColor    = cbox2.value() == 1
        copyShape    = cbox21.value() == 1
        deleteOldTags = cbox3.value() == 1
        oneStaff = cbox4.value() == 1
        selLayout = combobox4.value()
        opt['copyDrawObjs'] = copyDrawObjs
        opt['copyColor'] = copyColor
        opt['copyShape'] = copyShape
        opt['deleteOldTags'] = deleteOldTags
        opt['refScoreFile'] = refScoreFile


        dlg = FileDialog()
        dlg.__init__(bOpen=True)
        dlg.setTitle('Bitte Referenzdatei auswählen')
        dlg.addFilter('capella-Dateien', '*.cap;*.capx')
        if os.path.isfile(refScoreFile):
            capDir, capName = os.path.split(refScoreFile)
            dlg.setStartPath(capDir)
            dlg.setStartFile(capName)
        elif os.path.isdir(refScoreFile):
            dlg.setStartPath(refScoreFile)
        else:
            dlg.setStartPath(getProgramDir)
            
        if dlg.run():
            refScoreFile=dlg.filePath()
            capDir, capName = os.path.split(refScoreFile)
            opt['refScoreFile'] = refScoreFile
            options.set(opt)
            return True
        else:
            return False
    else:
        return False

def readRefScore(capFile):
    class ScoreChange1(ScoreChange):
        def changeScore(self, score):
            for chord in score.getElementsByTagName('chord'):
                newChord = chord.cloneNode(True)
                for metafile in newChord.getElementsByTagName('metafile'):
                    fileName = metafile.getAttribute('file')
                    refMetaFiles[fileName] = None
                    metafile.setAttribute('file', 'zy_'+fileName) # Diese Dateiname sollte in der Zielpartitur nicht vorkommen
                refChordList.append(newChord)

    capDir, capName = os.path.split(capFile)
    head, tail = os.path.splitext(capName)
    if tail.lower() not in  ['.cap', '.capx' ]:
        raise 'Keine Capelladatei'
    
    if not os.path.isfile(capFile):
        raise 'Keine Capelladatei'

    openScore(capFile)

    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)
    
    ScoreChange1(tempInput, tempOutput)

    zr = zipfile.ZipFile(tempInput, 'r')
    for name in refMetaFiles.keys():
        t = zr.read(name)
        refMetaFiles[name] = t
    zr.close()
    
    os.remove(tempInput)
    os.remove(tempOutput)
    
    closeActiveScore()
    


def changeDoc(score):
    
    readRefScore(refScoreFile)
    
    systems = score.getElementsByTagName('system')
    for sy in range(systems.length):
        staves = systems[sy].getElementsByTagName('staff')
        for st in range(staves.length):
            if oneStaff and staves[st].getAttribute('layout') <> voiceList[selLayout]:
                continue
            voices = staves[st].getElementsByTagName('voice')
            for vo in range(voices.length):
                for chord in voices[vo].getElementsByTagName('chord'):
                    head = chord.getElementsByTagName('head')[0]
                    pitch = head.getAttribute('pitch')
                    alter = head.getElementsByTagName('alter')
                    if alter.length == 0:
                        alterPresent = False
                        alterStep = ''
                    else:
                        alterPresent = True
                        alterStep = alter[0].getAttribute('step')
                

                    found = False
                    for refChord in refChordList:
                        refHead = refChord.getElementsByTagName('head')[0]
                        refPitch = refHead.getAttribute('pitch')
                        refAlter = refHead.getElementsByTagName('alter')
                        if refAlter.length == 0:
                            refAlterPresent = False
                            refAlterStep = ''
                        else:
                            refAlterPresent = True
                            refAlterStep = refAlter[0].getAttribute('step')
                        if pitch == refPitch and alterPresent == refAlterPresent and alterStep == refAlterStep:
                            found = True
                            foundChord = refChord
                            break

                    if found and copyColor:
                        color = '000000'
                        for refDisplay in foundChord.getElementsByTagName('display'):
                            # Notenfarbe von Referenznote kopieren, sofern vorhanden
                            if refDisplay.hasAttribute('color'):
                                color = refDisplay.getAttribute('color')
                        display = createNewChild(chord, 'display')
                        display.setAttribute('color', color)
                                
                                    
                    if found and copyDrawObjs:
                        for refDrawObjects in foundChord.getChildElements('drawObjects'):
                            
                            for refDrawObj in refDrawObjects.getChildElements('drawObj'):
                                # drawObjects erstellen wenn nicht vorhanden
                                drawObjects = createNewChild(chord, 'drawObjects')

                                # draWObj von Referenzzeile klonen                                
                                newDrawObj = refDrawObj.cloneNode(True)
                                drawObjects.appendChild(newDrawObj)
                                
                                # Scripttag setzen
                                basic = createNewChild(newDrawObj, 'basic')
                                basic.setAttribute('tag', scriptTag)

                if copyShape:
                    for chord in voices[vo].getElementsByTagName('chord'):
                        for head in chord.getElementsByTagName('head'):
                            pitch = head.getAttribute('pitch')
                            alter = head.getElementsByTagName('alter')
                            if alter.length == 0:
                                alterPresent = False
                                alterStep = ''
                            else:
                                alterPresent = True
                                alterStep = alter[0].getAttribute('step')
                    
    
                            found = False
                            for refChord in refChordList:
                                refHead = refChord.getElementsByTagName('head')[0]
                                refPitch = refHead.getAttribute('pitch')
                                refAlter = refHead.getElementsByTagName('alter')
                                if refAlter.length == 0:
                                    refAlterPresent = False
                                    refAlterStep = ''
                                else:
                                    refAlterPresent = True
                                    refAlterStep = refAlter[0].getAttribute('step')
                                    
                                if pitch == refPitch and alterPresent == refAlterPresent and alterStep == refAlterStep:
                                    if refHead.hasAttribute('shape'):
                                        head.setAttribute('shape',refHead.getAttribute('shape'))
                                    else:
                                        if head.hasAttribute('shape'):
                                            head.removeAttribute('shape')
                                    break
    

# Hauptprogramm:

from caplib.capDOM import ScoreChange
import tempfile

class ScoreChange(ScoreChange):
    def changeScore(self, score):
        global doc
        doc = score.parentNode
        changeDoc(score)

if activeScore():
    if not getDialogValues():
        pass
    else:
        activeScore().registerUndo("Noten Klonen")
        if deleteOldTags:
            activeScore().deleteTaggedGraphics(scriptTag)
            
        tempInput = tempfile.mktemp('.capx')
        tempOutput = tempfile.mktemp('.capx')
        activeScore().write(tempInput)
        
        ScoreChange(tempInput, tempOutput)

        # alle Metafiles in die aktuelle Partitur kopieren
        zw = zipfile.ZipFile(tempOutput, 'a', zipfile.ZIP_DEFLATED)
        for name in refMetaFiles.keys():
            info = zipfile.ZipInfo('zy_' + str(name))
            info.compress_type = zipfile.ZIP_DEFLATED
            t = refMetaFiles[name]
            zw.writestr(info, t)
        zw.close()
    
        activeScore().read(tempOutput)
        os.remove(tempInput)
        os.remove(tempOutput)

