# -*- coding: ISO-8859-1 -*-
""" capellaScript -- (c) Paul Villiger
>>> Staff Editor

    Notenzeilen umbenennen, vertauschen, kopieren, duplizieren, loeschen, aufspalten||
    Aenderungen in einem System oder in allen Systemen moeglich
<<<

History: 30.10.03 - Erste Ausgabe
         05.11.03 - neu kopieren, duplizieren, loeschen
                  - Neuer Name: Layout Manager -> Staff Editor
                  - Umlaute in Mustersystem erlaubt
         13.11.03 - Verwendung der Klasse ScoreChange
         14.01.04 - Notenzeilen zusammenfassen A + B - > A
         15.03.06 - Fehler: Bei Cursor 0,0,0,0 wird Skript nicht ausgeführt
         11.05.10 - Notenzeilen zusammenfassen: Fehler wenn eine Stimme fehlt
         06.11.10 - Neu: Notenzeile in aufspalten
                    
"""

def latin1(u):
    return u.encode('Latin-1')

def getCursor():
    sel = curSelection()
    result = (-1, -1, -1, -1)
    if sel == 0:
        messageBox('Fehler', 'keine aktive Partitur')
        return result
    #if sel[0] != sel[1]:
    #    messageBox('Fehler', 'Markierung ist nicht leer')
    #    return result
    result = sel[0]
    return result

def getAllLayouts(score):
    # Gibt eine Liste zurueck mit allen Eintraegen aus dem Mustersystem,
    # sowie deren Verwendungshaeufigkeit
    staffLayouts = score.getElementsByTagName('staffLayout')
    for i in range(staffLayouts.length):
        staffLayouts[i].count = 0
        for staff in score.getElementsByTagName('staff'):
            if staffLayouts[i].getAttribute('description') == staff.getAttribute('layout'):
                staffLayouts[i].count += 1
    return staffLayouts
    
def layoutExistsInSystem(system, layout):    
    result = False
    for staff in system.getElementsByTagName('staff'):
        if staff.getAttribute('layout') == layout:
            result = True
    return result
        
