# -*- coding: ISO-8859-1 -*-
""" capellaScript -- 10.04.2004 Paul Villiger
>>> Partiturverzeichnis

    Dieses Skript erstellt ein Partiturverzeichnis im HTML-Format aller CAP-Dateien in einem Ordner. 
<<<

    Die folgenden Einträge werden aus der Capelladatei gelesen:
    
    Titel:
      Einfachtext an der Seite oder an der ersten Notenzeile verankert
      und grösser als 12pt. Wird kein Titel gefunden, so wird der Dateiname verwendet.
    Komponist/Herkunft:
      Einfachtext, welcher am meisten rechts steht.
      Der Text muss an der Seite oder an der ersten Notenzeile verankert
      sein und über der ersten Notenzeile liegen.
    Notenzeilen:
      Die Namen aller Notenzeilen aus dem Mustersystem, welche in
      der Partitur verwendet werden.
    Stimmen:
      Die Summe der maximalen Anzahl Notenköpfe der einzelnen Notenzeilen.
      Es wird nur das erste System ausgewertet. (Die Angaben müssen nicht stimmen).
    Tonart:
      Alle Tonarten des ersten Systems
    
    Bemerkungen:
    - Bei Partituren, welche nicht korrekt gelesen werden können,
      wird ein Himweis auf CAPX-Fehler ausgegeben. Meist ist das
      Zeichen "&" im Text enthalten.
    - Im Filedialog wird die Cap-Datei $$XX.cap vorgeschlagen. Dieser Dateiname
      wird nicht verwendet, sondern nur das Verzeichnis.

History: 10.04.04 - Erstausgabe
         01.05.04 - Ausgabe der Tonart

"""

from caplib.capDOM import ScoreChange
import tempfile, os

titleList = []

def latin1_e(u):
    return u.encode('Latin-1')
def latin1_d(u):
    return u.decode('Latin-1')

def getTopDist(score):
    topDist = 0
    layout = score.getElementsByTagName('layout')[0]
    systems = layout.getElementsByTagName('systems')[0]
    topDist = topDist + eval(systems.getAttribute('top'))

    staves =  layout.getElementsByTagName('staves')[0]
    distances = staves.getElementsByTagName('distances')[0]
    topDist = topDist + eval(distances.getAttribute('top'))

    staff = score.getElementsByTagName('staff')[0]
    for extraDistance in staff.getElementsByTagName('extraDistance'):
        if extraDistance.hasAttribute('top'):
            topDist = topDist + eval(extraDistance.getAttribute('top'))
        break
    return topDist

def getStaveNames(score):
    layoutCount = dict()
    for staffLayout in score.getElementsByTagName('staffLayout'):
        layoutCount[staffLayout.getAttribute('description')] = [0,0]

    for system in score.getElementsByTagName('system'):
        for staff in system.getElementsByTagName('staff'):
            layoutCount[staff.getAttribute('layout')][0] += 1
            
            # Max. Anzahl Notenköpfe pro Stimme ermitteln
            heads = 0
            for voice in staff.getElementsByTagName('voice'):
                chordCount = 0
                headSum = 0
                for chord in voice.getElementsByTagName('chord'):
                    headSum = headSum + chord.getElementsByTagName('head').length
                    chordCount += 1
                if chordCount > 0:
                    heads = heads + int(round(headSum / float(chordCount)))
            layoutCount[staff.getAttribute('layout')][1] = heads
        break # nur erstes System durchsuchen
            
    return layoutCount

def getKeys(score):
    Dur = ['Ces-Dur','Ges-Dur', 'Des-Dur','As-Dur','Es-Dur','B-Dur','F-Dur',
           'C-Dur','G-Dur','D-Dur','A-Dur','E-Dur','H-Dur','Fis-Dur','Cis-Dur' ]
    
    keySigns = []
    
    system = score.getElementsByTagName('system')[0]
    for voice in system.getElementsByTagName('voice'):
        keys = voice.getElementsByTagName('keySign')
        if keys.length == 0:
            fifths = '0'
        else:
            fifths = keys[0].getAttribute('fifths')
        keyText = Dur[eval(fifths) + 7]
        if keyText not in keySigns:
            keySigns.append(keyText)
            
    return keySigns



