# -*- coding: ISO-8859-1 -*-
""" capellaScript -- 08.01.2006 Andreas Herzog
>>> Bezeichnungen übertragen


    Version 1.01
    
    Das Skript kopiert in einer mehrstimmigen Partitur beliebige Grafikobjekte einer Zeile und hängt diese an Noten bzw. Pause anderer Stimmen an, die an derselben rhythmischen Position stehen
    
    |
    

        |

<<<

# 1.0: Ursprungsversion

History:
  1.01  15.03.2008 Berücksichtigung von 3-fach Punktierung (Vlg)

"""
import new
from xml.dom.minidom import Node, Element
import xml.dom
import string
from xml.dom.minidom import NodeList

justStaffs = []
justVoices = []
objectsChosen = []

clefs = ['treble','alto','tenor','bass']

def latin1_e(u):
    return u.encode('Latin-1')
def latin1_d(u):
    return u.decode('Latin-1')

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 addElementNode(el,tagName):
    # add new Node to el if Node "tagName" does not exist
    # otherwise return the existing Node
    global doc
    childs = el.childNodes
    for n in range(childs.length):
        if childs[n].nodeType ==childs[n].ELEMENT_NODE and childs[n].tagName == tagName:
            return childs[n]
    newChild = doc.createElement(tagName)
    el.appendChild(newChild)
    return newChild
    
# neu eingefügt
def addNewElementNode(el,tagName):
    # add new Node with tagName "tagName" to el 
    global doc
    newChild = doc.createElement(tagName)
    el.appendChild(newChild)
    return newChild
    
def getAllLayouts(score):
   
    # Gibt eine Liste zurueck mit allen Eintraegen aus dem Mustersystem,
    # sowie deren Verwendungshaeufigkeit

    staffLayouts = score.getElementsByTagName('staffLayout')
    for i in range(staffLayouts.length):
        staffLayouts[i].count = 0
        for staff in score.getElementsByTagName('staff'):
            if staffLayouts[i].getAttribute('description') == staff.getAttribute('layout'):
                staffLayouts[i].count += 1
                
    return staffLayouts


options = ScriptOptions() 
opt = options.get()

def Test(text):
	messageBox('Test',str(text))

    
