# -*- coding: ISO-8859-1 -*-
""" capellaScript -- 05.12.2003 Paul Villiger
>>> Lieder Bindebogen anpassen

    Bei zweistimmingen Noten wird der Bindebogen vom Notenhalsende an den Notenkopf gehängt.|
    
<<<
History: 01.12.03 - Erste Version (Vorschlag von Klaus Meglitsch)
         05.12.03 - getMin/MaxPitch Multipikator von 6 -> 7 korrigiert
         09.12.03 - neu slurOffset
         10.12.03 - Berücksichtigung der Schlüssel
         
"""

import xml.dom
notenString='CDEFGAB'
slurOffset = 0.75
clefOffset = 41

def getMaxPitch(chord):
    maxV = 0
    for head in chord.getElementsByTagName('head'):
        pitch = head.getAttribute('pitch')
        pitchN = notenString.find(pitch[0]) + 7 * long(pitch[1])
        if pitchN > maxV:
            maxV=pitchN
    maxV = - (maxV - clefOffset) / 2.0  # B5 auf Mittellinie
    return maxV
        
def getMinPitch(chord):
    minV = 999
    for head in chord.getElementsByTagName('head'):
        pitch = head.getAttribute('pitch')
        pitchN = notenString.find(pitch[0]) + 7 * long(pitch[1])
        if pitchN < minV:
            minV=pitchN
    minV = - ((minV - clefOffset) / 2.0)  # B5 auf Mittellinie
    return minV


def chordHasBeam(chord,nextChord):
    beams = chord.getElementsByTagName('beam')
    
    if chord.getElementsByTagName('duration')[0].getAttribute('base') in ['2/1', '1/1', '1/2', '1/4']:
        return False
    elif nextChord.getElementsByTagName('duration')[0].getAttribute('base') in ['2/1', '1/1', '1/2', '1/4']:
        return False
    elif nurFaehnchen:
        if beams.length > 0:
            if beams[0].hasAttribute and beams[0].getAttribute('group') in ['force','divide']:
                return True
            else:
                return False
        else:
            return False
    else: # Balken werden automatisch gesetzt
        if beams.length > 0:
            if beams[0].hasAttribute and beams[0].getAttribute('group') in ['split']:
                return False
            else:
                return True
        else:
            return True

def getNextChord(nodes,n):
    for x in range(n+1, nodes.length):
        if nodes[x].nodeType == nodes[x].ELEMENT_NODE:
            if nodes[x].tagName == 'chord':
                return nodes[x]
    else:
        return None

def calculateClefOffset(c):
    global clefOffset
    # Berechnet den Offset der Note, welche bei diesem Schluessel auf der Mittellinie steht
    # Schlüssel umwandeln
    if c == 'treble':
        newC = 'G2'
    elif c == 'bass':
        newC = 'F4'
    elif c == 'alto':
        newC = 'C3'
    elif c == 'tenor':
        newC = 'C4'
    else:
        newC = c
    
    # Schlüssel analysieren
    clef = newC[0]
    line = int(newC[1])
    if newC.find('-') > 0:
        okt = -7
    elif newC.find('+') > 0:
        okt = 7
    else:
        okt = 0
    # Offset berechnen
    offset = - 2 * line + okt
    if clef == 'G':  # G-Schlüssel
        offset += 45
    elif clef == 'F':
        offset += 37 # F-Schlüssel
    elif clef == 'C':
        offset += 41 # C-Schlüssel
    elif clef in  ['N','P']:
        offset += 47 # Schlagzeug & Kein Schlüssel
    else:
        offset = clefOffset
    clefOffset = offset
            
def changeDoc(score):
    for system in score.getElementsByTagName('system'):
        # iteration über alle Systeme
        global nurFaehnchen  
        nurFaehnchen = system.getAttribute('beamGrouping') == '0'
        for voice in system.getElementsByTagName('voice'):
            if voice.hasAttributes and (voice.getAttribute('stemDir') in ['up', 'down']):
                noteObject = voice.getElementsByTagName('noteObjects')[0]
                childs = noteObject.childNodes
                for n in range(childs.length -1):
                    if childs[n].nodeType == childs[n].ELEMENT_NODE:
                        if childs[n].tagName == 'clefSign':
                            calculateClefOffset(childs[n].getAttribute('clef'))
                        elif childs[n].tagName == 'chord':
                            for drawObj in childs[n].getElementsByTagName('drawObj'):
                                for slur in drawObj.getElementsByTagName('slur'):
                                    for basic in drawObj.getElementsByTagName('basic'):
                                        if basic.hasAttributes and basic.getAttribute('noteRange') == '1':
                                            # Noch prüfen auf nur Faehnchen, Noten mit Faehnchen und gesetzte Balken
                                            nextChord = getNextChord(childs, n)
                                            if nextChord <> None and chordHasBeam(childs[n], nextChord) :
                                                pass
                                            else:
                                                maxV=getMaxPitch(childs[n])
                                                minV=getMinPitch(childs[n])
                                            
                                                y1 = float(slur.getAttribute('y1'))
                                                y2 = float(slur.getAttribute('y2'))
                                                y3 = float(slur.getAttribute('y3'))
                                                y4 = float(slur.getAttribute('y4'))
                                        
                                                if voice.getAttribute('stemDir') == 'up':
                                                    newY = maxV
                                                    dy = newY - y1 - slurOffset
                                                else:
                                                    newY = minV
                                                    dy = newY - y1 + slurOffset
                                            
                                                slur.setAttribute('y1', str(y1 + dy))
                                                slur.setAttribute('y2', str(y2 + dy))
                                                slur.setAttribute('y3', str(y3 + dy))
                                                slur.setAttribute('y4', str(y4 + dy))
                                            

# Hauptprogramm:

from caplib.capDOM import ScoreChange
import tempfile

class PausenQuetscher(ScoreChange):
    def changeScore(self, score):
        changeDoc(score)

if activeScore():
    activeScore().registerUndo("Staff Editor")
    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)
    
    PausenQuetscher(tempInput, tempOutput)

    activeScore().read(tempOutput)
    os.remove(tempInput)
    os.remove(tempOutput)

