# -*- coding: ISO-8859-1 -*-
""" capellaScript -- (c) Paul Villiger
>>> Pausen immer in der Mitte

    Bei zweistimmigen Liedern wird die Pause in die Mitte gesetzt, wenn in der
    Ober und Unterstimme die gleiche Pause vorkommt.

    Einschränkung: Bei mehreren Ober- und/oder  Unterstimmen wird die letzte Stimme verwendet.

<<<
History:  19.01.2004 - Erste Version
          02.02.2004 - Beim Ausmitten wird die vertikale Pausenposition gelöscht
          05.01.2006 - Absturz bei leeren Stimmen
         
"""

import xml.dom
from xml.dom.minidom import NodeList

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 centerRests(intUp, intDown, extUp, extDown):
    if intUp.nNoteObjs() == 0 or intDown.nNoteObjs() == 0:
        return
    timeUp = timeDown = Rational(0)
    noteObjsUp = getNoteObjects(extUp)    
    noteObjsDown = getNoteObjects(extDown)
    ptDown = 0
    timeDown = timeDown + intDown.noteObj(ptDown).duration()
    for ptUp in range(intUp.nNoteObjs()):
        if intUp.noteObj(ptUp).isChord() or intUp.noteObj(ptUp).isRest():
            timeUp = timeUp + intUp.noteObj(ptUp).duration()
            while timeDown < timeUp:
                ptDown += 1
                if ptDown > intDown.nNoteObjs()-1:
                    return
                timeDown = timeDown + intDown.noteObj(ptDown).duration()

            if timeUp == timeDown and intUp.noteObj(ptUp).isRest() and intDown.noteObj(ptDown).isRest():
                if intUp.noteObj(ptUp).duration() == intDown.noteObj(ptDown).duration():
                    vPosUp = noteObjsUp[ptUp].getElementsByTagName('verticalPos')
                    if vPosUp.length == 0:
                        vPosUp = doc.createElement('verticalPos')
                        noteObjsUp[ptUp].appendChild(vPosUp)
                    else:
                        vPosUp = vPosUp[0]
                    vPosUp.setAttribute('centered','true')
                    if vPosUp.getAttribute('shift'):
                        vPosUp.removeAttribute('shift')

                    vPosDown = noteObjsDown[ptDown].getElementsByTagName('verticalPos')
                    if vPosDown.length == 0:
                        vPosDown = doc.createElement('verticalPos')
                        noteObjsDown[ptDown].appendChild(vPosDown)
                    else:
                        vPosDown = vPosDown[0]
                    vPosDown.setAttribute('centered','true')
                    if vPosDown.getAttribute('shift'):
                        vPosDown.removeAttribute('shift')
                
    
def changeDoc(score):
    for sy in range(activeScore().nSystems()):
        intSystem = activeScore().system(sy)
        extSystem = score.getElementsByTagName('system')[sy]
        for st in range(intSystem.nStaves()):
            extStaff = extSystem.getElementsByTagName('staff')[st]
            intStaff = intSystem.staff(st)
            # Ober und Unterstimme suchen
            voiceUp = voiceDown = None
            extVoices = extStaff.getElementsByTagName('voice')
            for vo in range(extVoices.length):
                if extVoices[vo].hasAttribute('stemDir'):
                    stemDir = extVoices[vo].getAttribute('stemDir')
                    if stemDir == 'up':
                        voiceUp = vo
                    elif stemDir == 'down':
                        voiceDown = vo
                        
            if voiceUp <> None and voiceDown <> None:
                # wenn eine Ober- und eine Unterstimme gefunden wurde
                centerRests(intStaff.voice(voiceUp),
                           intStaff.voice(voiceDown),
                           extVoices[voiceUp],
                           extVoices[voiceDown])
            

# 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("Pausen immer in der Mitte")
    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)
    
    ScoreChange(tempInput, tempOutput)

    activeScore().read(tempOutput)
    os.remove(tempInput)
    os.remove(tempOutput)
