# -*- coding: ISO-8859-1 -*-
""" capellaScript -- 27.05.2004 Andreas Herzog
>>> Little Drummer Boy

    Mit diesem Skript kann man Schlagzeugnotation einfacher umsetzen..|
    |
    
    Version 1.1    |
    
    |
    Sofern die Notenköpfe aufgrund der Notenlänge nicht korrekt dargestellt werden können, werden sie durch grafische Objekte ersetzt.

        |

<<<

# 1.1: Ergänzung der Auswahl der zu bearbeitenden Zeile
"""

import xml.dom
import string
from xml.dom.minidom import NodeList

# doc = [] # parentNode von score



def latin1_e(u):
    return u.encode('Latin-1')
def latin1_d(u):
    return u.decode('Latin-1')
    
# neu eingefügt
def addElementNode(el,tagName):
    # add new Node to el if Node "tagName" does not exist
    # otherwise return the existing Node
    global doc
    childs = el.childNodes
    for n in range(childs.length):
        if childs[n].nodeType ==childs[n].ELEMENT_NODE and childs[n].tagName == tagName:
            return childs[n]
    newChild = doc.createElement(tagName)
    el.appendChild(newChild)
    return newChild
    
# neu eingefügt
def addNewElementNode(el,tagName):
    # add new Node with tagName "tagName" to el 
    global doc
    newChild = doc.createElement(tagName)
    el.appendChild(newChild)
    return newChild

    
def getDialogValues():

    global  NoteChoice, HeadChoice, AlterSuppress, Kreuz, BBB, ClefChoice, NoteChoiceNumber, Auswahl

    # Die einfache Vorzeichen:
    rad1 = Radio(['mit Kreuzalteration', 'mit Doppelkreuz','ohne Kreuz-Alteration' ], value=2, padding = 8)
    rad2 = Radio(['mit B-Alteration', 'mit Doppel-B','ohne B-Alteration'], value=2, padding = 8)

    # Doppel-Bs
     
    headNames = ['normal, rund',   'Rhombus',    'Kreuz',      'Dreieck' , 'Quadrat','Ungefüllter Rhombus    ' ,'Kreuz mit Kreis','Ungefülltes Dreieck','Ungefülltes Quadrat']   
    comboHead = ComboBox(headNames, width=16, value=int(0))
    chosenNote = ['A4' , 'B4','C5','D5','E5','F5','G5','A5','B5','C6','D6','E6','F6','G6','A6']
    comboChosenNote = ComboBox(chosenNote, width=20, value=int(9), text='   ')
    rad3 = Radio(['nur Notenzeile mit Cursor', 'Notenzeile mit Cursor in allen Systemen   ','gesamte Partitur'], text='Zu bearbeiten:', padding = 0, value=1)
    lab1 = Label(' ', width = 1)
    lab2 = Label('Kopfform:   ', width = 1)
    checkAlter = CheckBox('Vorzeichen automatisch unterdrücken', value=1)
    hbox1= HBox([comboChosenNote], padding = 16)
    hbox2= HBox([rad1, rad2], padding = 0 )
    hbox3= HBox([lab2,comboHead, lab1], padding = 0)
    vbox1= VBox([hbox1, hbox2,checkAlter], padding = 16,text='Ausgewählte Tonhöhe')
    vbox2= VBox([hbox3], padding = 0,text='')
    checkClef = CheckBox('Schlagzeugschlüssel setzen', value=0)
    vbox3= VBox([vbox1,vbox2,rad3, checkClef], padding = 10 )
    vbox4  = VBox([vbox3], text='', padding=16)
    dlg = Dialog('Kopfform formatieren: ', vbox4)

    if dlg.run():
        Kreuz = rad1.value()
        BBB = rad2.value()
        AlterSuppress = checkAlter.value()
        NoteChoiceNumber = comboChosenNote.value()
        NoteChoice = chosenNote[NoteChoiceNumber]
        HeadChoice = comboHead.value()
        ClefChoice = checkClef.value()
        Auswahl = rad3.value()
        return True
    else:
        return False