def changeDoc(score):
    (sy, st, vo, ob) = getCursor()
    if sy == -1:
        return

    allLayouts = getAllLayouts(score)

    layoutList = [ latin1(allLayouts[i].getAttribute('description')) +' (' + str(allLayouts[i].count) + ')' 
                   for i in range(allLayouts.length ) ]

    # Aktuelle Cursorposition bestimmen
    (sy, st, vo, ob) = getCursor()
    
    #----------------------------------------------------
    #----- Dialog Optionen laden ------------------------
    options = ScriptOptions() 
    opt = options.get()

    oldLay = ComboBox( layoutList, value = 0, width=32)
    newLay = ComboBox( layoutList, value = 0, width=32)

    hBox1 = HBox([Label('A :', width = 3), oldLay], padding = 8, text='Notenzeile A')
    hBox2 = HBox([Label('B :', width = 3), newLay], padding = 8, text='Notenzeile B')
    

    renameLayout = Radio(['Umbenennen A -> B (wenn B nicht vorhanden) ',
                          'Vertauschen A <-> B',
                          'Duplizieren A',
                          'Kopieren A -> B (wenn B nicht vorhanden)',
                          'Loeschen A',
                          'Zusammenführen A + B -> A',
                          'Aufspalten A'], value=0 , padding=12, text = 'Notenzeile Aktion')

    actualSystem = CheckBox('Nur aktuelles System aendern ( '+str(sy+1)+' )', value = 0)
    
    vBox   = VBox([hBox1,
                   hBox2,
                   Label(' '),
                   renameLayout,
                   Label(' '),
                   actualSystem,
                   Label(' ')])
        
    dlg = Dialog('  -- Staff Editor --  ', vBox)

    if dlg.run():
        layoutA = allLayouts[ oldLay.value() ].getAttribute('description') 
        layoutB = allLayouts[ newLay.value() ].getAttribute('description') 
        layoutAction = renameLayout.value()
        actSystem = bool( actualSystem.value() == 1 )

        systems = score.getElementsByTagName('system')
        if actSystem:
            # Aenderung nur im aktuellen System durchfuehren
            systems = [systems[sy]]
        
        # ---- Layout duplizieren ------
        if layoutAction == 2:
            # Mustersystem erweitern
            for staffLayout in score.getElementsByTagName('staffLayout'):
                if staffLayout.getAttribute('description') == layoutA:
                    clone = staffLayout.cloneNode(True)
                    clone.setAttribute('description', layoutA + '_a')
                    staffLayout.parentNode.insertBefore(clone, staffLayout)
                    staffLayout.setAttribute('description', layoutA + '_b')
            # Alle betroffenen Notenzeilen umbenennen fuer den Fall, dass nur ein System betroffen ist
            for staff in score.getElementsByTagName('staff'):
                if staff.getAttribute('layout') == layoutA:
                    staff.setAttribute('layout', layoutA + '_a')
                    
        # ---- Layout duplizieren ------
        if layoutAction == 6:
            # Maximale Anzahl Stimmen zählen
            maxVoices = 0
            for staff in score.getElementsByTagName('staff'):
                if staff.getAttribute('layout') == layoutA:
                    voices = staff.getElementsByTagName('voice')
                    maxVoices = max(maxVoices, len(voices))

            # Mustersystem erweitern
            for staffLayout in score.getElementsByTagName('staffLayout'):
                if staffLayout.getAttribute('description') == layoutA:
                    for voiceNum in range(maxVoices):
                        clone = staffLayout.cloneNode(True)
                        clone.setAttribute('description', layoutA + '_' + str(voiceNum+1))
                        staffLayout.parentNode.insertBefore(clone, staffLayout)
                    # Alte Mustersystemeintrag löschen
                    staffLayout.parentNode.removeChild(staffLayout)
                        

        for system in systems:
            
            # --- Notenzeile umbenennen A --> B, wenn B nicht vorhanden ---
            #--------------------------------------------------------------
            if layoutAction == 0:
                if layoutB <> layoutA:
                    if layoutExistsInSystem(system, layoutB):
                        pass
                    else:
                        for staff in system.getElementsByTagName('staff'):
                            if staff.getAttribute('layout') == layoutA:
                                staff.setAttribute('layout', layoutB)

            # --- Notenzeilen austauschen A <--> B ---
            # ----------------------------------------
            elif layoutAction == 1:
                if layoutB <> layoutA:
                    for staff in system.getElementsByTagName('staff'):
                        if staff.getAttribute('layout') == layoutA:
                            staff.setAttribute('layout', layoutB)
                        else:
                            if staff.getAttribute('layout') == layoutB:
                                staff.setAttribute('layout', layoutA)

            # --- Notenzeile A duplizieren ---
            # ---------------------    -------
            elif layoutAction == 2:
                for staff in system.getElementsByTagName('staff'):
                    if staff.getAttribute('layout') == layoutA + '_a' :
                        clone = staff.cloneNode(True)
                        clone.setAttribute('layout', layoutA + '_a')
                        staff.parentNode.insertBefore(clone, staff)  # clone before staff
                        staff.setAttribute('layout', layoutA + '_b')
                            
            # --- Notenzeile kopieren A --> B (sofern Ziellayout B nicht im System vorhanden)---
            # -----------------    -------------------------------------------------------------
            elif layoutAction == 3:
                if layoutB <> layoutA:
                    if layoutExistsInSystem(system, layoutB):
                        pass
                    else:
                        for staff in system.getElementsByTagName('staff'):
                            if staff.getAttribute('layout') == layoutA:
                                clone = staff.cloneNode(True)
                                staff.parentNode.insertBefore(clone, staff)  # clone before staff
                                staff.setAttribute('layout', layoutB)
                                break   # for Schlaufe abbrechen
                            
            # --- Notenzeile A loeschenn ---
            # ------------------------------
            elif layoutAction == 4:
                staffs = system.getElementsByTagName('staff')
                if staffs.length > 1:
                    # Die letzte Notenzeile darf nicht geloescht werden
                    for staff in staffs:
                        if staff.getAttribute('layout') == layoutA:
                            staff.parentNode.removeChild(staff)

            # --- Notenzeile A und B in A zusammenführen ---
            # ---------------------------------------------
            elif layoutAction == 5:
                if layoutB <> layoutA:
                    staffA = staffB = None
                    for staff in system.getElementsByTagName('staff'):
                        if staff.getAttribute('layout') == layoutA:
                            staffA = staff
                        if staff.getAttribute('layout') == layoutB:
                            staffB = staff
                    if staffA and staffB:
                        for voiceA in staffA.getElementsByTagName('voice'):
                            voiceA.setAttribute('stemDir','up')
                        voicesA = staffA.getElementsByTagName('voices')[0]
                        for voiceB in staffB.getElementsByTagName('voice'):
                            voicesA.appendChild(voiceB)
                            voiceB.setAttribute('stemDir','down')
                        staffB.parentNode.removeChild(staffB)
                
            # --- Notenzeile A aufspalten ---
            # -------------------------------
            elif layoutAction == 6:
                for staff in system.getElementsByTagName('staff'):
                    if staff.getAttribute('layout') == layoutA:
                        count = 0
                        for voice in staff.getElementsByTagName('voice'):
                            clone = staff.cloneNode(True)
                            clone.setAttribute('layout', layoutA + '_' + str(count + 1))
                            staff.parentNode.insertBefore(clone, staff)  # clone before staff
                            
                            # nicht benötigte Stimmen löschen
                            count1 = 0
                            for v in clone.getElementsByTagName('voice'):
                                if count <> count1:
                                    v.parentNode.removeChild(v)
                                else:
                                    if v.hasAttribute('stemDir'):
                                        # Halsrichtung auf automatisch
                                        v.removeAttribute('stemDir')
                                count1 += 1
                            count += 1
                        staff.parentNode.removeChild(staff)
                
            else:
                # layoutAction nicht definiert
                pass
                

# Hauptprogramm:

from caplib.capDOM import ScoreChange
import tempfile

class staffEdit(ScoreChange):
    def changeScore(self, score):
        changeDoc(score)

if activeScore():
    activeScore().registerUndo("Staff Editor")
    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)
    
    staffEdit(tempInput, tempOutput)

    activeScore().read(tempOutput)
    os.remove(tempInput)
    os.remove(tempOutput)
