#!/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 convertnodedata(mynodevalue):
    mynodedata={}
#    datastr=('').join(value.split(' '))
    startbrack=mynodevalue.find('{')
    endbrack=mynodevalue.find('}')
    metagdatastr=mynodevalue[startbrack+1:endbrack]
    mynodedata['nodelabel']=mynodevalue[0:startbrack]
    metadatalist=metagdatastr.split(',')
    for pair in metadatalist:
        mydata=pair.split('=',1)
        mynodedata[mydata[0]]=mydata[1]
    #print 'mynodedata'
    return mynodedata

def convertnodecollection(value):
    cleanvalue=stripws(value)
    mynodecollection=[]
    nodelist=cleanvalue.split(';')
    for nodedata in nodelist:
        mynodecollection.append(convertnodedata(nodedata))
    return mynodecollection

def check_nodedata(option, opt, value):
    try:
        return convertnodecollection(value)
    except ValueError:
        raise OptionValueError(
            "option %s: invalid nodedata: %r" % (opt, value))
class MyOption (Option):
    TYPES = Option.TYPES + ("nodedata",)
    TYPE_CHECKER = copy(Option.TYPE_CHECKER)
    TYPE_CHECKER["nodedata"] = check_nodedata
    
class tagTreeBuilder:
    def __init__(self):
        """
        Class add node to an existing tag tree
        usage: %prog [options]
        -f, --file=filename: use file to populate the tag tree. -l will not be considered together with the -f option. The connect parameter will be overwritten by option -c. 
        -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 create(required). Note: the tree name is case insensitive, it is always internally converted to uppercase.
        -n, --node=node: one or a collection of non-leaf node(s) to attach to the tree. \"node1{parent=string,globalsince=unsigned long long,globaltill=unsigned long long};node2{...}\". 
        -l, --leafnode=leafnode: one or a collection of leaf node(s) to attach to the tree. \"node1{parent=string,tagname=string};node2{...}\".
        -v, --verbose: switch on verbose mode
        -h, --help: print usage
        """
        self.__parser=OptionParser(option_class=MyOption)
        self.__connectstring=''
        self.__user=''
        self.__password=''
        self.__authpath=''
        self.__treename=''
        self.__nodecollection=[]
        self.__leafcollection=[]
        self.__verbose=False
    def parsecmdln(self):
        """
        Parse commandline
        """
        usage = "usage: \%prog [options] \n"
        self.__parser.add_option("-f","--file",action="store",dest="filename",help="populate the tag tree from the given file. -l will not be considered together with the -f option. The connect parameter will be overwritten by option -c.")
        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("-n","--nodedata",action="store",dest="nodedata",type="nodedata",help="one or a collection of non-leaf node(s) to attach to the tree. \"node1{parent=string,globalsince=unsigned long long,globaltill=unsigned long long};node2{...}\"")
        self.__parser.add_option("-l","--leafdata",action="store",dest="leafdata",type="nodedata",help=" one or a collection of leaf node(s) to attach to the tree. \"node1{parent=string,tagname=string};node2{...}\" ")
        self.__parser.add_option("-v","--verbose",action="store_true",dest="verbose",help="verbose mode")
        self.__parser.set_defaults(filename='')
        self.__parser.set_defaults(connectstring='')
        self.__parser.set_defaults(user='')
        self.__parser.set_defaults(password='')
        self.__parser.set_defaults(authpath='')
        self.__parser.set_defaults(nodedata=[])
        self.__parser.set_defaults(leafdata=[])
        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'))
        self.__treename=str.upper(self.__parser.values.treename)
        if options.filename and options.connectstring:
            print 'Warning: -c option ',options.connectstring, 'overwrites the connection string in ',options.filename
            #raise OptionValueError("option -%s and -%s are exclusive"%('f','c'))
        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
        
        if self.__parser.values.filename!='':
            treesection=' '.join(['TAGTREE',self.__treename])
            #print treesection
            configparser=ConfigParser()
            configparser.read(self.__parser.values.filename)
            if options.connectstring:
                self.__connectstring=self.__parser.values.connectstring
            else:
                self.__connectstring=configparser.get('COMMON','connect')
            if configparser.has_option(treesection, 'nodedata'):
                nodedata=stripws(configparser.get(treesection,'nodedata'))
                self.__nodecollection=convertnodecollection(nodedata)
            if configparser.has_option(treesection, 'leafdata'):
                leafdata=stripws(configparser.get(treesection,'leafdata'))
                self.__leafcollection=convertnodecollection(leafdata)
                #print self.__leafcollection
            if self.__parser.values.verbose is True:
                print 'config file: ',self.__parser.values.filename
        else:
            self.__connectstring=self.__parser.values.connectstring
            if self.__parser.nodedata:            
                nodedata=stripws(self.__parser.values.nodedata)
                self.__nodecollection=convertnodedata(nodedata)
            if self.__parser.leafdata:
                leafdata=stripws(self.__parser.values.leafdata)
                self.__leafcollection=convertnodedata(leafdata)
        if self.__parser.values.verbose is True:
            print 'connectstring: ',self.__connectstring
            print 'user: ',self.__user
            print 'password: ',self.__password
            print 'authpath: ',self.__authpath
            print 'tree: ',self.__treename
            print 'nodecollection: ',self.__nodecollection
            print 'leafcollection: ',self.__leafcollection

    def addEntries(self):
        """
        Add nodes in the tag tree
        """
        if len(self.__nodecollection)==0 and len(self.__leafcollection)==0:
            print 'empty data, do nothing'
            return
        #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 )
        try:
            mytree=TagTree.tagTree(session,self.__treename)
            if mytree.existTagTreeTable() is False:
                raise Exception,'non-existing tag tree table, use cmscond_tagtree_createroot to create the table and tree root first'
            for item in self.__nodecollection:
                mynode=Node.Node()
                mynode.globalsince=0
                mynode.globaltill=0
                mynode.tagid=0
                mynode.nodelabel=item['nodelabel']
                if item.has_key('globalsince'):
                    mynode.globalsince=nodedata['globalsince']
                if item.has_key('globaltill'):
                    mynode.globaltill=nodedata['globaltill']
                if not item.has_key('parent'):
                    raise KeyError,'no parent parameter for'+mynode.nodelabel
                newnodeid=mytree.insertNode(mynode,item['parent'])
                if item.has_key('comment'):
                  entrycomment=entryComment.entryComment(session)
                  if entrycomment.existCommentTable() is False:
                      entrycomment.createEntryCommentTable()
                  entrycomment.insertComment(CommonUtils.treeTableName(self.__treename),newnodeid ,item['comment'])
            if len(self.__leafcollection)!=0:
                inv=tagInventory.tagInventory(session)
                for leafdata in self.__leafcollection:
                    myleaf=Node.Node()
                    myleaf.globalsince=0
                    myleaf.globaltill=0
                    myleaf.tagid=0
                    myleaf.nodelabel=leafdata['nodelabel']
                   # print 'again ',myleaf.nodelabel
                    if leafdata.has_key('tagname') is False:
                        raise ValueError, "tagname is not specified for the leaf node "+myleaf.nodelabel
                    tagname=leafdata['tagname']
                    mypfn=''
                    if leafdata.has_key('pfn') is True:
                        mypfn=leafdata['pfn']
                       # print 'leafdata pfn ',mypfn
                    result=inv.getEntryByName(tagname,mypfn)
                    if result.tagid == 0:
                        raise ValueError, "unknown tag \'"+leafdata['tagname']+" "+leafdata['pfn']+"\' in the inventory"
                    myleaf.tagid=result.tagid
                    if not leafdata.has_key('parent'):
                        raise KeyError,'no parent parameter for'+myleaf.nodelabel
                    newnodeid=mytree.insertNode(myleaf,leafdata['parent'])
                    if leafdata.has_key('comment'):
                        entrycomment=entryComment.entryComment(session)
                        if entrycomment.existCommentTable() is False:
                            entrycomment.createEntryCommentTable()
                        entrycomment.insertComment(CommonUtils.treeTableName(self.__treename),newnodeid,item['comment'])
            del session
        except Exception, e:
            print str(e)
            del session        
if __name__ == "__main__":
    tagtreebuilder=tagTreeBuilder() 
    tagtreebuilder.parsecmdln()
    tagtreebuilder.addEntries()


