# -*- coding: ISO-8859-1 -*-
""" capellaScript -- Layout Kopieren
>>>
Mit diesem Skript kann das Layout einer Partitur oder Teile davon in die aktuelle Partitur kopiert werden.
Was kopiert werden soll wird im Dialog abgefragt.
    
<<<

History:  21.03.2009 - Betaversion
          23.03.2009 - Mustersystem kopieren
          28.03.2009 - Remove extra Distance
          31.03.2009 - capXML Templates
                     - Limit Brackets to range of staffs
          07.05.2009 - leere Einträge in Mustersystem löschen
          
Rückmeldungen bitte an villpaul(a)bluewin.ch

"""

german = ("de", {
    'what'                  :   '--- Was soll kopiert werden? ---',
    'regUndo'               :   'Layout Kopieren',
    'dlgPages'              :   'Seitenränder',
    'dlgDistances'          :   'Abstand erstes/zwischen System',
    'dlgStyle'              :   'Brevisstyle',
    'dlgBeamFlattening'     :   'Balkensteigung',
    'dlgSpacing'            :   'Notenausrichtung',
    'dlgInstrumentNames'    :   'Instrumentennamen Schrift',
    'dlgInfo'               :   'Partiturinfo',
    'dlgBarCount'           :   'Taktnummerierung',
    'dlgPageObjects'        :   'Pageobjekte',
    'dlgDeletePageObjects'  :   'Alte Pageobjekte löschen',
    'dlgLyricsSettings'     :   'Liedtextformatierung',
    'dlgSystemAttributes'   :   'Systemattribute (Randausgleich, -abstand, Tempo)',
    'dlgStaffLayout'        :   'Mustersystem && Klammern',
    'dlgRemoveExtraDist'    :   'Zusätzliche Zeilenabstände entfernen (nach capella-scan) ',
    'selTemplate'           :   'Capella Template-Datei auswählen',
    'capFile'               :   'Capella-Datei',
    'capxFile'               :  'capXML-Datei',
    'allFile'               :   'Alle capella Dateien'
    })


try:
    exec('from %s import translations' % ( translationModule() ))
    translations.append(german)
    setLanguages(translations)
except:
    def tr(s):
        return german[1].get(s, "???")
#-------------------------------------------------------------------

import new, os.path
from xml.dom.minidom import NodeList, Node, Element

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 getChildNodes(currentNode):
    childs = currentNode.childNodes
    newList = []
    for c in childs:
        if c.nodeType == c.ELEMENT_NODE:
            newList.append(c)
    return newList