def changeDoc(score):
    global capFile
    topDist = getTopDist(score)
    title, composer = '',''

    # Pageobjekt nach Titel und Komponist durchsuchen    
    for pageObject in score.getElementsByTagName('pageObjects'):
        composerX = 0.0
        for text in pageObject.getElementsByTagName('text'):
            basics = text.parentNode.getElementsByTagName('basic')
            if basics.length > 0 and basics[0].hasAttribute('firstPage') and basics[0].getAttribute('firstPage') == 'false':
                continue
            if eval(text.getAttribute('y')) > topDist - 3:
                continue
            for font in text.getElementsByTagName('font'):
                if font.hasAttribute('height'):
                    fontHeight = eval(font.getAttribute('height'))
                    fontFace = font.getAttribute('face')
                    if 'capella' in fontFace:
                        break
                    if  fontHeight > 12 and title == '':
                        for content in text.getElementsByTagName('content'):
                            if content.firstChild:
                                title = latin1_e(content.firstChild.nodeValue)
                                if title.isdigit():
                                    title = ''
                                else:
                                    break
                    if 12 >= fontHeight >= 7:
                        if text.hasAttribute('x') and float(text.getAttribute('x')) > composerX:
                            for content in text.getElementsByTagName('content'):
                                if content.firstChild:
                                    c = latin1_e(content.firstChild.nodeValue)
                                    if c.isdigit():
                                        pass
                                    else:
                                        composer = c
                                        composerX = float(text.getAttribute('x'))
                                        break

    # 1ste Notenzeile nach Titel und Komponist durchsuchen    
    for staff in score.getElementsByTagName('staff'):
        for voice in staff.getElementsByTagName('voice'):
            for text in voice.getElementsByTagName('text')[::-1]:  # hinten beginnen
                if eval(text.getAttribute('y')) >  -5:
                    continue
                for font in text.getElementsByTagName('font'):
                    if font.hasAttribute('height'):
                        fontFace = font.getAttribute('face')
                        if 'capella' in fontFace:
                            break
                        fontHeight = eval(font.getAttribute('height'))
                        if  fontHeight > 12 and title == '':
                            for content in text.getElementsByTagName('content'):
                                if content.firstChild:
                                    title = latin1_e(content.firstChild.nodeValue)
                                    if title.isdigit():
                                        title = ''
                                    else:
                                        break
                        if 12 >= fontHeight >= 7 and composer == '':
                            for content in text.getElementsByTagName('content'):
                                if content.firstChild:
                                    composer = latin1_e(content.firstChild.nodeValue)
                                    if composer.isdigit():
                                        composer = ''
                                    else:
                                        break
        break # nur erste Notenzeile durchsuchen

    staveNames = getStaveNames(score)    
    composer = composer.replace(chr(10),'<br>')
    keySigns = getKeys(score)
    titleList.append( (capFile,title,composer, staveNames, keySigns) )



class ScoreChange(ScoreChange):
    def changeScore(self, score):
        changeDoc(score)

dlg = FileDialog()
dlg.__init__(bOpen=False)
dlg.setTitle('Bitte Ordner auswählen')
dlg.addFilter('capella-Dateien', '*.cap;*.capx')
dlg.setStartFile('$$XX.cap')

if dlg.run():
    capFile=dlg.filePath()
    capDir, capName = os.path.split(capFile)
else:
    capDir = 'C:\\temp'


dirlist = os.listdir(capDir)
dirlist.sort()
for capFile in dirlist:
    head, tail = os.path.splitext(capFile)
    if os.path.isdir(os.path.join(capDir,capFile)):
        titleList.append( (capFile,'<i>'+capFile+'</i>','',dict( {' ':[0,0]} ),[] ) )

for capFile in dirlist:
    head, tail = os.path.splitext(capFile)
#    if 'Alpen' not in capFile:
#        continue
    if tail.lower() <> '.cap':
        continue
    
    if not os.path.isfile(os.path.join(capDir,capFile)):
        continue

    openScore(os.path.join(capDir,capFile))

    tempInput = tempfile.mktemp('.capx')
    tempOutput = tempfile.mktemp('.capx')
    activeScore().write(tempInput)
    
    try:
        ScoreChange(tempInput, tempOutput)
        
        os.remove(tempInput)
        os.remove(tempOutput)
    except:
        titleList.append( (capFile,'','CAPX Fehler',dict( {' ':[0,0]} ),[] ) )
    
    closeActiveScore()

outFile = file(os.path.join(capDir,'Partiturverzeichnis.html'),'w')
outFile.write('<html><head><title>Partiturverzeichnis '+capDir+'</title></head><body><table border>\n')
outFile.write('<tr><th>Titel</th><th>Komponist / Herkunft</th><th>Notenzeilen /<br>Stimmen</th><th>Tonart<br>(nur Dur)</th></tr>')
for capFile, title, composer, staveNames, keySigns in titleList:
    if title == '':
        title=capFile
    outFile.write('<tr valign="top">')
    outFile.write('<td><a href="' + capFile + '">'+ title +'</a></td>')
    if composer == '':
        composer = '&nbsp;'
    outFile.write('<td>' + composer + '</td>')
    outFile.write('<td>')
    s = staveNames.keys()
    #s.sort()
    firstLine = True
    for k in s:
        if staveNames[k][0] == 0:
            continue
        if firstLine:
            firstLine = False
        else:
            outFile.write('<br>')
        outFile.write(latin1_e(k) + ' / '+str(staveNames[k][1]))
    outFile.write('&nbsp;</td><td>')
    if len(keySigns) > 0:
        outFile.write(keySigns[0])
        for k in keySigns[1:]:
            outFile.write('<br>' + k)
    else:
        outFile.write('&nbsp;')
    outFile.write('</td></tr>\n')

outFile.write('</table></body></html>\n')
outFile.flush()
outFile.close()    
