#
# -*- coding: utf-8 -*-

'''
$RCSfile: cmfinfo.py,v $
$Revision: 987 $
$Author: markus $
$Date: 2010-09-14 13:27:06 +0200 (Di, 14. Sep 2010) $
Methods related to schemas / CMFs. 
'''

############################################################################################################
#
#   IMPORTS
#
#===========================================================================================================

import os
import biocase.configuration
from biocase.wrapper.cmf_base import CMFClass
import logging
log = logging.getLogger("lib")
cfg = biocase.configuration.Cfg()

import logging
log=logging.getLogger("lib.cmfinfo")

############################################################################################################
#
#   CLASSES
#
#===========================================================================================================
class CMFListClass:
    # ------------------------------------------------------------------------------------
    def __init__(self):
        self.schemas = []
        
    # ------------------------------------------------------------------------------------
    def __len__(self):
        return len(self.schemas)
    # ------------------------------------------------------------------------------------
    def __getitem__(self, index):
        return self.schemas[index]
    # ------------------------------------------------------------------------------------
    def __iter__(self):
        self._iterIndex = 0              # the next iterator index
        return self                      # simplest iterator creation
    # ------------------------------------------------------------------------------------
    def next(self):
        if self._iterIndex < len(self):
            self._iterIndex += 1
            return self.__getitem__( self._iterIndex-1 )
        else:
            raise StopIteration
    # ------------------------------------------------------------------------------------
    def __repr__(self):
        return "CMFList:%s"%(str(self.schemas))
        
    # ------------------------------------------------------------------------------------
    def addSchemasFromDir(self, dir):
        if os.path.isdir(dir):
            for cmf in os.listdir(dir):
                if cmf[:4]=='cmf_' and cmf[-4:]<>'pick' and cmf[-4:] <> '.bak' and cmf[-8:-3] <> '.bak.' and cmf[-4:] <> '.tmp':
                    self.addSchema(os.path.join(dir, cmf))
                    
    # ------------------------------------------------------------------------------------
    def addDeletedSchemasFromDir(self, dir):        
        if os.path.isdir(dir):
            for cmf in os.listdir(dir):
                if cmf[:4]=='_cmf' and cmf[-8:-3] == '.bak.' and cmf[-4:]<>'pick' and cmf[-4:] <> '.tmp' and cmf[-4:] <> '.bak':                    
                    self.addSchema(os.path.join(dir, cmf))
                
    # ------------------------------------------------------------------------------------
    def getBakFileName(self, dir, schema):                
        if os.path.isdir(dir):
            schemaPattern = os.path.join(dir, "_" + schema + ".bak.")
            for i in range(1000):
                bakFileName = schemaPattern + '%0*d' % (3, i)
                if not os.path.exists(bakFileName):
                    return bakFileName            
                                
        return schemaPattern + "000"
                

    # ------------------------------------------------------------------------------------
    def addSchema(self, filename):
        if os.path.isfile(filename):
            log.debug("CMFList: Trying to add file %s"%filename)
            # read CMF
            cmfObj = CMFClass()
            try:
                if cmfObj.loadCMFdata(filename=filename, pickle=True):
                    cmfInfoObj = CMFInfoClass(cmfObj)
                    self.schemas.append( cmfInfoObj )
                    log.debug("  Added. Name=%s"%(cmfInfoObj.name))
                    return True
                else:
                    log.debug("  Failed.")
                    log.debug(str(cmfObj))
                    return False
            except:
                    log.debug("  Failed to load pickle. Try from source.")
                    if cmfObj.loadCMFdata(filename=filename, pickle=False):
                        cmfInfoObj = CMFInfoClass(cmfObj)
                        self.schemas.append( cmfInfoObj )
                        log.debug("  Added. Name=%s"%(cmfInfoObj.name))
                        return True
                    else:
                        log.debug("  Failed.")
                        log.debug(str(cmfObj))
                        return False
                

    # ------------------------------------------------------------------------------------
    def removeSchema(self, NS=None, name=None, filename=None):
        '''Remove a schema from the list identified by any of the parameters.'''
        sObj = None
        if NS is not None:
            sObj = self.getSchemaByNS(NS)
        elif name is not None:
            sObj = self.getSchemaByName(name)
        elif filename is not None:
            sObj = self.getSchemaByFile(filename)
        if sObj is not None:
            self.schemas.remove(sObj)
            log.debug("Removed schema %s from list"%sObj.name)
        else:
            log.debug("Could not remove schema from list")
        return sObj

    # ------------------------------------------------------------------------------------
    def getSchemaList(self):
        return self.schemas
        
    # ------------------------------------------------------------------------------------
    def getSchemaByName(self, name):
        for sObj in self.schemas:
            if sObj.name == name:
                return sObj
        return None
        
    # ------------------------------------------------------------------------------------
    def getSchemaByNS(self, NS):
        for sObj in self.schemas:
            if sObj.NS == NS:
                return sObj
        return None

    # ------------------------------------------------------------------------------------
    def getSchemaByFile(self, filename):
        for sObj in self.schemas:
            if sObj.file == filename:
                return sObj
        return None

#===========================================================================================================
class CMFInfoClass:
    # ------------------------------------------------------------------------------------
    def __init__(self, cmfObj):
        # the name is the filename without leading cmf_
        self.name           = os.path.split(cmfObj.absFilename)[1]
        if self.name[:4].lower() == 'cmf_':
            self.name = self.name[4:]
        # take relevant data
        self.file           = cmfObj.absFilename
        self.fullname       = cmfObj.name
        self.acronym        = cmfObj.acronym
        self.version        = cmfObj.version
        self.generated_when = cmfObj.generated_when
        self.generated_by   = cmfObj.generated_by
        self.modified_when  = cmfObj.modified_when
        self.NS             = cmfObj.getRootNamespace()
        self.recID          = cmfObj.recIdents
        self.rootAlias      = cmfObj.getRootTableAlias()
        self.mappings       = cmfObj.countMappedConcepts()
        self.concepts       = cmfObj.countConcepts()
        self.filters        = cmfObj.countGlobalFilters()
    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def getLastUpdated(self):
        '''Returns the datetime of the last update of the CMF file or None if unknown.'''
        return self.modified_when
        
    # ------------------------------------------------------------------------------------
    def __repr__(self):
        return "CMF %s  NS=%s, recID=%s, root=%s, mappings=%i, concepts=%i, filters=%i, file:%s"%(self.name, self.NS, str(self.recID), self.rootAlias, self.mappings, self.concepts, self.filters, self.file)


#===========================================================================================================
class CMFTemplateListClass(CMFListClass):
    def __init__(self):
        self.schemas = []
        self.NS2schema = {}
        self.addSchemasFromDir(cfg.rawCmfTemplateLocator)
        
    # ------------------------------------------------------------------------------------
    def __repr__(self):
        return "CMFTemplList:%s"%(str(self.schemas))
        
############################################################################################################
#
#   FUNCTIONS
#
#===========================================================================================================

def getCMFTemplateList():
    slObj = SchemaListClass()
    slObj.addSchemasFromDir(cfg.rawCmfTemplateLocator)
    return slObj.getSchemaList()
    
    
    
