# -*- coding: ISO-8859-1 -*-
""" capellaScript -- 12.11.2004 Andreas Herzog
>>> Suchen und Ersetzen

    Das Skript bietet eine Suchen und Ersetzen-Funktion für Textfelder.|
    |
    ACHTUNG: Die UNDO-Funktion der Pythonschnittstelle erfasst leider Textfelder nicht korrekt. Einmal per Skript gemachte Änderungen an Textfeldern können deshalb nicht rückgängig gemacht werden.
    |
    Version 1.0a    |
    
    |
    

        |

<<<


"""

import xml.dom
import string
from xml.dom.minidom import NodeList

# Version 1.0: Ursprungsversion
# Version 1.0a: Fehlerkorrektur

# doc = [] # parentNode von score

Dateien = []
DateienShown = []
Umlaute = [['\\\'e4','ä'],['\\\'fc','ü'],['\\\'f6','ö'],['\\\'c4','Ä'],['\\\'d6','Ö'],['\\\'dc','Ü'],['\\\'df','ß']]

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 Test(text):
	messageBox('Test',str(text))
    
def getDialogValues():

	global SuchenText, ErsetzenText,caseSensitive, textfelderChange, einfachTextChange, lyricChange
	
	SuchenTextEdit = Edit('',width= 20)
	ErsetzenTextEdit = Edit('',width= 20)
	SuchenTextLabel = Label('Suchen:  ', width = 6)
	ErsetzenTextLabel = Label('Ersetzen: ', width = 6)
	caseSensitiveCheck = CheckBox('Klein/Großschreibung beachten', value=1)
	textfelderChangeCheck = CheckBox('Textfelder durchsuchen', value=1)
	einfachTextChangeCheck = CheckBox('Einfachtext durchsuchen', value=1)
	lyricChangeCheck = CheckBox('Liedtext durchsuchen', value=1)
	
	
	hbox1 = HBox([SuchenTextLabel,SuchenTextEdit], padding= 4)
	hbox2 = HBox([ErsetzenTextLabel,ErsetzenTextEdit], padding= 4)


	vbox  = VBox([hbox1,hbox2, caseSensitiveCheck,textfelderChangeCheck,einfachTextChangeCheck, lyricChangeCheck], text='', padding=4)
	dlg = Dialog('Suchen und Ersetzen: ', vbox)

	if dlg.run():
		SuchenText = SuchenTextEdit.value()
		ErsetzenText = ErsetzenTextEdit.value()
		caseSensitive = caseSensitiveCheck.value()
		textfelderChange = textfelderChangeCheck.value()
		einfachTextChange = einfachTextChangeCheck.value()
		lyricChange = lyricChangeCheck.value()

		return True
	else:
		return False


def getCursor():
    sel = curSelection()
    result = None
    if sel == 0:
        messageBox('Fehler', 'keine aktive Partitur')
        return result
    result = sel[0]
    return result
                        

def isItFormat(text):
	if len(text) > 1:
		if text[0] == '\\' or text=='':
			return True
		else:
			return False
	else:
		return False

def replaceText(text,search, replace):
	i = 0
	if len(search) > 0:
		while i + len(search) <= len(text):
			
			if (text[i:i+len(search)] == search) or ((text[i:i+len(search)].upper() == search.upper()) and (caseSensitive == 0)):
				text = text[:i] + replace + text[(i+len(search)):] 
				i = i+len(search)
			else:
				i+=1
		
	return text
	
	

