# -*- coding: ISO-8859-1 -*-
""" capellaScript -- (c) Paul Villiger
>>> Tonart Wechsler

    Mit diesem Skript kann die Tonart am Zeilenanfang in der ganzen Partitur
    gewechselt werden. Folgende Auswahl steht zur Verfügung:|
    - Wechseln ab aktuellem System|
    - Nur wechseln in der aktuellen Notenzeile|
    - Defaul Meter korrigieren (ganze Partitur)|
    Kombinationen sind möglich. Ohne Auswahl erfolgt der Wechsel in der ganzen Partitur. 
    
<<<

History: 05.03.06 Erstausgabe
         09.03.06 Korrektur von Defaulttakt implementiert
"""

import new, sys
from xml.dom.minidom import NodeList, Node, Element
from xml.dom.minidom import parseString, NodeList, Node, Element
# import win32traceutil

doc = parseString('<score/>')

def getCursor():
    sel = curSelection()
    result = None
    if sel == 0:
        messageBox('Fehler', 'keine aktive Partitur')
        return result
    if sel[0] < sel[1]:
        result = sel[0]
    else:
        result = sel[1]
    return result


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 getTimeSigns(system):
    for staff in system.getElementsByTagName('staff'):
        timeDefault = staff.getAttribute('defaultTime')
        timeBegin = timeEnd = ''
        isFirstTimeSign = True
        for voice in staff.getElementsByTagName('voice'):
            noteObjects = voice.gotoChild('noteObjects')
            obj = noteObjects.firstChild
            while obj:
                if obj.nodeType == obj.ELEMENT_NODE:
                    if obj.tagName in ['barline', 'chord', 'rest']:
                        isFirstTimeSign = False
                    elif obj.tagName == 'timeSign':
                        if isFirstTimeSign:
                            timeBegin = obj.getAttribute('time')
                        else:
                            timeEnd = obj.getAttribute('time')
                obj = obj.nextSibling

            if timeBegin and timeEnd and timeBegin <> timeEnd:
                return (timeDefault, timeBegin, timeEnd)
    return (timeDefault, timeBegin, timeEnd)
                

def setDefaultTime(score):
    prevTime = ''
    for system in score.getElementsByTagName('system'):
        timeDefault, timeBegin, timeEnd = getTimeSigns(system)
        if timeBegin:
            timeDefault = timeBegin
            prevTime = timeBegin
        if not prevTime:
            prevTime = timeDefault
        for staff in system.getElementsByTagName('staff'):
            staff.setAttribute('defaultTime', prevTime)
        if timeEnd:
            prevTime = timeEnd
            

def changeKey(voice, fifths):
    noteObjects = voice.gotoChild('noteObjects')
    obj = noteObjects.firstChild
    while obj:
        if obj.nodeType == obj.ELEMENT_NODE:
            if obj.tagName == 'keySign':
                obj.setAttribute('fifths',fifths)
                if fifths == '0':
                    obj.parentNode.removeChild(obj)
                break
            elif obj.tagName in ['timeSign', 'barline', 'chord', 'rest']:
                if fifths <> '0':
                    newObj = doc.createElement('keySign')
                    newObj.setAttribute('fifths',fifths)
                    obj.parentNode.insertBefore(newObj, obj)
                break
        obj = obj.nextSibling
        if not obj:
            newObj = doc.createElement('keySign')
            newObj.setAttribute('fifths',fifths)
            noteObjects.appendChild(newObj)
            
            

def handleStaff(staff, fifths):
    for voice in staff.getElementsByTagName('voice'):
        changeKey(voice, fifths)
        

def changeDoc(score):
    sy1, st1, vo1, ob1 = getCursor()
    actSystem = score.getElementsByTagName('system')[sy1]
    actStaff = actSystem.getElementsByTagName('staff')[st1]
    actLayout = actStaff.getAttribute('layout')

    keyList = ['7# Cis','6# Fis','5# H','4# E','3# A','2# D','1# G','C','1b F','2b B','3b Es','4b As','5b Des','6b Ges','7b Ces']

    newKey = ComboBox( keyList, value = 7, width=10)
    
    fromSystem = CheckBox('Ab aktuellem System', value=0)
    thisStaffOnly = CheckBox('Nur aktuelle Notenzeile', value=0)
    correctTimeSign = CheckBox('Default Meter korrigieren', value = 0)
    changeKey = CheckBox('Tonart wechseln', value = 1)
    
    dlg = Dialog('Tonart wechseln ohne Transponieren',
                 VBox([changeKey,
                       HBox([Label(' ', width = 5), Label('neue Tonart   '), newKey, Label(' ', width = 10)]),
                       HBox([Label(' ', width = 5), fromSystem]),
                       HBox([Label(' ', width = 5), thisStaffOnly]),
                       Label(' '),
                       correctTimeSign,
                       Label(' ')
                     ]))
    if dlg.run():
        newKey = str(- newKey.value() + 7)
    else:
        return

    if changeKey.value():
        sy = 0
        for system in score.getElementsByTagName('system'):
            if fromSystem.value() and sy < sy1:
                sy += 1
                continue
            # messageBox('',str(fromSystem) +' '+ str(sy1)+' '+ str(sy))
            for staff in system.getElementsByTagName('staff'):
                if thisStaffOnly.value() and staff.getAttribute('layout') <> actLayout:
                    continue
                handleStaff(staff, newKey)

            sy += 1

    if correctTimeSign.value():
        setDefaultTime(score)        


from caplib.capDOM import ScoreChange
import tempfile

class ScoreChange(ScoreChange):
    def changeScore(self, score):
        changeDoc(score)

if activeScore():
    activeScore().registerUndo("Tonart Wechsler")

    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)
    
    ScoreChange(tempInput, tempOutput)

    activeScore().read(tempOutput)
    os.remove(tempInput)
    os.remove(tempOutput)