class layoutCollector(Node):

    def __init__(self):
        options = ScriptOptions() 
        opt = options.get()

        self.copyPages = eval(opt.get('copyPages','1'))
        self.copyDistances = eval(opt.get('copyDistances','1'))
        self.copyStyle = eval(opt.get('copyStyle','1'))
        self.copyBeamFlattening = eval(opt.get('copyBeamFlattening','1'))
        self.copySpacing = eval(opt.get('copySpacing','1'))
        self.copyInstrumentNames = eval(opt.get('copyInstrumentNames','1'))
        self.copyInfo = eval(opt.get('copyInfo','1'))
        self.copyBarCount = eval(opt.get('copyBarCount','1'))
        self.copyPageObjects = eval(opt.get('copyPageObjects','1'))
        self.deletePageObjects = eval(opt.get('deletePageObjects','0'))
        self.copyLyricsSettings = eval(opt.get('copyLyricsSettings','1'))
        self.copySystemAttributes = eval(opt.get('copySystemAttributes','1'))
        self.removeExtraDist = eval(opt.get('removeExtraDist','1'))
        self.copyStaffLayout = eval(opt.get('copyStaffLayout','1'))

        self.ok = True

        self.getDialogValues()

        if self.ok:
            opt['copyPages']                 =  self.copyPages            
            opt['copyDistances']             =  self.copyDistances        
            opt['copyStyle']                 =  self.copyStyle            
            opt['copyBeamFlattening']        =  self.copyBeamFlattening   
            opt['copySpacing']               =  self.copySpacing          
            opt['copyInstrumentNames']       =  self.copyInstrumentNames  
            opt['copyInfo']                  =  self.copyInfo             
            opt['copyBarCount']              =  self.copyBarCount         
            opt['copyPageObjects']           =  self.copyPageObjects      
            opt['deletePageObjects']         =  self.deletePageObjects    
            opt['copyLyricsSettings']        =  self.copyLyricsSettings   
            opt['copySystemAttributes']      =  self.copySystemAttributes
            opt['removeExtraDist']           =  self.removeExtraDist
            opt['copyStaffLayout']           =  self.copyStaffLayout
            options.set(opt)                                         



    def getDialogValues(self):
        dlgPages            = CheckBox(tr('dlgPages'), value = self.copyPages)
        dlgDistances        = CheckBox(tr('dlgDistances'), value = self.copyDistances)
        dlgStyle            = CheckBox(tr('dlgStyle'), value = self.copyStyle)
        dlgBeamFlattening   = CheckBox(tr('dlgBeamFlattening'), value = self.copyBeamFlattening)
        dlgSpacing          = CheckBox(tr('dlgSpacing'), value = self.copySpacing)
        dlgInstrumentNames  = CheckBox(tr('dlgInstrumentNames'), value = self.copyInstrumentNames)
        dlgInfo             = CheckBox(tr('dlgInfo'), value = self.copyInfo)
        dlgBarCount         = CheckBox(tr('dlgBarCount'), value = self.copyBarCount)
        dlgPageObjects      = CheckBox(tr('dlgPageObjects'), value = self.copyPageObjects)
        dlgDeletePageObjects= CheckBox(tr('dlgDeletePageObjects'), value = self.deletePageObjects)
        dlgLyricsSettings   = CheckBox(tr('dlgLyricsSettings'), value = self.copyLyricsSettings)
        dlgSystemAttributes = CheckBox(tr('dlgSystemAttributes'), value = self.copySystemAttributes)
        dlgRemoveExtraDist  = CheckBox(tr('dlgRemoveExtraDist'), value = self.removeExtraDist)
        dlgStaffLayout      = CheckBox(tr('dlgStaffLayout'), value = self.copyStaffLayout)
        
                                       
        dlg = Dialog(tr('what'),
                     VBox([dlgPages,
                     dlgDistances,
                     dlgStyle,
                     dlgBeamFlattening,
                     dlgSpacing,
                     dlgInstrumentNames,
                     dlgInfo,
                     dlgBarCount,
                     dlgPageObjects,
                     HBox([Label('  '),dlgDeletePageObjects]),
                     dlgLyricsSettings,
                     dlgSystemAttributes,
                     dlgRemoveExtraDist,
                     dlgStaffLayout,
                     Label(' ')
                     ], padding = 4))
        if dlg.run():
            self.copyPages = dlgPages.value()
            self.copyDistances = dlgDistances.value()
            self.copyStyle = dlgStyle.value()
            self.copyBeamFlattening = dlgBeamFlattening.value()   
            self.copySpacing = dlgSpacing.value()
            self.copyInstrumentNames = dlgInstrumentNames.value()  
            self.copyInfo = dlgInfo.value()             
            self.copyBarCount = dlgBarCount.value()         
            self.copyPageObjects = dlgPageObjects.value()      
            self.deletePageObjects = dlgDeletePageObjects.value()
            self.copyLyricsSettings = dlgLyricsSettings.value()   
            self.copySystemAttributes = dlgSystemAttributes.value() 
            self.copyStaffLayout = dlgStaffLayout.value() 
                                               
        else:
            self.ok = False


    def collectPages(self,score):
        layout = score.gotoChild('layout')
        pages = layout.gotoChild('pages')
        self.layoutPages = pages.cloneNode(True)

    def setPages(self, score):
        if not self.copyPages:
            return
        layout = score.gotoChild('layout')
        pages = layout.gotoChild('pages')
        pages.parentNode.replaceChild(self.layoutPages, pages)

    def collectDistances(self,score):
        layout = score.gotoChild('layout')
        distances = layout.gotoChild('distances')
        self.layoutDistances = distances.cloneNode(True)

    def setDistances(self,score):
        if not self.copyDistances:
            return
        layout = score.gotoChild('layout')
        distances = layout.gotoChild('distances')
        distances.parentNode.replaceChild(self.layoutDistances, distances)

    def collectStyle(self, score):
        self.hasStyle = False
        layout = score.gotoChild('layout')
        for style in layout.getElementsByTagName('style'):
            self.hasStyle = True
            self.layoutStyle = style.cloneNode(True)

    def setStyle(self, score):
        if not self.copyStyle:
            return
        layout = score.gotoChild('layout')
        for style in layout.getElementsByTagName('style'):
            style.parentNode.removeChild(style)
        if self.hasStyle:
            layout.appendChild(self.layoutStyle)

    def collectBeamFlattening(self, score):
        layout = score.gotoChild('layout')
        beamFlattening = layout.gotoChild('beamFlattening')
        self.layoutBeamFlattening = beamFlattening.cloneNode(True)

    def setBeamFlattening(self, score):
        if not self.copyBeamFlattening:
            return
        layout = score.gotoChild('layout')
        beamFlattening = layout.gotoChild('beamFlattening')
        beamFlattening.parentNode.replaceChild(self.layoutBeamFlattening, beamFlattening )

    def collectSpacing(self,score):
        layout = score.gotoChild('layout')
        spacing = layout.gotoChild('spacing')
        self.layoutSpacing = spacing.cloneNode(True)

    def setSpacing(self, score):
        if not self.copySpacing:
            return
        layout = score.gotoChild('layout')
        spacing = layout.gotoChild('spacing')
        spacing.parentNode.replaceChild(self.layoutSpacing, spacing)
        
    def collectInstrumentNames(self,score):
        layout = score.gotoChild('layout')
        instrumentNames = layout.gotoChild('instrumentNames')
        self.layoutInstrumentNames = instrumentNames.cloneNode(True)

    def setInstrumentNames(self, score):
        if not self.copyInstrumentNames:
            return
        layout = score.gotoChild('layout')
        instrumentNames = layout.gotoChild('instrumentNames')
        instrumentNames.parentNode.replaceChild(self.layoutInstrumentNames, instrumentNames)

    def collectInfo(self, score):
        self.hasInfo = False
        for cn in getChildNodes(score):
            if cn.tagName == 'info':
                self.hasInfo = True
                self.scoreInfo = cn.cloneNode(True)

    def setInfo(self, score):
        if not self.copyInfo:
            return
        for cn in getChildNodes(score):
            if cn.tagName == 'info':
                cn.parentNode.removeChild(cn)
        if self.hasInfo:
            layout = score.gotoChild('layout')
            layout.parentNode.insertBefore(self.scoreInfo, layout)

    def collectBarCount(self, score):
        self.hasBarCount = False
        for cn in getChildNodes(score):
            if cn.tagName == 'barCount':
                self.hasBarCount = True
                self.scoreBarCount = cn.cloneNode(True)
        
    def setBarCount(self, score):
        if not self.copyBarCount:
            return
        for cn in getChildNodes(score):
            if cn.tagName == 'barCount':
                cn.parentNode.removeChild(cn)
        if self.hasBarCount:
            for cn in getChildNodes(score):
                if cn.tagName == 'systems':
                    cn.parentNode.insertBefore(self.scoreBarCount, cn)

    def collectPageObjects(self, score):
        self.hasPageObjects = False
        for cn in getChildNodes(score):
            if cn.tagName == 'pageObjects':
                self.hasPageObjects = True
                self.scorePageObjects = cn.cloneNode(True)
        
    def setPageObjects(self, score):
        if not self.copyPageObjects:
            return

        if self.deletePageObjects:
            for cn in getChildNodes(score):
                if cn.tagName == 'pageObjects':
                    cn.parentNode.removeChild(cn)
                    
        if self.hasPageObjects:
            pageObjects = score.gotoChild('pageObjects')
            for cn in getChildNodes(self.scorePageObjects):
                pageObjects.appendChild(cn.cloneNode(True))
                
            # pageObjects vor systems einfügen (Trick)
            systems = score.gotoChild('systems')
            score.insertBefore(score.removeChild(pageObjects), systems)

    def collectLyricsSettings(self, score):
        for lyricsSettings in score.getElementsByTagName('lyricsSettings'):
            self.lyricsSettings = lyricsSettings.cloneNode(True)
            break
            
    def setLyricsSettings(self, score):
        if not self.copyLyricsSettings:
            return
        for lyricsSettings in score.getElementsByTagName('lyricsSettings'):
            lyricsSettings.parentNode.replaceChild(self.lyricsSettings.cloneNode(True), lyricsSettings)

    def collectSystemAttributes(self, score):
        firstSystem = True
        for system in score.getElementsByTagName('system'):
            attribs = []
            attributes = system.attributes
            for i in range(attributes.length):
                att = attributes.item(i)
                attribs.append( (att.name,att.value) )

            if firstSystem:
                firstSystem = False
                self.attributesFirstSystem = attribs
                self.attributesSecondSystem = attribs
            else:
                self.attributesSecondSystem = attribs
                break
                
    def setSystemAttributes(self,score):
        if not self.copySystemAttributes:
            return
        firstSystem = True
        for system in score.getElementsByTagName('system'):
            attributes = system.attributes
            for i in range(attributes.length):
                att = attributes.item(i)
                if att:
                    system.removeAttribute(att.name)

            if firstSystem:
                firstSystem = False
                attribs = self.attributesFirstSystem
            else:
                attribs = self.attributesSecondSystem

            for name, value in attribs:
                system.setAttribute(name, value)

    def collectStaffLayout(self, score):
        layout = score.gotoChild('layout')
        staves = layout.gotoChild('staves')
        self.layoutStaves = staves.cloneNode(True)

        self.hasBrackets = False
        for cn in getChildNodes(layout):
            if cn.tagName == 'brackets':
                self.hasBrackets = True
                self.layoutBrackets = cn.cloneNode(True)

    def setStaffLayout(self, score):
        if not self.copyStaffLayout:
            return
        
        
        usedLayout = []
        # collect layout names
        for staff in score.getElementsByTagName('staff'):
            layout = staff.getAttribute('layout')
            if layout not in usedLayout:
                usedLayout.append(layout)
        # remove unused layout entries
        for staffLayout in score.getElementsByTagName('staffLayout'):
            if staffLayout.getAttribute('description') not in usedLayout:
                staffLayout.parentNode.removeChild(staffLayout)

        # copy layout from template
        templateLayouts = self.layoutStaves.getElementsByTagName('staffLayout')
        count = 0
        for staffLayout in score.getElementsByTagName('staffLayout'):
            if count >= len(templateLayouts):
                break

            oldDescription = staffLayout.getAttribute('description')
            newDescription = templateLayouts[count].getAttribute('description')

            # check if description already used
            check = False
            while not check:
                check = True
                for staff in score.getElementsByTagName('staff'):
                    if staff.getAttribute('layout') == newDescription:
                        check = False
                        newDescription += '_1'
                        templateLayouts[count].setAttribute('description', newDescription)
            
            staffLayout.parentNode.replaceChild(templateLayouts[count], staffLayout)
            
            for staff in score.getElementsByTagName('staff'):
                if staff.getAttribute('layout') == oldDescription:
                    staff.setAttribute('layout', newDescription)
            count += 1
        
        layout = score.gotoChild('layout')
        for brackets in layout.getElementsByTagName('brackets'):
            brackets.parentNode.removeChild(brackets)
        if self.hasBrackets:
            spacing = layout.gotoChild('spacing')
            spacing.parentNode.insertBefore(self.layoutBrackets, spacing)
            # Klammern auf Anzahl Notenzeilen begrenzen
            maxStaff = len(layout.getElementsByTagName('staffLayout')) - 1
            for bracket in layout.getElementsByTagName('bracket'):
                if int(bracket.getAttribute('from')) > maxStaff:
                    bracket.setAttribute('from', str(maxStaff))
                if int(bracket.getAttribute('to')) > maxStaff:
                    bracket.setAttribute('to', str(maxStaff))

    def removeExtraDistance(self, score):
        if not self.removeExtraDist:
            return
        for extraDistance in score.getElementsByTagName('extraDistance'):
            extraDistance.parentNode.removeChild(extraDistance)
            
        