def getDialogValues1(voiceNames):

    global  allLayouts, Auswahl, splitPoint, selectedTargetStimmeVoice, selectedOriginalVoice, selectedTargetStimmeStaff, selectedOriginalStaff, Stimmenzahl,selectedVoices,objectsChosen, lyricChoice
    global lyricTransfer, lyricChosen
    
    
    layoutList = [ latin1_e(allLayouts[i].getAttribute('description')) for i in range(allLayouts.length ) ]
    voiceNames2 = voiceNames + ['Jeweils in die erste Stimme einer Zeile','Alle Stimmen im System']
    
    selLayoutCombo1 = ComboBox(voiceNames, value = 0, width=32)
    selLayoutCombo2 = ComboBox(voiceNames2,value = 1, width=32)
    AuswahlRadio = Radio(['nur System mit Cursor','alle Systeme'],text='Bearbeiten:', value=0)
    
    
    
    LyricCheck = CheckBox('übertragen',value=1)
    
    Strophe1Check = CheckBox('Strophe 1  ', value = 1)
    Strophe2Check = CheckBox('Strophe 2  ', value = 1)
    Strophe3Check = CheckBox('Strophe 3  ', value = 1)
    Strophe4Check = CheckBox('Strophe 4  ', value = 1)
    Strophe5Check = CheckBox('Strophe 5  ', value = 1)
    Strophe6Check = CheckBox('Strophe 6  ', value = 1)
    Strophe7Check = CheckBox('Strophe 7  ', value = 1)
    Strophe8Check = CheckBox('Strophe 8  ', value = 1)
    Strophe9Check = CheckBox('Strophe 9  ', value = 1)    
    
    TextCheck = CheckBox('Einfachtexte  ',value=1)
    RichTextCheck = CheckBox('Textfelder  ',value=1)
    LineCheck = CheckBox('Linien  ',value=1)
    EllipseCheck = CheckBox('Ellipsen  ',value=1)
    GuitarCheck = CheckBox('Gitarrengriffe  ',value=1)
    MetafileCheck = CheckBox('Grafiken  ',value=1)
    NoteLineCheck = CheckBox('Notenlinien  ',value=1)
    PolygoneCheck = CheckBox('Polygone  ',value=1)
    RectangleCheck = CheckBox('Rechtecke  ',value=1)
    SlurCheck = CheckBox('Bindebögen  ',value=1)
    TransposablesCheck = CheckBox('Transponierbare Objekte  ',value=0)
    TrillCheck = CheckBox('Trillerschlangen ',value=1)    
    VoltaCheck = CheckBox('Voltenklammern  ',value=1)
    WavyLineCheck = CheckBox('Schlangenlinien  ',value=1)
    WedgeCheck = CheckBox('(De-)Crescendos  ',value=1)

    
    lab1 = Label('Zeichen übertragen', width = 5) 
    lab2 = Label('von:', width = 5) 
    lab3 = Label('nach:', width = 5) 

    lableer = Label(' ', width = 1) 


    vbox1a  = VBox([TextCheck, RichTextCheck, LineCheck,EllipseCheck,GuitarCheck, MetafileCheck, NoteLineCheck ], text='', padding=6)
    vbox1b  = VBox([PolygoneCheck, RectangleCheck, SlurCheck, TrillCheck,VoltaCheck,WavyLineCheck, WedgeCheck ], text='', padding=6)
    
    
    
    hBox1 = HBox([lab1 ], text='', padding=12)
    hBox2 = HBox([lab2, selLayoutCombo1], text='', padding=12)
    hBox3 = HBox([lab3, selLayoutCombo2], text='', padding=12)
    hbox4  = HBox([vbox1a, vbox1b], text='Elemente:', padding=12)
    
    vbox2  = VBox([hBox1,hBox2, hBox3], text='', padding=12)
    
    hbox5a = HBox([Strophe1Check, Strophe2Check, Strophe3Check], padding = 6)
    hbox5b = HBox([Strophe4Check, Strophe5Check, Strophe6Check], padding = 6)
    hbox5c = HBox([Strophe7Check, Strophe8Check, Strophe9Check], padding = 6)
    
    vbox3a = VBox([LyricCheck,hbox5a, hbox5b, hbox5c], padding=6)
    

    hbox3 = HBox([vbox3a],text = 'Liedtext')
    
    vbox4  = VBox([vbox2,lableer,AuswahlRadio,hbox4, hbox3], text='', padding=6)
    
    dlg = Dialog('Bitte wählen: ', vbox4)

    if dlg.run() and Stimmenzahl>=1:
        selectedOriginalVoice = latin1_d(justVoices[selLayoutCombo1.value()])
        selectedOriginalStaff = latin1_d(justStaffs[selLayoutCombo1.value()])  
        Auswahl = AuswahlRadio.value()      
        
        lyricTransfer = LyricCheck.value()
        
        if selLayoutCombo2.value() < len(justVoices):
            selectedTargetStimmeVoice = latin1_d(justVoices[selLayoutCombo2.value()])
            selectedTargetStimmeStaff = latin1_d(justStaffs[selLayoutCombo2.value()])
            
        if selLayoutCombo2.value() == (len(justVoices)):
            selectedTargetStimmeVoice = '0'
            selectedTargetStimmeStaff = 'Joker'	
        if selLayoutCombo2.value() == len(justVoices)+1:
            selectedTargetStimmeVoice = '999999'
            selectedTargetStimmeStaff = 'Joker'	  
        if TextCheck.value() == 1:
            objectsChosen += ['text']
        if RichTextCheck.value() == 1:
            objectsChosen += ['richText']
        if LineCheck.value() == 1:
            objectsChosen += ['line']
        if EllipseCheck.value() == 1:
            objectsChosen += ['ellipse']
        if GuitarCheck.value() == 1:
            objectsChosen += ['guitar']
        if MetafileCheck.value() == 1:
            objectsChosen += ['metafile']
        if NoteLineCheck.value() == 1:
            objectsChosen += ['notelines']
        if PolygoneCheck.value() == 1:
            objectsChosen += ['polygon']
        if RectangleCheck.value() == 1:
            objectsChosen += ['rectangle']
        if SlurCheck.value() == 1:
            objectsChosen += ['slur']
        if TransposablesCheck.value() == 1:
            objectsChosen += ['transposable']   
        if TrillCheck.value() == 1:
            objectsChosen += ['trill']
        if VoltaCheck.value() == 1:
            objectsChosen += ['volta']  
        if WavyLineCheck.value() == 1:
            objectsChosen += ['wavyLine']
        if WedgeCheck.value() == 1:
            objectsChosen += ['wedge']
        
        lyricChosen = [Strophe1Check.value(),Strophe2Check.value(),Strophe3Check.value(),Strophe4Check.value(),Strophe5Check.value(),Strophe6Check.value(),Strophe7Check.value(),Strophe8Check.value(),Strophe9Check.value()]

        return True
    else:
        return False