def replaceInRichtText(content):

	
	
	global SuchenText, ErsetzenText
	
	start = content.find((chr(92)+'pard'))
	end = content.rfind((chr(92)+'par'))
	
	paragraphs = content[start:end]


	parts = []
	
	i=0
	while i < len(paragraphs):
		if paragraphs[i] in [chr(92),' ', chr(13)]:
			#Test(paragraphs)
			a = paragraphs[i+1:].find(chr(92))
			b = paragraphs[i+1:].find(' ')
			c = paragraphs[i+1:].find(chr(13))
			
			if a == -1: 
				a = 1000000
			if b == -1: 
				b = 1000000		
			if c == -1: 
				c = 1000000					
			z = min (a,b,c)
			if z <> 1000000:
				part = paragraphs[i] + paragraphs[i+1:z+1]
				parts +=  [part]
				paragraphs = paragraphs[z+1:]
				i=-1
		i+=1
	parts += [paragraphs]							# Anhängen des Restes	
	
	#Test(parts)	
	j =0											# Dekodiert Umlaute um
	while j < len(parts):
		parts[j] = UmlauteEncode(parts[j])
		j+=1

	gefunden = 0									# Verbindet einzelne Textstücke
	while gefunden == 0:
		gefunden = 1
		j=0 											
		while j < len(parts):
			if j+1 < len(parts):
				if not isItFormat(parts[j]) and not isItFormat(parts[j+1]):
					parts[j] = parts[j]+parts[j+1]
					parts.remove(parts[j+1])
					gefunden = 0
			j+=1

	j=0
	while j < len(parts):
		if textfelderChange == 1:
			parts[j] = replaceText(parts[j],SuchenText,ErsetzenText)
		j+=1
	j =0											# Dekodiert Umlaute zurück
	while j < len(parts):
		parts[j] = UmlauteDecode(parts[j])
		j+=1
					
	k=0
	paragraphs2 = ''
	while k < len(parts):
		paragraphs2 += parts[k]
		k+=1

	content = content[0:start] + paragraphs2 + content[end:]
	
	return content



	

def changeDoc1(score):
	global Dateien, DateienShown

	chords = score.getElementsByTagName('chord')
	
	for pageObjects in score.getElementsByTagName('pageObjects'):
		for drawObj in pageObjects.getElementsByTagName('drawObj'):

			basicFound = False
			for basic in drawObj.getElementsByTagName('basic'):
				basicFound = True
				if basic.hasAttribute('firstPage'):
					firstPage = basic.getAttribute('firstPage')
				else:
					firstPage = ''
				if basic.hasAttribute('oddPagesExceptFirst'):
					oddPagesExceptFirst = basic.getAttribute('oddPagesExceptFirst')
				else:
					oddPagesExceptFirst = ''					
				if basic.hasAttribute('evenPages'):
					evenPages = basic.getAttribute('evenPages')
				else:
					firstPage = ''					
				DateienShown += [[firstPage,oddPagesExceptFirst,evenPages]]
			if basicFound == False:
				DateienShown += [['','','']]
			
			for richText in drawObj.getElementsByTagName('richText'):
				datei = richText.getAttribute('file')
				x = richText.getAttribute('x')
				y = richText.getAttribute('y')
				Dateien += [str(x)+str(y)]
			
				cloneDrawObj = richText.parentNode.cloneNode(True)
				
					
				drawObjects = addElementNode(chords[0], 'drawObjects')
				chordDrawObj = drawObjects.appendChild(cloneDrawObj)
				pageObjects.removeChild(drawObj)
			for text in drawObj.getElementsByTagName('text'):
				x = text.getAttribute('x')
				y = text.getAttribute('y')
				Dateien += [str(x)+str(y)]
				cloneDrawObj = text.parentNode.cloneNode(True)
			
				drawObjects = addElementNode(chords[0], 'drawObjects')
				chordDrawObj = drawObjects.appendChild(cloneDrawObj)
				pageObjects.removeChild(drawObj)




def changeDoc2(score):
	global SuchenText, ErsetzenText, einfachTextChange

	chords = score.getElementsByTagName('chord')
	
	for drawObjects in score.getElementsByTagName('drawObjects'):
		for text in drawObjects.getElementsByTagName('text'):
			for content in text.getElementsByTagName('content'):
				ObjectContent = latin1_e(content.firstChild.nodeValue)
				content.removeChild(content.firstChild)
				if einfachTextChange == 1:
					ObjectContent = replaceText(ObjectContent,SuchenText,ErsetzenText)
				textNode = doc.createTextNode(latin1_d(ObjectContent))
		        content.appendChild(textNode)
	if lyricChange == 1:
		for lyric in score.getElementsByTagName('lyric'):
			for verse in lyric.getElementsByTagName('verse'):
				try:
					lyricContent = latin1_e(verse.lastChild.nodeValue)
					verse.removeChild(verse.lastChild)
					lyricContent = replaceText(lyricContent,SuchenText,ErsetzenText)
					textNode2 = doc.createTextNode(latin1_d(lyricContent))
					verse.appendChild(textNode2)
				except:
					pass
			
				
				
				
