# -*- coding: ISO-8859-1 -*-
""" capellaScript -- (c) Paul Villiger
>>> Pausen verbergen

    Dieses Skript verbirgt Pausen in einer Notenzeile, wenn in einer anderen Stimme der Notenzeile eine Note steht.

    Rückmeldungen bitte an villpaul(a)bluewin.ch
<<<

History: 13.02.2009 - Erste Ausgabe
         15.08.2009 - Absturz behoben

"""
german = ("de", {
    'dialogHeader'      :   ' Pausen verbergen ',
    'regUndo'           :   'Pausen verbergen',
    'layoutSelect'      :   'Notenzeile:'
    } )

try:
    exec('from %s import translations' % ( translationModule() ))
    translations.append(german)
    setLanguages(translations)
except:
    def tr(s):
        return german[1].get(s, "???")
#-------------------------------------------------------------------
from xml.dom.minidom import parseString, NodeList, Node, Element
from caplib.rational import Rational
from caplib.capDOM import ScoreChange
import tempfile, string, new

def latin1(u):
    return u.encode('Latin-1')

doc = parseString('<score/>')

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 getDuration(note):
    """ Dauer einer Note oder Pause als rationale Zahl in ganzen Noten
        <note> muss ein 'chord'- oder 'rest'-Knoten sein
        (kopiert aus capDOM.py und angepasst)
    """
    duration = note.gotoChild('duration')
    if duration.getAttribute('noDuration') == 'true':
        return 0
    n = Rational(str(duration.getAttribute('base')))

    dots = duration.getAttribute('dots')
    if dots != '':
        if int(dots) == 1: n = (3 * n) / 2
        elif int(dots) == 2: n = (7 * n) / 4
        else: n = (15 * n) / 8

    tuplet = duration.gotoChild('tuplet')
    if tuplet.hasAttribute('count'):
        denominator = Rational(int(tuplet.getAttribute('count')))
        numerator = Rational(1)
        if tuplet.getAttribute('tripartite') == 'true':
           numerator = Rational(3,2)
        while numerator < denominator: numerator *= 2
        if tuplet.getAttribute('prolong') != 'true':
           numerator /= 2
        n = (n * numerator) / denominator

    return n

def getAllLayouts(score):
    # Gibt eine Liste zurueck mit allen Eintraegen aus dem Mustersystem,
    staffLayoutList = []
    for staffLayout in score.getElementsByTagName('staffLayout'):
        staffLayoutList.append(latin1(staffLayout.getAttribute('description')))

    return staffLayoutList
            

def hideRests(staff):
    voiceList = []
    voicePointer = []
    voiceIsRest = []
    for no in staff.getElementsByTagName('noteObjects'):
        child = no.firstChild
        while child:
            if child.nodeType == child.ELEMENT_NODE and child.tagName in ['chord','rest']:
                voiceList.append(child)
                voicePointer.append(Rational(0))
                voiceIsRest.append(child.tagName == 'rest')
                break
            child = child.nextSibling
            
    if len(voiceList) == 0:
        return

    finish = False
    while not finish:
        # get the shortest pointer (duration)
        p = Rational(9999)
        pi = -1
        for i in range(len(voiceList)):
            if voicePointer[i] < p:
                p = voicePointer[i]
                pi = i

        # adjust all lines with the same pointer
        for i in range(len(voiceList)):
            if voicePointer[i] == p:
                voiceIsRest[i] = voiceList[i].tagName == 'rest'

        # messageBox('',str(voicePointer) + str(voiceIsRest))
        
        # if a chord exists at same duration, the rest is made invisible
        if voiceIsRest[pi]:
            for i in range(len(voiceList)):
                if i == pi:
                    continue
                if not voiceIsRest[i]:      # is chord
                    display = voiceList[pi].gotoChild('display')
                    display.setAttribute('invisible','true')
                    break
        

        voicePointer[pi] += getDuration(voiceList[pi])

        # search next chord or rest
        voiceList[pi] = voiceList[pi].nextSibling
        while voiceList[pi] and ( voiceList[pi].nodeType <> voiceList[pi].ELEMENT_NODE or voiceList[pi].tagName not in ['chord','rest']):
                voiceList[pi] = voiceList[pi].nextSibling

        # at end of voice the pointer is set to 9999
        if not voiceList[pi]:
            voicePointer[pi] = Rational(9999)
            finish = True
            # check if still a voice is remaining
            for p in voicePointer:
                if p <> Rational(9999):
                    finish = False
                    break
            

def userInput(staffLayoutList):
    
    layoutSelect = ComboBox(staffLayoutList, value = 0, width = 20)
    dlg = Dialog(tr('dialogHeader'),
                 VBox([HBox([Label(tr('layoutSelect'), width = 10),layoutSelect]),
                       Label(' ')
                       ]))
    if dlg.run():
        ok = True
        layoutSelect = staffLayoutList[layoutSelect.value()]
    else:
        ok = False

    return ok, layoutSelect

handlingOk = True

def changeDoc(score):
    staffLayoutList = getAllLayouts(score)
    handlingOk, selectedLayout = userInput(staffLayoutList)
   
    for staff in score.getElementsByTagName('staff'):
        if selectedLayout == staff.getAttribute('layout'):
            hideRests(staff)

class ScoreChange(ScoreChange):

    def changeScore(self, score):
        global scriptAction, doc
        doc = score.parentNode
        changeDoc(score)
        
if activeScore():

    activeScore().registerUndo( tr('regUndo') )
    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)

    ScoreChange(tempInput, tempOutput)

    if handlingOk:
        activeScore().read(tempOutput)
        
    os.remove(tempInput)
    os.remove(tempOutput)