def handleNotes(score, voice):
    global NoteChoice, Kreuz, BBB, NoteHight, AlterSuppress, Alterationskennung, Notenkennung, NoteChoiceNumber, NoteLength, NoteSharpOrFlat, NotePosition, HeadChoice, ClefChoice, GraficalTag

    for clefSign in voice.getElementsByTagName('clefSign'):
    	if ClefChoice == 1:
    		clefSign.setAttribute('clef','P3')
    		
    if ((Kreuz == 2) and (BBB == 2)):
    	Alterationskennung = 0
    if (Kreuz == 0):
    	Alterationskennung = 20
    if (Kreuz == 1):
    	Alterationskennung = 40	
    if (BBB == 0):
    	Alterationskennung = 60
    if (BBB == 1):
    	Alterationskennung = 80
    	
    Notenkennung = NoteChoiceNumber + Alterationskennung
    Kennung = '56294-' +  '10' + str(Notenkennung)  
    GraficalTag = Kennung
    # Alle drawObj mit tag == GraficalTag löschen
    for drawObjects in voice.getElementsByTagName('drawObjects'):
        for drawObj in drawObjects.childNodes:
            if drawObj.nodeType == drawObj.ELEMENT_NODE and drawObj.tagName == 'drawObj':
                for basic in drawObj.getElementsByTagName('basic'):
                    if basic.hasAttribute('tag') and basic.getAttribute('tag') == GraficalTag:
                        drawObjects.removeChild(drawObj)
        # Wenn drawObjects keine Elemente mehr enthält, dann löschen                        
        if drawObjects.getElementsByTagName('drawObj').length == 0:
            drawObjects.parentNode.removeChild(drawObjects)

    for chord in voice.getElementsByTagName('chord'):

        duration = chord.getElementsByTagName('duration')[0]
        NoteLength = duration.getAttribute('base')
        
        heads =  chord.getElementsByTagName('head')
        drawObjs = chord.getElementsByTagName('drawObjs')
        
       

        for head in chord.getElementsByTagName('head'):
            # Notenkopfnummer +=1
            if head.getAttribute('pitch') == NoteChoice:
                GraficalHead = 0

                alter = addElementNode(head,'alter')
                if not alter.hasAttribute('step'):
                   alter.setAttribute('step',str('0'))
                 
                alters =  head.getElementsByTagName('alter')
                
                NoteSharpOrFlat = alter.getAttribute('step')
                if (Kreuz == 2 and BBB == 2 and NoteSharpOrFlat == '0') or (Kreuz == 0 and NoteSharpOrFlat == '1') or (Kreuz == 1 and NoteSharpOrFlat == '2') or (BBB == 0 and NoteSharpOrFlat == '-1') or (BBB == 1 and NoteSharpOrFlat == '-2'):       
                    if AlterSuppress == 1:
                        alter.setAttribute('display',str('suppress'))
                    if HeadChoice == 0:
                        if head.hasAttribute('shape'):         # Attribut shape löschen, wenn vorhanden
                            head.removeAttribute('shape')
                    if HeadChoice == 1 and NoteLength in ['1/4','1/8','1/16','1/32','1/64']:
                        head.setAttribute('shape', str('diamond'))
                    if HeadChoice == 1 and NoteLength in ['1/2','1/1']:
                        GraficalHead = 1
                        HeadSymbol = chr(241)
                        NotePosition = '0'
                    if HeadChoice == 2 and NoteLength in ['1/4','1/8','1/16','1/32','1/64']:
                        head.setAttribute('shape', str('crossCircle'))
                    if HeadChoice == 2 and NoteLength in ['1/2','1/1']:
                        GraficalHead = 1
                        HeadSymbol = chr(242)
                        NotePosition = '0'
                    if HeadChoice == 3 and NoteLength in ['1/4','1/8','1/16','1/32','1/64']:
                        head.setAttribute('shape', str('triangle'))
                    if HeadChoice == 3 and NoteLength in ['1/2','1/1']:
                        GraficalHead = 1
                        HeadSymbol = chr(239)
                        NotePosition = '0'
                    if HeadChoice == 4 and NoteLength in ['1/4','1/8','1/16','1/32','1/64']:
                        head.setAttribute('shape', str('square'))
                    if HeadChoice == 4 and NoteLength in ['1/2','1/1']:
                        GraficalHead = 1
                        HeadSymbol = chr(245)
                        NotePosition = '0'	
                    if HeadChoice == 5 and NoteLength in ['1/4','1/8','1/16','1/32','1/64']:
                    	GraficalHead = 1
                    	HeadSymbol = chr(240)
                    	NotePosition = '0'
                    if HeadChoice == 5 and NoteLength in ['1/2','1/1']:
                    	head.setAttribute('shape', str('diamond'))
                    if HeadChoice == 6 and NoteLength in ['1/4','1/8','1/16','1/32','1/64']:
                    	GraficalHead = 1
                    	HeadSymbol = chr(243)
                    	NotePosition = '-0.2'
                    if HeadChoice == 6 and NoteLength in ['1/2','1/1']:
                    	head.setAttribute('shape', str('crossCircle'))
                    if HeadChoice == 7 and NoteLength in ['1/4','1/8','1/16','1/32','1/64']:
                    	GraficalHead = 1
                    	HeadSymbol = chr(238)
                    	NotePosition = '-0.2'
                    if HeadChoice == 7 and NoteLength in ['1/2','1/1']:
                    	head.setAttribute('shape', str('triangle'))
                    if HeadChoice == 8 and NoteLength in ['1/4','1/8','1/16','1/32','1/64']:
                        GraficalHead = 1
                        HeadSymbol = chr(244)
                        NotePosition = '0'
                    if HeadChoice == 8 and NoteLength in ['1/2','1/1']:
                    	head.setAttribute('shape', str('square'))
                    if GraficalHead == 1:
                        head.setAttribute('shape','none')
                        drawObjects = addElementNode(chord,'drawObjects')
                        drawObj = addNewElementNode(drawObjects,'drawObj')
                        text = addElementNode(drawObj,'text')
                        text.setAttribute('x',NotePosition)

                        # Anmerkung: Tag's gehören unter drawObj in basic
                        basic = addElementNode(drawObj,'basic')
                        basic.setAttribute('tag',GraficalTag)
                        
                        font = addNewElementNode(text,'font')
                        font.setAttribute('face','capella3')
                        NoteHeight = '18'
                        font.setAttribute('height',NoteHeight)
                        font.setAttribute('charSet','2')
                        font.setAttribute('pitchAndFamily','2')
                        content = addNewElementNode(text,'content')
                        textNode = doc.createTextNode(latin1_d(HeadSymbol))
                        content.appendChild(textNode)
                        if head.getAttribute('pitch') == 'B4':
                        	NoteHight = '4'
                        if head.getAttribute('pitch') == 'B4':
                        	NoteHight = '3.5'
                        if head.getAttribute('pitch') == 'C5':
                        	NoteHight = '3'                    
                        if head.getAttribute('pitch') == 'D5':
                        	NoteHight = '2.5'
                        if head.getAttribute('pitch') == 'E5':
                        	NoteHight = '2'
                        if head.getAttribute('pitch') == 'F5':
                        	NoteHight = '1.5'                                       
                        if head.getAttribute('pitch') == 'G5':
                        	NoteHight = '1'                   
                        if head.getAttribute('pitch') == 'A5':
                        	NoteHight = '0.5'                   					
                        if head.getAttribute('pitch') == 'B5':
                        	NoteHight = '0'                    
                        if head.getAttribute('pitch') == 'C6':
                        	NoteHight = '-0.5'
                        if head.getAttribute('pitch') == 'D6':
                            NoteHight = '-1'
                        if head.getAttribute('pitch') == 'E6':
                            NoteHight = '-1.5'
                        if head.getAttribute('pitch') == 'F6':
                            NoteHight = '-2'
                        if head.getAttribute('pitch') == 'G6':
                            NoteHight = '-2.5'	            	
                        if head.getAttribute('pitch') == 'A6':
                            NoteHight = '-3'	            
                        text.setAttribute('y',NoteHight)
                    
