#!/usr/bin/env python
import os,os.path,string
import sys
import xml.parsers.expat
import fnmatch
from optparse import OptionParser

elementstack_l1=[]
elementstack_l2=[]


def locate(pattern, root=os.curdir):
    '''Locate all files matching supplied filename pattern in and below
    supplied root directory.'''
    for path, dirs, files in os.walk(os.path.abspath(root)):
        for filename in fnmatch.filter(files, pattern):
            yield str(os.path.join(path, filename))

def start_element(name, attrs):
    if name=='detector':
        elementstack_l1.append(attrs)
    if name=='poolsetup':
        elementstack_l2.append(attrs)
    return

class bootstrap:
    def __init__(self):
        """
        Prepare schema for one or many database schema.
        usage: %prog [options]
        -f, --dbconfig : DB configuration file with absolute path(default hardcoded in CondTools/OracleDBA/dbconfig/dbconfiguration.xml)
        -P, --authPath : path to authentication.xml(default .)
        -c, --connect : connect string to DB to set up (default in dbconfig)
        -a, --all : Set up all schemas in DB configuration file(default)
        -b, --basedir : basedir for mappingdir. Default to $CMSSW_RELEASE_BASE
        -D, --Detector : Set up only schema identified with given Detector entry in the DBConfiguration file
        --fake : Don't actually do anything, only print commands
        -v, --verbose: verbose mode
        -h, --help: print usage
        """
        self.__verbose=False
        self.__fake=False
        self.__all=False
        self.__detector=''
        self.__authpath='.'
        self.__connect=''
        self.__registry={}
        self.__basedir=''
        self.__dbconfig=''
    def fillregistry(self):
        idx=0
        for l1element in elementstack_l1:
            currentdetector=l1element['name']
            print currentdetector
            offlineconnect=l1element['offline_connect']
            detectormap={}
            detectormap['mapping']=[]
            detectormap['library']=''
            self.__registry[currentdetector]=(offlineconnect,detectormap)
            idx=elementstack_l1.index(l1element)
            level2elements=elementstack_l2[idx]
            if os.path.isabs(level2elements['mappingdir']):
                mappingdir=level2elements['mappingdir']
            else:
                mappingdir=os.path.abspath(os.path.join(self.__basedir,level2elements['mappingdir']))
            mappingfile=level2elements['mappingfile']
            result=[]
            if mappingfile.find('*')!=-1:
              for result in locate(mappingfile,mappingdir):
                 self.__registry[currentdetector][1]['mapping'].append(result)
                 self.__registry[currentdetector][1]['library']=level2elements['library']
            else:
              a=mappingfile.split(' ')
              result=map(lambda x: os.path.join(mappingdir,x) ,a)
              self.__registry[currentdetector][1]['mapping']=result
              self.__registry[currentdetector][1]['library']=level2elements['library']
        return
    def parsedbconfig(self):
        """
        Parse dbconfig xml to fill in self.__registry
        """
        p = xml.parsers.expat.ParserCreate()
        p.StartElementHandler = start_element
        f=open(self.__dbconfig,'r')
        p.ParseFile(f)
        self.fillregistry()
        
    def parsecmdln(self):
        """
        Parse commandline
        """
        usage = "usage: \%prog [options] \n"
        parser = OptionParser()
        parser.add_option("-f","--dbconfig",action="store",dest="dbconfig",
                          help="( DB configuration file with absolute path required )")
        parser.add_option("-P","--authPath",action="store",dest="authpath",
                          help="path to authentication.xml(default .)")
        parser.add_option("-c","--connect",action="store",dest="connect",
                          help="DB to set up (overwrites default value in dbconfig.)")
        parser.add_option("-a","--all",action="store_true",dest="all",
                          help="Set up all schemas in DB configuration file(default)")
        parser.add_option("-D","--Detector",action="store",dest="Detector",
                          help="Set up only schema identified with given Detector entry in the DBConfiguration file")
        parser.add_option("-b","--basedir",action="store",dest="basedir",
                          help="basedir for mappingdir. Default to $CMSSW_RELEASE_BASE")
        parser.add_option("--fake",action="store_true",dest="fake",
                          help="Don't actually do anything, only print commands")
        parser.add_option("-v","--verbose",action="store_true",dest="verbose",
                          help="verbose mode")        
        (options, args) = parser.parse_args()
        self.__verbose=options.verbose
        if options.fake:
            self.__fake=True
        if options.all:
            self.__all=True
        self.__detector=options.Detector
        if options.authpath:
            self.__authpath=options.authpath
        if options.connect:
            self.__connect=options.connect
        if options.basedir:
            self.__basedir=options.basedir
        else:
            try:
                mybase=os.environ['CMSSW_RELEASE_BASE']
            except KeyError:
                raise ValueError, 'variable CMSSW_RELEASE_BASE not set, do eval scram runtime first'
            self.__basedir=os.path.expandvars('$CMSSW_RELEASE_BASE')
        if not options.dbconfig:
            raise ValueError,'option -f is required!'
        self.__dbconfig=options.dbconfig
        self.parsedbconfig()
        if self.__verbose is True:
            print '###Auth path : ',self.__authpath
            if self.__all is True:
                for d in self.__registry.keys():
                    print '###Detector : ', d
                    if len(self.__connect)!=0:
                        print '###Connect : ',self.__connect
                    else:
                        print '###Connect : ',self.__registry[d][0]
                    mappingxmlfile=self.__registry[d][1]['mapping']
                    dict=self.__registry[d][1]['library']
                    print '###Mapping base dir : ',self.__basedir
                    print '###Mapping : ',mappingxmlfile
                    print '###Dictionary : ',dict
            else:
                d=self.__registry[self.__detector]
                print '###Detector : ',self.__detector
                if len(self.__connect)!=0:
                    print '###Connect : ',self.__connect
                else:
                    print '###Connect : ',d[0]
                mappingxmlfile=d[1]['mapping']
                dict=d[1]['library']
                print '###Mapping base dir : ',self.__basedir
                print '###Mapping : ',mappingxmlfile
                print '###Dictionary : ',dict
    def execute(self):
        os.environ['CORAL_AUTH_PATH']=self.__authpath
        if self.__all is False:
            commands=[]
            c=self.__connect
            if len(self.__connect)==0:
                c=self.__registry[self.__detector][0]
            createmeta=' '.join(['cmscond_schema_metadata','--create','-P',self.__authpath,'-c',c])
            createiov=' '.join(['cmscond_schema_iov','--create','-P',self.__authpath,'-c',c])
            for mappingxmlfile in self.__registry[self.__detector][1]['mapping']:
                dict=self.__registry[self.__detector][1]['library']
                createpool=' '.join(['pool_setup_database','-c',c,'-f',mappingxmlfile,'-d',dict])
                commands.append(createpool)
            if self.__fake is True:
                print 'Fake run...'
                print '\t',createmeta
                print '\t',createiov
                for command in commands:
                    print '\t',command
            else:
                print 'Running...'
                print '\t',createmeta
                os.system(createmeta)
                print '\t done'
                print '\t',createiov
                os.system(createiov)
                print '\t done'
                for command in commands:
                    print '\t',command
                    os.system(command)
                    print '\t done'
        else:
            c=self.__connect
            for detector in self.__registry.keys():
                self.__detector=detector
                if len(self.__connect)==0:
                    c=self.__registry[self.__detector][0]
                commands=[]
                createmeta=' '.join(['cmscond_schema_metadata','--create','-P',self.__authpath,'-c',c])
                createiov=' '.join(['cmscond_schema_iov','--create','-P',self.__authpath,'-c',c])
                dict=self.__registry[self.__detector][1]['library']
                for mappingxmlfile in self.__registry[self.__detector][1]['mapping']:
                    createpool=' '.join(['pool_setup_database','-c',c,'-f',mappingxmlfile,'-d',dict])
                    commands.append(createpool)
                if self.__fake is True:
                    print 'Fake run...'
                    print '\t',createmeta
                    print '\t',createiov
                    for command in commands:
                        print '\t',command
                else:
                    print 'Running...'
                    print '\t',createmeta
                    os.system(createmeta)
                    print '\t done'
                    print '\t',createiov
                    os.system(createiov)
                    print '\t done'
                    for command in commands:
                        print '\t',command
                        os.system(command)
                        print '\t done'
                        
if __name__ == "__main__":
    b=bootstrap()
    b.parsecmdln()
    b.execute()

