#
# -*- coding: utf-8 -*-
'''
$RCSfile: cmfupgrade.py,v $
$Revision: 904 $
$Author: markus $
$Date: 2008-04-30 10:56:34 +0200 (Mi, 30. Apr 2008) $
'''

import sys, os, string
from datetime                   import datetime
from biocase.wrapper.cmf_base   import CMFClass
from biocase.wrapper.cmf_element import CMFMappingClass
import biocase.configuration

cfg = biocase.configuration.Cfg()
import logging
log = logging.getLogger("webapp.cfgtool")

class cmfUpgrade(object):
    def __init__(self):
        self.cmfUpgradeDir = os.path.join( cfg.rawCmfTemplateLocator, 'upgrades')
        # read index dictionary for upgrade files
        class Index( object ):
            pass
        indexObj = Index()
        execfile( os.path.join(self.cmfUpgradeDir,'index.py'), globals(), indexObj.__dict__ )
        self.indexDict     = indexObj.index
        log.debug("Full available upgrade ditcionary:")
        log.debug(unicode(self.indexDict))
        
        
    def listPossibleUpgrades(self, sourceCmfNS):
        '''Return a list of raw cmf filenames without suffix suitable for upgrading a given cmf.'''
        if not self.indexDict.has_key(sourceCmfNS):
            return []
        return [ t[1][:-4] for t in self.indexDict[sourceCmfNS].values() ]
        
    def listPossibleUpgradeTuples(self, sourceCmfNS):
        '''Return a dict (key=namespace) of tuples (rawCmfFileName, upgradeFileName) 
        for all available upgrades of a given cmf namespace.'''
        if self.indexDict.has_key(sourceCmfNS):
            log.debug("List possible upgrades for ns=%s: %s" % (sourceCmfNS, unicode( self.indexDict[sourceCmfNS].keys() )))
            return self.indexDict[sourceCmfNS]
        elif self.indexDict.has_key(sourceCmfNS.lower() ):
            log.debug("List possible upgrades for ns=%s: %s" % (sourceCmfNS.lower(), unicode( self.indexDict[sourceCmfNS.lower()].keys() )))
            return self.indexDict[sourceCmfNS.lower()]
        else:
            log.debug("No possible upgrades for ns=%s"%sourceCmfNS)
            return {}

    def getUpgradedCmfObj(self, cmfFileName, targetNamespace):
        '''Return a cmf object based on the upgraded namespace and the appropiate upgrade file.
        All existing mappings that couldnt be transfered are returned as a list in the second parameter.'''
        if os.path.isfile(cmfFileName):
            # read existing CMF
            oldCmf = CMFClass()
            oldCmf.loadCMFdata( cmfFileName)
            if self.indexDict.has_key(oldCmf.getRootNamespace()) or self.indexDict.has_key(oldCmf.getRootNamespace().lower()):
                # upgradeTuple
                if self.indexDict[oldCmf.getRootNamespace()].has_key(targetNamespace):
                    upgradeTuple = self.indexDict[oldCmf.getRootNamespace()][targetNamespace]
                elif self.indexDict[oldCmf.getRootNamespace().lower()].has_key(targetNamespace):
                    upgradeTuple = self.indexDict[oldCmf.getRootNamespace()][targetNamespace]
                else:
                    return None, [], (None,None)
            else:
                return None, [], (None,None)
        else:
            return None, [], (None,None)
        
        log.debug("UPGRADING CMF %s to NS %s ..." % (oldCmf.getRootNamespace(), targetNamespace))
        # new target cmf object
        newCmf = CMFClass()
        rawCmfPath = os.path.join( cfg.rawCmfTemplateLocator, upgradeTuple[0] )
        newCmf.loadCMFdata( rawCmfPath )
        # transfer non mapping properties
        newCmf.name           = oldCmf.name
        newCmf.generated_by   = "Configtool lib $Revision: 904 $"
        newCmf.generated_when = str(datetime.now())
        newCmf.omitNS         = oldCmf.omitNS
        newCmf.tableTreeObj.rootTableAlias = oldCmf.tableTreeObj.rootTableAlias
        # transfer mappings
        # read upgrade file...
        upgradeFilePath = os.path.join( self.cmfUpgradeDir, upgradeTuple[1] )
        upgradeDict = {}
        literalsDict = {}   # key=newCmfPath, value=literal
        for line in file(upgradeFilePath).readlines():
            sourcePath, targetPath = line.split( chr(9) )
            sourcePath = sourcePath.strip()
            targetPath = targetPath.strip()
            if len(sourcePath) > 2 and sourcePath.startswith("'") and sourcePath.endswith("'"):
                # its a literal in simple quotes!
                literalsDict[targetPath] = sourcePath[1:-1]
            elif upgradeDict.has_key(sourcePath):
                upgradeDict[sourcePath].append( targetPath )
            else:
                upgradeDict[sourcePath] = [targetPath]
        # get dict of mappings with key=concept path, value=list of mapping objects
        mappings = oldCmf.removeMappings()
        newMappings = {}
        missingConcepts = {}
        for path, map in mappings.items():
            if upgradeDict.has_key(path):
                log.debug("Move mappings from %s to %s" %(path, unicode(upgradeDict[path]) ))
                for targetPath in upgradeDict[path]:
                    if not newMappings.has_key(targetPath):
                        newMappings[targetPath] = []
                    newMappings[targetPath] += map[:]
            else:
                missingConcepts[path] = map
        # update newCmf
        newCmf.setMappings( newMappings )
        # add literals
        for path, literal in literalsDict.items():
            mapObj = CMFMappingClass(items=[literal])
            newCmf.addMappingToConcept(path=path, mapObj=mapObj)
        # log missing concepts
        log.debug("The following missing concepts couldnt be included in the upgraded CMF:")
        for path, map in missingConcepts.items():
            log.debug("Concept %s : %s" % (path, unicode(map) ))
        # return cmf and missing concepts mapping dict
        return newCmf, missingConcepts, upgradeTuple
        
        
        
