#!/usr/bin/env python
import os
from ConfigParser import ConfigParser
#from copy import copy
from optparse import OptionParser, Option, OptionValueError
import coral
from CondCore.TagCollection import Node,TagTree,tagInventory,CommonUtils,entryComment

def stripws(myinput):
    result=('').join(myinput.split(' '))
    result=('').join(result.split('\n')) 
    return result

def copycomments(session,sourcetreename,desttreename):
    entrycomment=entryComment.entryComment(session)
    if entrycomment.existCommentTable() is False:
        entrycomment.createEntryCommentTable()
    session.transaction().start(False)
    data=coral.AttributeList()
    editor=session.nominalSchema().tableHandle(CommonUtils.treeTableName(desttreename)).dataEditor()
    query=session.nominalSchema().tableHandle(CommonUtils.treeTableName(sourcetreename)).newQuery()
    conditionData=coral.AttributeList()
    query.setCondition('',conditionData)
    query.setRowCacheSize(2048)
    editor.rowBuffer(data)
    query.defineOutput(data)
    bulkOperation=editor.bulkInsert(data,2048)
    cursor=query.execute()
    while (cursor.next() ):
        bulkOperation.processNextIteration()
    bulkOperation.flush()
    del bulkOperation
    del query
    session.transaction().commit()
    
class tagTreeClone:
    def __init__(self):
        """
        Class clone an existing tree to a new one only changing pfn in leaf nodes.
        usage: %prog [options]
        -f, --file=filename: configuration file (required). The connect parameter will be overwritten by option -c if present.
        -c, --connect=connectstring: connection string to the tag DB. If -c, -f both given -c value will overwrite the connect parameter in the config file.
        -u, --user=user: user name
        -p, --password=password: password
        -P, --path=path: path to authentication.xml
        -T, --tree=treename:  name of the tree to clone(required)
        -v, --verbose: switch on verbose mode
        -h, --help: print usage
        """
        self.__parser=OptionParser()
        self.__connectstring=''
        self.__user=''
        self.__password=''
        self.__authpath=''
        self.__filename=''
        self.__sourcetreename=''
        self.__targettreename=''
        self.__realclone=False
        self.__service_replace=''
        self.__schema_replace=''
        self.__connect_replace=''
        self.__verbose=False        
    def parsecmdln(self):
        """
        Parse commandline
        """
        usage = "usage: \%prog [options] \n "
        self.__parser.add_option("-f","--file",action="store",dest="filename",help="configuration file for input(required). The connect parameter will be overwritten by option -c if present.")
        self.__parser.add_option("-c","--connect",action="store",dest="connectstring",type="string",help="connection string to the tag DB. If -c, -f both given -c value will overwrite the connect parameter in the config file.")
        self.__parser.add_option("-u","--user",action="store",dest="user",type="string",help="user name")
        self.__parser.add_option("-p","--password",action="store",dest="password",type="string",help="password")
        self.__parser.add_option("-P","--path",action="store",dest="authpath",type="string",help="path to authentication.xml")
        self.__parser.add_option("-T","--tree",action="store",dest="treename",type="string",help="name of the tree to create(required). Note: the tree name is case insensitive, it is internally converted to uppercase")
        self.__parser.add_option("-v","--verbose",action="store_true",dest="verbose",help="verbose mode")
        self.__parser.set_defaults(connectstring='')
        self.__parser.set_defaults(user='')
        self.__parser.set_defaults(password='')
        self.__parser.set_defaults(authpath='.')
        self.__parser.set_defaults(verbose=False)
        (options, args) = self.__parser.parse_args()
        if not self.__parser.values.treename:
            raise OptionValueError("option -%s --%s is required "%('T','tree'))
        if not self.__parser.values.filename:
            raise OptionValueError("option -%s --%s is required "%('f','file'))
        self.__sourcetreename=self.__parser.values.treename.upper()
        self.__filename=self.__parser.values.filename
        if os.path.exists(self.__filename)==False:
            print 'non-existing input file ',self.__filename
            return
        if options.filename and options.connectstring:
            #raise OptionValueError("option -%s and -%s are exclusive"%('f','c'))
            print 'Warning: -c option ',options.connectstring, 'overwrites the connection string in ',options.filename
        if len(self.__parser.values.authpath)!=0:
            self.__authpath=self.__parser.values.authpath
        else:
            self.__user=self.__parser.values.user
            self.__password=self.__parser.values.password
        self.__verbose=self.__parser.values.verbose
        
        clonesection=' '.join(['CLONE',self.__sourcetreename])
        configparser=ConfigParser()
        configparser.read(self.__filename)
        if options.connectstring:
            self.__connectstring=self.__parser.values.connectstring
        else:
            self.__connectstring=configparser.get("COMMON","connect")
        sections=configparser.sections()
        if not clonesection in sections:
            print 'section ', clonesection, 'not found in ',self.__filename
            print 'do nothing'
            return
        self.__targettreename=stripws(configparser.get(clonesection,'target'))
        try:
            self.__service_replace=stripws(configparser.get(clonesection,'service_replace'))
        except NoOptionError:
            pass

        try:
           self.__schema_replace=stripws(configparser.get(clonesection,'schema_replace'))
        except NoOptionError:
            pass

        try:
           self.__connect_replace=stripws(configparser.get(clonesection,'connect_replace'))
        except NoOptionError:
            pass
        
        if self.__parser.values.verbose is True:
            print 'config file: ',self.__filename
            print 'connect: ',self.__connectstring
            print 'sourcetree: ',self.__sourcetreename
            print 'targettree: ',self.__targettreename
            print 'service_replace: ',self.__service_replace
            print 'schema_replace: ',self.__schema_replace
            print 'connect_replace: ',self.__connect_replace
        if len(self.__service_replace)==0 and len(self.__schema_replace)==0 and len(self.__connect_replace)==0:
            self.__realclone=True

    def clonetree(self):
        """
        Create a clone tree 
        """
        #context = coral.Context()
        #if self.__verbose is True:
        #    context.setVerbosityLevel( 'DEBUG' )
        #else:
        #    context.setVerbosityLevel( 'ERROR' )
        
        svc = coral.ConnectionService()
        config=svc.configuration()
        os.environ['CORAL_AUTH_PATH']=self.__authpath
        config.setDefaultAuthenticationService('CORAL/Services/XMLAuthenticationService')
        session=svc.connect( self.__connectstring,accessMode = coral.access_Update )
        allLeafs=[]
        try:
            newtree=TagTree.tagTree(session,self.__targettreename)
            newtree.importFromTree(self.__sourcetreename)
            allLeafs=newtree.getAllLeaves()
            if self.__realclone is True:
                copycomments(session,self.__sourcetreename,self.__targettreename)
                del session
                return
            #the rest don't know how to handle comments yet
            if len(self.__service_replace) != 0:
                inv=tagInventory.tagInventory(session)
                newtaglinks=inv.addEntriesReplaceService(self.__service_replace)
                leafreplacement={}
                for leaf in allLeafs:
                    oldtagid=leaf.tagid
                    newtagid=0
                    for item in newtaglinks:
                        if item[0]==oldtagid:
                            newtagid=item[1]
                    if newtagid == 0:
                        raise "no replacement tagid found for tagid ",oldtagid
                    leafreplacement[oldtagid]=newtagid
                newtree.replaceLeafLinks(leafreplacement)
            del session
        except Exception, e:
            print str(e)
            del session

if __name__ == "__main__":
    tagtreeclone=tagTreeClone() 
    tagtreeclone.parsecmdln()
    tagtreeclone.clonetree()
    

