# -*- coding: ISO-8859-1 -*-
""" capellaScript -- (c) Paul Villiger
>>> Pausenschieber

    - In Unter- und Oberstimmen kann die vertikale Position der Pausen gesetz werden|
    - Bei gleichen Pausen in Unter- und Oberstimmen werden sie in die Mitte gesetzt|
    - Pausen in Unter- und/oder Oberstimmen verstecken.
      
<<<
History:  03.02.2004 - Erste Version
          08.12.2004 - Zusammenfassung von Skript "Pausenschieber" und "Pausen immer in der Mitte"
                     - Neu Pausen in Unter-/Oberstimme verstecken
          05.01.2006 - Absturz bei leeren Stimmen
         
"""
# ---- Defaultwerte ----

shiftUp   = '1'
shiftDown = '-1'
centerRest = True

import xml.dom, new
from xml.dom.minidom import NodeList, Node, Element

def getDialog():
    global shiftUp, shiftDown, centerRest, hideUp, hideDown, selPos

    selHide = CheckBox('Pausen unsichtbar', value = 0, width = 20)
    hideUp  = CheckBox('', value = 0, width = 5)
    hideDown  = CheckBox('', value = 0, width = 5)
    selCenter = CheckBox('Pausen in Mitte', value = centerRest, width = 20)
    selPos  = CheckBox('Vertikale Position', value = 1, width = 20)
    posUp   = Edit(shiftUp, width = 5)
    posDown   = Edit(shiftDown, width = 5)


    dlg = Dialog('--- Pausen Schieber ---',
                 VBox([HBox([Label(' ', width=24 ), Label('Stimme  ') ]),
                       # Label(' '),
                       HBox([Label(' ', width=20 ), Label('Ober-', width=5), Label(' ', width = 1), Label('Unter-', width = 5) ]),
                       Label(' '),
                       HBox([selPos, posUp, Label(' ', width = 1),posDown]),
                       # Label(' '),
                       HBox([selHide, hideUp, Label(' ', width = 1), hideDown]),
                       # Label(' '),
                       HBox([selCenter]),
                       Label(' ')
                     ]))

    if dlg.run():
        shiftUp = posUp.value()
        shiftDown = posDown.value()
        centerRest = selCenter.value() == 1
        selPos = selPos.value() == 1
        selHide = selHide.value() == 1
        hideUp = hideUp.value() and selHide
        hideDown = hideDown.value() and selHide
        return True
    else:
        return False

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 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():
                    # gleiche Pausen in Ober- und Unterstimme
                    if centerRest:
                        vPos = noteObjsUp[ptUp].gotoChild('verticalPos')
                        vPos.setAttribute('centered','true')
                        if vPos.getAttribute('shift'):
                            vPos.removeAttribute('shift')
                        vPos = noteObjsDown[ptDown].gotoChild('verticalPos')
                        vPos.setAttribute('centered','true')
                        if vPos.getAttribute('shift'):
                            vPos.removeAttribute('shift')
            elif timeUp == timeDown:
                if intUp.noteObj(ptUp).isRest() and hideUp:
                    display = noteObjsUp[ptUp].gotoChild('display')
                    display.setAttribute('invisible','true')
                if intDown.noteObj(ptDown).isRest() and hideDown:
                    display = noteObjsDown[ptDown].gotoChild('display')
                    display.setAttribute('invisible','true')
                        
    
def changeDoc(score):
    if selPos:
        for voice in score.getElementsByTagName('voice'):
            if voice.hasAttribute('stemDir'):
                stemDir = voice.getAttribute('stemDir')
                for rest in voice.getElementsByTagName('rest'):
                    verticalPos = rest.gotoChild('verticalPos')
                    if stemDir == 'up':
                        verticalPos.setAttribute('shift',shiftUp)
                    elif stemDir == 'down':
                        verticalPos.setAttribute('shift',shiftDown)

    # Anteil aus Skript "Pausen immer in der Mitte"
    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() and getDialog():
    activeScore().registerUndo("Pausenschieber")
    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)
    
    ScoreChange(tempInput, tempOutput)

    activeScore().read(tempOutput)
    os.remove(tempInput)
    os.remove(tempOutput)

