# -*- coding: ISO-8859-1 -*-
""" capellaScript -- 11.12.2004 Andreas Herzog
>>> VoiceSplit


    Version 1.0
    
    |
    

        |

<<<

# 1.0: Ursprungsversion

"""
import new
from xml.dom.minidom import Node, Element
import xml.dom
import string
from xml.dom.minidom import NodeList

Toene = [['C-','--','Ds'],['C#','--','Db'],['D-','Cx','Es'],['D#','Fs','Eb'],['E-','Dx','Fb'],['F-','E#','Gs'],['F#','Ex','Gb'],['G-','Fx','As'],['G#','---','Ab'],['A-','Gx','Bs'],['A#','--','Bb'],['B-','Ax','--']]

justStaffs = []
justVoices = []
clefs = ['treble','alto','tenor','bass']

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 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


options = ScriptOptions() 
opt = options.get()

def Test(text):
	messageBox('Test',str(text))

class settings:
    def __init__(self):
    	self.clefChosen = 4
    	self.splitPointA = 0
    	self.splitPointB = 5


def getOptions():
	global clefChosen, splitPointA, splitPointB
        
	clefChosen = eval(opt.get('clefChosen',str(clefChosen)))
	splitPointA	= eval(opt.get('splitPointA',str(splitPointA)))
	splitPointB	= eval(opt.get('splitPointB',str(splitPointB)))
	

	
def setOptions():
    global dlgSet

    opt.update(dict(clefChosen= str(clefChosen),
	   				splitPointA = str(splitPointA),
	   				splitPointB = str(splitPointB)		
                   ))
                

    options.set(opt)
    
def getDialogValues2(voiceNames):

    global  allLayouts, Auswahl, splitPoint, selectedSplitStimmeVoice, selectedOriginalVoice, selectedSplitStimmeStaff, selectedOriginalStaff, Stimmenzahl,selectedVoices,clefChosen
    global splitPointA, splitPointB

    
    
    layoutList = [ latin1_e(allLayouts[i].getAttribute('description')) for i in range(allLayouts.length ) ]
    
    
    selLayoutCombo1 = ComboBox(voiceNames, value = 0, width=32)
    selLayoutCombo2a = ComboBox(voiceNames, value = 1, width=32)
    selLayoutCombo2b = ComboBox(['Violinschlüssel','Altschlüssel','Tenorschlüssel','Bassschlüssel','unverändert'], value = clefChosen, width=32)
    
    
    ToeneAnzeige = []
    i = 0
    while i < len(Toene):
    	
    	ToeneAnzeige += [Toene[i][0] + ' ' + Toene[i][1] + ' ' + Toene[i][2]]
    	i +=1
    	
    selSplitCombo1 = ComboBox(ToeneAnzeige, value = splitPointA, width=9)
    selSplitCombo2 = ComboBox(['0','1','2','3','4','5','6','7','8'], value = splitPointB, width=5)

    lab1 = Label('Ursprungsstimme:', width = 5) 
    lab2 = Label('Splitstimme:   ', width = 5) 
    lab3 = Label('Splitpunkt:   ', width = 5) 

    lableer = Label(' ', width = 1) 
    labErklaerung1 = Label('Zeichenerklärung:', width = 1) 
    labErklaerung2 = Label('# = einfach hochalteriert', width = 1) 
    labErklaerung3 = Label('x = doppelt hochalteriert', width = 1) 
    labErklaerung4 = Label('b = einfach tielalteriert', width = 1) 
    labErklaerung5 = Label('s = doppelt tiefalteriert', width = 1) 



    hBox1 = HBox([lab1, selLayoutCombo1], text='', padding=12)
    hBox2 = HBox([lab2, selLayoutCombo2a,selLayoutCombo2b], text='', padding=12)
    hBox3 = HBox([lab3, selSplitCombo1, selSplitCombo2], text='', padding=12)

    vboxErklaerung  = VBox([labErklaerung1,labErklaerung2,labErklaerung3,labErklaerung4,labErklaerung5], text='', padding=0)
    vbox1  = VBox([hBox1,hBox2, hBox3,vboxErklaerung], text='', padding=12)
    vbox2  = VBox([vbox1,lableer], text='', padding=12)
    
    dlg = Dialog('Bitte wählen: ', vbox2)

    if dlg.run() and Stimmenzahl>=1:
        selectedOriginalVoice = latin1_d(justVoices[selLayoutCombo1.value()])
        selectedOriginalStaff = latin1_d(justStaffs[selLayoutCombo1.value()])        
        selectedSplitStimmeVoice = latin1_d(justVoices[selLayoutCombo2a.value()])
        selectedSplitStimmeStaff = latin1_d(justStaffs[selLayoutCombo2a.value()])
        splitPointA= selSplitCombo1.value()
        splitPointB= selSplitCombo2.value()
        splitPoint = str(Toene[splitPointA][0]) + str(splitPointB)
        clefChosen = selLayoutCombo2b.value()

           
        selectedVoices = [voiceNames[selLayoutCombo1.value()],voiceNames[selLayoutCombo2a.value()]]
        return True
    else:
        return False