def getCursor():
    sel = curSelection()
    result = None
    if sel == 0:
        messageBox('Fehler', 'keine aktive Partitur')
        return result
    result = sel[0]
    return result
                        
def getVoiceNames(score):
    global Stimmenzahl
    
    layouts = []
    
    Stimmenzahl = 0
    for staff in score.getElementsByTagName('staff'):
        layout = staff.getAttribute('layout')
        for n in range(staff.getElementsByTagName('voice').length):
            nplus = n+1
            justStaff = latin1_e(layout)
            justVoice = latin1_e(' %02d' % n)
            voiceName = latin1_e(layout+(' %02d' % nplus)+'.Stimme')
            if voiceName not in layouts:
                layouts.append(voiceName)
                justStaffs.append(justStaff)
                justVoices.append(justVoice)
                Stimmenzahl = Stimmenzahl + 1
    #layouts.sort()
    return layouts
    
    
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 Test(text):
    messageBox('Test',str(text))

def getTime(chord):
    objList = getElementObjects(chord.parentNode.parentNode.getElementsByTagName('noteObjects')[0].childNodes)
    time = 0
    i = 0
    while chord <> objList[i]:
        objects = objList[i]
        addTime = getLength(objects)
        time +=  addTime
        i += 1
    return time

def getIrregular(object):
    irregular = float(1)
    count = 0
    tripartite = 'false'
    for duration in object.getElementsByTagName('duration'):
        for tuplet in duration.getElementsByTagName('tuplet'):
            count = string.atoi(tuplet.getAttribute('count'))
            tripartite = tuplet.getAttribute('tripartite')

    if count == 2 and tripartite == 'true':
        irregular = float(3) /float (4)
    elif count == 3:
        irregular =  float(2) /float (3)
    elif count == 5:
        irregular = float(4) /float (5)
    elif count == 7:
        irregular = float(4) /float (7)
    else:
        irregular = 1

    return irregular


def getLength(object):
    length = 0
    if object.tagName in ['chord','rest']:
        for duration in object.getElementsByTagName('duration'):
            if duration.getAttribute('noDuration') <> 'true':
                if not duration.getAttribute('base') in ['1']:
                    length = 1 / string.atof(duration.getAttribute('base')[2:])

                else:
                    length = 1
                dotsMult = 1
                d = duration.getAttribute('dots')
                if d == '1':
                    dotsMult = 1.5
                elif d == '2':
                    dotsMult = 1.75
                elif d == '3':
                    dotsMult = 1.875
                length = length * dotsMult
                length = length * getIrregular(object)

    return length

def eliminateNotChosenLyric(lyricClone):
    for verse in lyricClone.getElementsByTagName('verse'):
        verseCounter = string.atoi(verse.getAttribute('i'))
        if lyricChosen[verseCounter] == 0:
            lyricClone.removeChild(verse)

    if len(lyricClone.getElementsByTagName('verse')) == 0:
        return False
    else:
        return lyricClone

def handleObject(noteObject, drawObjectArray, lyricArray):
    if noteObject.tagName in ['chord', 'rest']:
        objectTime = getTime(noteObject)
        for drawObj in noteObject.getElementsByTagName('drawObj'):
            drawObjClone = drawObj.cloneNode(1)
            drawObjectArray+=[[drawObjClone,objectTime]]

        for lyric in noteObject.getElementsByTagName('lyric'):
            lyricClone = lyric.cloneNode(1)
            lyricClone = eliminateNotChosenLyric(lyricClone)
            if lyricClone <> False:
                lyricArray+=[[lyricClone,objectTime]]



def isObjectChosen(drawObj):
    global objectsChosen
    result = False
    i=0
    for elements in objectsChosen:
        if len(drawObj.getElementsByTagName(objectsChosen[i])) > 0:
            result = True 
            break
        i +=1
    return result