def restoreDoc(score):
	global Dateien
	if  len(Dateien) > 0:
		chords = score.getElementsByTagName('chord')
		
		pageObjects = addElementNode(score,'pageObjects')
		
		for drawObjects in chords[0].getElementsByTagName('drawObjects'):
			for drawObj in drawObjects.getElementsByTagName('drawObj'):
				for richText in drawObj.getElementsByTagName('richText'):
					x = richText.getAttribute('x')
					y = richText.getAttribute('y')
					if (str(x)+str(y)) in Dateien:
						dIndex = Dateien.index((str(x)+str(y)))
						cloneDrawObj = richText.parentNode.cloneNode(True)
						pageObjects.appendChild(cloneDrawObj)
						drawObjects.removeChild(drawObj)
						basic = cloneDrawObj.addNewElementNode('basic')
						basic.setAttribute('firstPage',DateienShown[dIndex][0])	
						basic.setAttribute('oddPagesExceptFirst',DateienShown[dIndex][1])
						basic.setAttribute('evenPages',DateienShown[dIndex][2])
						 
				for text in drawObj.getElementsByTagName('text'):
					x = text.getAttribute('x')
					y = text.getAttribute('y')
					if (str(x)+str(y)) in Dateien:
						dIndex = Dateien.index((str(x)+str(y)))
						cloneDrawObj = text.parentNode.cloneNode(True)
						pageObjects.appendChild(cloneDrawObj)
						drawObjects.removeChild(drawObj)
						basic = addNewElementNode(cloneDrawObj,'basic')
	
						basic.setAttribute('firstPage',DateienShown[dIndex][0])	
						basic.setAttribute('oddPagesExceptFirst',DateienShown[dIndex][1])
						basic.setAttribute('evenPages',DateienShown[dIndex][2])
											
			if drawObjects.getElementsByTagName('drawObj').length == 0:			# Wenn drawObjects keine Elemente mehr enthält, dann löschen  
				drawObjects.parentNode.removeChild(drawObjects)	

				

					

# Hauptprogramm:

from caplib.capDOM import ScoreChange
import tempfile

class ScoreChange(ScoreChange):
	def changeScore(self, score):
		global doc
		doc = score.parentNode  
	   

		changeDoc1(score)
		changeDoc2(score)
		
class ScoreRestore(ScoreChange):
	def changeScore(self, score):
		global doc
		doc = score.parentNode  
	   
		
		restoreDoc(score)        
		
		
def UmlauteEncode(s):
	i= 0
	while i < len(Umlaute):
		s = s.replace(Umlaute[i][0],Umlaute[i][1])
		i+=1
	return s

				
def UmlauteDecode(s):
	i= 0
	while i < len(Umlaute):
		s = s.replace(Umlaute[i][1],Umlaute[i][0])
		i+=1
	return s


if activeScore():
	if getDialogValues():
		doc = activeScore()
		doc.registerUndo("Suchen und Ersetzen")
		tempInput = tempfile.mktemp('.capx')
		tempOutput = tempfile.mktemp('.capx')
		activeScore().write(tempInput)
		ScoreChange(tempInput, tempOutput)
		activeScore().read(tempOutput)
		os.remove(tempInput)
		os.remove(tempOutput)
		
		checkCapVersion(5,1,5)
		
		for note in activeScore().noteObjs():
		    for i in range(note.nDrawObjs()):
		        d = note.drawObj(i)
		        if d['type'] == 'richText': # Textfeld
		            s = d['data']
		           
		            s = replaceInRichtText(s)
	            
		            d['data'] = s
		            note.replaceDrawObj(i, d)
		            
		tempInput = tempfile.mktemp('.capx')
		tempOutput = tempfile.mktemp('.capx')
		activeScore().write(tempInput)
		ScoreRestore(tempInput, tempOutput)
		activeScore().read(tempOutput)
		os.remove(tempInput)
		os.remove(tempOutput)