def setKey(voice):
	global clefChosen
	if clefChosen < 4:
		for clefSign in voice.getElementsByTagName('clefSign'):
			clefSign.setAttribute('clef',clefs[clefChosen])

def getCursor():
    sel = curSelection()
    result = None
    if sel == 0:
        messageBox('Fehler', 'keine aktive Partitur')
        return result
    result = sel[0]
    return result
                        
def getVoiceNames(score):
    global Stimmenzahl
    
    layouts = []
    
    Stimmenzahl = 0
    for staff in score.getElementsByTagName('staff'):
        layout = staff.getAttribute('layout')
        for n in range(staff.getElementsByTagName('voice').length):
            nplus = n+1
            justStaff = latin1_e(layout)
            justVoice = latin1_e(' %02d' % n)
            voiceName = latin1_e(layout+(' %02d' % nplus)+'.Stimme')
            if voiceName not in layouts:
                layouts.append(voiceName)
                justStaffs.append(justStaff)
                justVoices.append(justVoice)
                Stimmenzahl = Stimmenzahl + 1
    #layouts.sort()
    return layouts
    
    
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 Test(text):
	messageBox('Test',str(text))

def getHightInOctave(pitch):
	i=0
	while i < len(Toene):
		if pitch[0:2] == Toene[i][0] or pitch[0:2] == Toene[i][1] or pitch[0:2] == Toene[i][2]:
			break
		i+=1
	return i

def compareHead(head, splitPoint, upDown):
	
	
	alteration = '-'
	for alter in head.getElementsByTagName('alter'):
		if alter.getAttribute('step') == 1:
			alteration = '#'
		if alter.getAttribute('step') == 2:
			alteration = 'x'
		if alter.getAttribute('step') == -1:
			alteration = 'b'	
		if alter.getAttribute('step') == -2:
			alteration = 'x'										
	pitch = head.getAttribute('pitch')[0] + alteration + head.getAttribute('pitch')[1]
	
		
	if pitch[2] < splitPoint[2]:
		result =  True
	elif pitch[2] > splitPoint[2]:
		result =  False
	else:	
		if getHightInOctave(pitch) < getHightInOctave(splitPoint):
			result =  True
		else:
			result =  False
	if upDown == 0:
		if result == True:
			result = False
		else:
			result = True
	
	return result

def cleanNote(voice, upDown):
	global splitPoint
	for chord in voice.getElementsByTagName('chord'):
		for head in chord.getElementsByTagName('head'):
			if compareHead(head, splitPoint, upDown):
				head.parentNode.removeChild(head)
			if len(chord.getElementsByTagName('head')) == 0:
				rest = addNewElementNode(chord.parentNode, 'rest')
				duration = chord.getElementsByTagName('duration')[0].cloneNode(True)
				rest.appendChild(duration)	
				chord.parentNode.insertBefore(rest, chord)
				chord.parentNode.removeChild(chord)
    
def changeDoc(score):
	global  allLayouts, selectedTenorVoice, selectedBassVoice, selectedTenorStaff, selectedBassStaff, selectedOriginalVoice, selectedOriginalStaff,  selectedSplitStimmeVoice, selectedSplitStimmeStaff, stimme, Stimmenzahl, clefChosen
	global splitPointA, splitPointB
	
	clefChosen = 4
	splitPointA = 0
	splitPointB = 5
	
	voiceNames = getVoiceNames(score)
	allLayouts = getAllLayouts(score)
	staffLayouts = score.getElementsByTagName('staffLayout')
	
	systems = score.getElementsByTagName('system')
	staffs = score.getElementsByTagName('staff')

	getOptions()
	if getDialogValues2(voiceNames):
		setOptions()

		for system in systems:
			staves = system.getElementsByTagName('staves')
			for staff in system.getElementsByTagName('staff'): 			# Clone und Bearbeiten der ausgewählten Zeilen
				descr = staff.getAttribute('layout')					# 
				if descr == selectedOriginalStaff:						# 
					j=0
					for voice in staff.getElementsByTagName('voice'):
						if j == string.atoi(selectedOriginalVoice):
							clone1 = voice.cloneNode(1)
							cleanNote(voice,1)
							cleanNote(clone1,0)
							setKey(clone1)
							
						j+=1
			
								
			for staff in system.getElementsByTagName('staff'): 			# Einfügen der Zeilen
				descr = staff.getAttribute('layout')			
				if descr == selectedSplitStimmeStaff:				
					j=0
					for voice in staff.getElementsByTagName('voice'):
						if j == string.atoi(selectedSplitStimmeVoice):
							voice.parentNode.insertBefore(clone1,voice)	
							voice.parentNode.removeChild(voice)
							
						j+=1					
			
	    		
	    	
# 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("Stimmen trennen")
	tempInput = tempfile.mktemp('.capx')
	tempOutput = tempfile.mktemp('.capx')
	activeScore().write(tempInput)
	ScoreChange(tempInput, tempOutput)
	activeScore().read(tempOutput)
	os.remove(tempInput)
	os.remove(tempOutput)