def getCursor():
    sel = curSelection()
    result = None
    if sel == 0:
        messageBox('Fehler', 'keine aktive Partitur')
        return result
    result = sel[0]
    return result
                        

def changeDoc(score):
    
    if getDialogValues():
	    		if Auswahl == 0:												# Nur die Markierte Zeile 
		        	sel = getCursor()
		    		if sel == None:
		        		return
		    		else:
		        		system = score.getElementsByTagName('system')[sel[0]]
		        		staff = system.getElementsByTagName('staff')[sel[1]]
		        		voice = staff.getElementsByTagName('voice')[sel[2]]
		        		handleNotes(score, voice)
		        					
	    		if Auswahl == 1:												# Nur die Markierte Zeile, allerdings über die gesamte Partitur
		        	sel = getCursor()
		    		if sel == None:
		        		return
		    		else:
		        		system = score.getElementsByTagName('system')[sel[0]]
		        		staff = system.getElementsByTagName('staff')[sel[1]]
		        		actLayout = staff.getAttribute('layout')
		        		for staff in score.getElementsByTagName('staff'):
        					if staff.getAttribute('layout') == actLayout:
		        				for voice in staff.getElementsByTagName('voice'):
		        					handleNotes(score, voice)
		        		
		        				
	    		if Auswahl == 2:
	    			for voice in score.getElementsByTagName('voice'):			# Gesamte Partitur bearbeiten
	    				handleNotes(score, voice)

# 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("Schlagzeug-Notation")
	tempInput = tempfile.mktemp('.capx')
	tempOutput = tempfile.mktemp('.capx')
	activeScore().write(tempInput)
	ScoreChange(tempInput, tempOutput)
	activeScore().read(tempOutput)
	os.remove(tempInput)
	os.remove(tempOutput)