def setLyric(noteObject, lyricClone):
    global lyricOverwrite

    if len(noteObject.getElementsByTagName('lyric')) <= 0:
        noteObject.appendChild(lyricClone)
    else:
        lyric = noteObject.getElementsByTagName('lyric')[0]
        for verseClone in lyricClone.getElementsByTagName('verse'):
            verseCloneFound = False
            verseCloneCounter = verseClone.getAttribute('i')
            for verse in lyric.getElementsByTagName('verse'):
                if verseCloneCounter == verse.getAttribute('i'):
                    verseCloneFound = True
                    if lyricOverwrite == 0:
                        lyricOverwrite = messageBox('ACHTUNG','Sie wollen Liedtext übertragen, in Strophen anderer Zeilen die schon mit Liedtext gefüllt sind.                                   Wollen Sie diesen wirklich überschreiben?', img=3, buttons=2, defBtn=0)
            if verseCloneFound == False or lyricOverwrite == 2:
                lyric.appendChild(verseClone)
                
                

def setObjects(noteObject, drawObjectArray, lyricArray):

    if noteObject.tagName in ['chord', 'rest']:
        objectTime = getTime(noteObject)
        i=0
        while i < len(drawObjectArray):
            if drawObjectArray[i][1] == objectTime:
                if isObjectChosen(drawObjectArray[i][0]):
                    drawObjects = addElementNode(noteObject,'drawObjects')
                    drawObjects.appendChild(drawObjectArray[i][0].cloneNode(1))
            i+=1
        
        if noteObject.tagName in ['chord']:
            i=0

            while i < len(lyricArray):
                if lyricArray[i][1] == objectTime:
                    if lyricTransfer == True:
                        setLyric(noteObject, lyricArray[i][0].cloneNode(1))
                i+=1
                

def changeDoc(score):
    global  allLayouts, Auswahl,selectedOriginalVoice, selectedOriginalStaff,  selectedTargetStimmeVoice, selectedTargetStimmeStaff, stimme, Stimmenzahl, clefChosen, lyricOverwrite

    sel = getCursor()
    
    lyricOverwrite = 0
    systemSel = score.getElementsByTagName('system')[sel[0]]
    voiceNames = getVoiceNames(score)
    allLayouts = getAllLayouts(score)
    staffLayouts = score.getElementsByTagName('staffLayout')
    
    systems = score.getElementsByTagName('system')
    staffs = score.getElementsByTagName('staff')


    if getDialogValues1(voiceNames):


        for system in systems:
            if system == systemSel or Auswahl == 1:
                staves = system.getElementsByTagName('staves')
                drawObjectArray = []
                lyricArray = []
                for staff in system.getElementsByTagName('staff'): 			# Erstellung einer List mit Clones der graphischen Objekte
                    descr = staff.getAttribute('layout')					# 
                    if descr == selectedOriginalStaff :						# 
                        j=0
                        for voice in staff.getElementsByTagName('voice'):
                            if j == string.atoi(selectedOriginalVoice):
                                originalVoice = voice
                                objList = getElementObjects(voice.getElementsByTagName('noteObjects')[0].childNodes)
                                k = 0 
                                while k <len(objList): 
                                    handleObject(objList[k],drawObjectArray, lyricArray)
                                    k+=1
                                
                            j+=1
                
                    
                for staff in system.getElementsByTagName('staff'): 			# Einfügen der Zeilen
                    descr = staff.getAttribute('layout')			
    
                    if descr == selectedTargetStimmeStaff or selectedTargetStimmeStaff == 'Joker':				
                        j=0
                        for voice in staff.getElementsByTagName('voice'):
                            if (j == string.atoi(selectedTargetStimmeVoice) or selectedTargetStimmeVoice == '999999') and voice <> originalVoice:
                        
                                objList = getElementObjects(voice.getElementsByTagName('noteObjects')[0].childNodes)
                                k = 0 
                                while k <len(objList): 
                                    setObjects(objList[k],drawObjectArray, lyricArray)
                                    k+=1
                                    
                            j+=1
                    
            


# Hauptprogramm:

from caplib.capDOM import ScoreChange
import tempfile

class ScoreChange(ScoreChange):
    def changeScore(self, score):
       global doc
       doc = score.parentNode  
       changeDoc(score)

if activeScore():
    
    activeScore().registerUndo("Bezeichnungen übertragen")
    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)
    ScoreChange(tempInput, tempOutput)
    activeScore().read(tempOutput)
    os.remove(tempInput)
    os.remove(tempOutput)

