# -*- coding: ISO-8859-1 -*-
""" capellaScript -- 28.02.2004 Paul Villiger
>>> Rhythmus angleichen

    Synchronisiert den Rhythmus zweier Stimmen oder aller Stimmen mit einer.

<<<

History:  23.02.2004 - Erste Ausgabe
          28.02.2004 - Neu Hinweis bei unterschiedlicher Notenanzahl

"""
from xml.dom.minidom import NodeList
from string import strip

def latin1_e(u):
    return u.encode('Latin-1')
def latin1_d(u):
    return u.decode('Latin-1')

doc = [] # parentNode von score

options = ScriptOptions()
opt = options.get()

def getVoiceNames(score):
    layouts = []
    for staff in score.getElementsByTagName('staff'):
        layout = staff.getAttribute('layout')
        for n in range(staff.getElementsByTagName('voice').length):
            voiceName = latin1_e(layout+('_%02d' % n))
            if voiceName not in layouts:
                layouts.append(voiceName)
    #layouts.sort()
    return layouts


def getNoteObjects(voice):  # returns a List
    noteObject = voice.getElementsByTagName('noteObjects')[0]
    objList = noteObject.childNodes
    newList = NodeList()
    for n in range(objList.length):
        if objList[n].nodeType == objList[n].ELEMENT_NODE:
            newList.append(objList[n])
    return newList

def moveRhythm(voice1,voice2):
    list1 = getNoteObjects(voice1)
    list2 = getNoteObjects(voice2)
    if len(list1) == len(list2):
        diffLength = False
    else:
        diffLength = True
        
    for n in range(min(len(list1),len(list2))):
        if list1[n].tagName in ['chord','rest'] and list2[n].tagName in ['chord','rest']:
            dur1 = list1[n].getElementsByTagName('duration')[0]
            dur2 = list2[n].getElementsByTagName('duration')[0]

            dur2.setAttribute('base',dur1.getAttribute('base'))

            tuplets1 = dur1.getElementsByTagName('tuplet')
            tuplets2 = dur2.getElementsByTagName('tuplet')
            # wenn Triolen in erster Stimme, dann übernehmen
            if tuplets1.length > 0:
                tup1 = tuplets1[0].cloneNode(True)
                if tuplets2.length > 0:
                    dur2.replaceChild(tup1,tuplets2[0])
                else:
                    dur2.appendChild(tup1)
            # wenn Triolen nur in zweiter Stimme, dann löschen
            elif tuplets2.length > 0:
                tuplets2[0].removeAttribute('count')
                
            # Punktierung angleichen
            dur2.setAttribute('dots',dur1.getAttribute('dots'))
            
    return diffLength

def dialog(voiceNames):
    leerzeile      = Label('')

    lab1       = Label('A:', width = 3)
    cboxVoice1 = ComboBox(voiceNames, value=0, width = 25)
    hbox1      = HBox([lab1, cboxVoice1])    

    lab2       = Label('B:', width = 3)
    cboxVoice2 = ComboBox(voiceNames, value=0, width = 25)
    hbox2      = HBox([lab2, cboxVoice2])    

    lab3       = Label('', width = 3)
    cboxAll    = CheckBox('All Stimmen an A: angleichen', value=0)
    hbox3      = HBox([lab3, cboxAll])    
    
    vbox       = VBox([hbox1,leerzeile,hbox2,leerzeile, hbox3])

    dlg = Dialog('-- Rythmus angleichen --', vbox)
    
    if dlg.run():
        res1 = voiceNames[cboxVoice1.value()]
        res2 = voiceNames[cboxVoice2.value()]
        res3 = cboxAll.value() <> 0
    else:
        res1 = res2 = ''
        res3 = False
    return res1, res2, res3
    
    
            
    
def changeDoc(score):
    voiceNames = getVoiceNames(score)
    vn1, vn2, all = dialog(voiceNames)
    if vn1 == '' or vn2 == '':
        return
    systemNo = 0
    diffLength = dict()
    for system in score.getElementsByTagName('system'):
        systemNo += 1
        voiceDict = dict()
        for staff in system.getElementsByTagName('staff'):
            layout = staff.getAttribute('layout')
            voices = staff.getElementsByTagName('voice')
            for n in range(voices.length):
                voiceName = latin1_e(layout+('_%02d' % n))
                voiceDict[voiceName] = voices[n]

        if vn1 in voiceDict:
            if all:
                for vn2 in voiceDict:
                    if moveRhythm(voiceDict[vn1],voiceDict[vn2]):
                        diffLength[systemNo] = True
            elif vn2 in voiceDict:
                if moveRhythm(voiceDict[vn1],voiceDict[vn2]):
                    diffLength[systemNo] = True
                    
    # Hinweis wegen unterschiedlicher Länge ausgeben
    l = diffLength.keys()
    l.sort()
    if len(l) > 0:
        s = str(l[0])
        for x in l[1:]:
            s = s + ', '+ str(x)
            
        messageBox('Rhythmus angleichen','Hinweis:\n\nIn den folgenden Systemen existieren \nNotenzeilen mit unterschiedlicher Länge:\n\n' + s,2)
                
            

# Hauptprogramm:

from caplib.capDOM import ScoreChange
import tempfile

class ScoreChange(ScoreChange):
    def changeScore(self, score):
        doc = score.parentNode
        changeDoc(score)

if activeScore():
    activeScore().registerUndo("Rhythmus angleichen")

    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)

    ScoreChange(tempInput, tempOutput)

    activeScore().read(tempOutput)
    os.remove(tempInput)
    os.remove(tempOutput)