lc = layoutCollector()

def changeDoc1(score):
    lc.collectPages(score)
    lc.collectDistances(score)
    lc.collectInstrumentNames(score)
    lc.collectStyle(score)
    lc.collectSpacing(score)
    lc.collectBeamFlattening(score)
    lc.collectInfo(score)
    lc.collectPageObjects(score)
    lc.collectBarCount(score)
    lc.collectLyricsSettings(score)
    lc.collectSystemAttributes(score)
    lc.collectStaffLayout(score)

def changeDoc2(score):
    lc.setPages(score)
    lc.setDistances(score)
    lc.setInstrumentNames(score)
    lc.setStyle(score)
    lc.setSpacing(score)
    lc.setBeamFlattening(score)
    lc.setInfo(score)
    lc.setPageObjects(score)
    lc.setBarCount(score)
    lc.setLyricsSettings(score)
    lc.setSystemAttributes(score)
    lc.removeExtraDistance(score)
    lc.setStaffLayout(score)

# Hauptprogramm:
from caplib.capDOM import ScoreChange
import tempfile

class ScoreChange1(ScoreChange):

    def changeScore(self, score):
        global doc
        doc = score.parentNode
        changeDoc1(score)

class ScoreChange2(ScoreChange):

    def changeScore(self, score):
        changeDoc2(score)

        
if activeScore() and lc.ok:
    activeTitle = activeScore().title()
    dlg = FileDialog()
    dlg.__init__(bOpen=True)
    dlg.setTitle( tr('selTemplate') )
    dlg.addFilter(tr('allFile'), '*.cap*')
    dlg.addFilter(tr('capFile'), '*.cap')
    dlg.addFilter(tr('capxFile'), '*.capx')
    dlg.setStartFile('')
    if dlg.run():
        capFileName = dlg.filePath()
        head, tail = os.path.split(capFileName)
        # Bei import aus aktiver Datei stürzt capella mit diesem Skript ab
        if tail <> activeTitle:
            openScore(capFileName)
            tempInput = tempfile.mktemp('.capx')
            activeScore().write(tempInput)
            ScoreChange1(tempInput)
            os.remove(tempInput)
            closeActiveScore()

            activeScore().registerUndo('Layout Kopieren')
            tempInput2 = tempfile.mktemp('.capx')
            tempOutput2 = tempfile.mktemp('.capx')
            activeScore().write(tempInput2)

            ScoreChange2(tempInput2, tempOutput2)
            
            activeScore().read(tempOutput2)
            os.remove(tempInput2)
            os.remove(tempOutput2)
        else:
            pass

