##################################################################################################
#                                                                                                #    
#                                      ```...`                                                   #    
#                                   `......-::::.`...---.`                                       #    
#                                  ``     `.-::-.....---:::-`                                    #    
#                                           ..`      `.--:://-                                   #    
#                                     `//:`            .-:::/+:                                  #    
#                                    +m/`sy            `.-:://+`                                 #    
#                              `    :mMmdN/        .::.`.-:://+-                                 #    
#                   ``-//-----------odMMMs`      -yh:/m+.-:///+-                                 #    
#               `..--------/oyy/---::/+sh.      -mNd/omh-:://++.                                 #    
#             `.-------------:------::///:.     yNMMMMNs-:///+:                                  #    
#           `------------------------:::://:`   omNNNmy-:///+:`                                  #    
#          .--------........---------:::::/+/.  `+sys/-::/+++:`                                  #    
#         .---------.---------------:::::///++:..------::://+o+.                                 #    
#        .---------...-------------:::::://++/----------:::///+o-                                #    
#        -------------------------::::::////:---.-------::::///+o.                               #    
#       `:----------------------:::::::///:---..-------:::::///+o/                               #    
#       .:--------------------:::::://///:-------------::::////+o+             `.-               #    
#       `::---------------:::::::://////:------------::::::///+++/            ..-:               #    
#       `::::--------:::::::////////////-----------::::://///++++-           .--:/`  ``..        #    
#        -/:::::::::::://///////////////--------::::://////+++++/`          .--:/+...--/.        #    
#         :///::::://////++++++++++++++/-----::::///////++++++//.         `.---::----:/:         #    
#          :+//////++++++++++++++++++o+/-:::::///////++++++++/:`         `..-------:/+/`````.`   #    
#           ./++++ooooooooooooooooooo/:::::///+++++++++++++//-`         `.---------///-..--:-    #    
#            `-+osssso/+sssssssssso+/::://+++ooooooooo+++/:-`          `----------------://-     #    
#               .:+:.` `-+ossyyyysooo++++oosssssoooo++//+:.            ---------------:/+/.      #    
#                         `-/+osyyyyyysssyysssssoo++++++oso/.----.````.-------------://+/`       #    
#                             `..-://+++osysssssooosyso+ooossydhs+----------------:://++:        #    
#                                       `+ssssssssssyyyo+++++/:--------------::::////////-`      #    
#                   `                  -+osooooooooosshhs/:----..--------::://////++//:----.     #    
#           ..`    ...`               :ssooooossssssyyy+:------------::/++ooooooooooo+/:----.`   #    
#           .--..``-.--`              .oysssssssssshdo:----------::/++ossyhddhhdo....--------`   #    
#     ``    `:-.---:----`             .----------:+mh:------:://++oohhhdddddddddms`              #    
#    `.......-:----------.`          .-...```````..smy++//++ooooooooyddddddddddddmy`             #    
#      `.-------------------.`````..-/:--.....`````.:shhhdddho/::/+oohdddddhhhhhddms             #    
#         `-------....--------------/:-...````````````..----:/.` ``-/+hddddhhhddddmd:            #    
#           `.-----.--..-----------:/:-....````````````````..::``  `.:ommddhdddmmmmms            #    
#             `---------------::://++:--......``````````....--/:`````.:sdddmmmmmdddmh`           #    
#             .--------:://+++++//:-//:--.....................-/-````.-/yydhyyyhhhhdd`           #    
#           `..----:://///:--..``   :+::--------..............-//.```.-:sdhyyyyyhhhhd`           #    
#          ..--::://::-..-://+///:-`.o/::----.................-:+:.``..:+hyyyyyyhhhhs            #    
#         .-::-..`   `:+ooooooooooso/o+:::---------------------:++-....:/yyyyyyyyhhh:            #    
#          `        .syso+++++++oooosso+/::::::-----------::::::+s/-..--:shyyyyyhhys`            #    
#                `.../yysoooooo+oooossyso///::------------::://++yo:---:/ohyyyyhhys.             #    
#                :o+:`.oysoooooooooossyhhoo+:----------:::::://++dh+::::/+dhhhhhys.              #    
#                .ooo:``ohyssoooooosssyhhoooo+:------::::::////++ymo//::/+dhhddh/`               #    
#                 /sso:``ohyyssssssssyyhdysooooo/:::://++///++++shds+////+mddho-                 #    
#                  :sss/.`odhyyyyyyyyyyhdddyssooso///+oysooooosshNhso++//+hyo-                   #    
#                   -syy+-.sdhhhyyyyyyyyyyhhhyyssssoosyyysssyhdmNdysso++/ossso+/-.               #    
#                    `/syo:-sddhhhyyyyysssyyhhhhyyyysosssssossyyhyyssso+ossoo++//-               #    
#                      `+hy/-oddhhyyyyssssyyyhddddhh+  `/oosssssssssoo+ydhho/:-.`                #    
#                       :osso:+ddhhyyyssssyyyhddhhyo.   `/oosssssssssssyhhhhhhhhy+.              #    
#                        -sso+::yddhyyyyyyyyyhho `       `:+osssssssssyhsoshdhhhhddo-`           #    
#                         .oys/--odddhhhhyyhhhs.           .:osyyyyyyhsoooyhdhyssyhds/           #    
#                          `/yy+:-/dmdddhhhhyo.             `yhhhhhysoosyhddhsoosyyds-           #    
#                            .+ys+/+dmdddhy+.               `shyssoosyhdddhysooosyhdo-`          #    
#                              .+so:-/::-.                   `-+oshhhhhhyyssoooosyhd/-           #    
#                                ``                        .:+oooo++oooooooooooosyhh-.           #    
#                                                        `+oooo++++++++++++++ooosyho`            #    
#                                                        +ssooooo++++++++++++oosyhd/.            #    
#                                                       `yyysssoooooooo+++oooosyyhh-.            #    
#                                                        sdhhyyyssssssssssssyyyhhd+-.            #    
#                                                        .hmddddhhhhhhhhhhhhhddddo:-             #    
#                                                         `:ohddmmddddddddddhyso/::              #    
#                                                            -:/++ooooooo++//:--.`               #    
##################################################################################################
#                           ____       _                                                         #
#                          / ___| __ _| | __ _ _ __   __ _  __ _  ___                            #
#                         | |  _ / _` | |/ _` | '_ \ / _` |/ _` |/ _ \                           #
#                         | |_| | (_| | | (_| | |_) | (_| | (_| | (_) |                          # 
#                     _____\____|\__,_|_|\__,_| .__/ \__,_|\__, |\___/ _                         #  
#                    |  ___| __ __ _ _ __ ___ |_|____      |___/  _ __| | _                      #_
#                    | |_ | '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /                     #
#                    |  _|| | | (_| | | | | | |  __/\ V  V / (_) | |  |   <                      # 
#                    |_|  |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\                     #
#                                                                                                # 
##################################################################################################

import ROOT as r
from array import array
from ROOT import TTree, TFile, TCut, TH1F, TH2F, TH3F, THStack, TCanvas, SetOwnership
from include.processHandler import processHandler
from include.plotHandler import plotHandler
from include.yieldHandler import yieldHandler
from include.effHandler import effHandler
import copy
import os
import __main__

########################################################################################
########################################################################################
################################### Sample Class #######################################
########################################################################################
########################################################################################
class Sample:
   'Common base class for all Samples'
   def __init__(self, name, label, color, location, xsection, isdata):

      self.name = name
      self.label = label
      self.color = eval(color)
      self.location = location if location[-1] == '/' else location + '/'
      self.xSection = xsection
      self.isData = isdata
      self.ftpaths = []
      self.ftfiles = []
      self.ttrees = []
      self.count = 0.0

      for _file in os.listdir(self.location):
        if '.root' not in _file: continue
        ftfile = TFile(location + _file)
        ttree = ftfile.Get('Events')
        self.ftpaths.append(location + _file)
        self.ftfiles.append(ftfile)
        self.ttrees.append(ttree)

      if not self.isData:
        gw = 0.
        for i,ttree in enumerate(self.ttrees):
          for j in ttree:
            gw = abs(j.genWeight)
            if gw: break
          try:
              self.count = self.count + self.ftfiles[i].Get('sumWeights').GetBinContent(1)/(abs(gw))
          except AttributeError:
              self.count = self.count + self.ftfiles[i].Get('sum2Weights').GetBinContent(1)/(abs(gw)*abs(gw))
      else:
        for ttree in self.ttrees:
          self.count = self.count + ttree.GetEntries()

      if not self.isData:
        self.lumWeight = self.xSection / self.count

      #print('Name: ', self.name, self.label)
      #print('Cross-section: ', self.xSection)
      #print('Count: ', self.count)
      #print('lumWeight: ', self.lumWeight)


   def printSample(self):
      print("#################################")
      print("Sample Name: ", self.name)
      print("Sample Location: ", self.location)
      print("Sample XSection: ", self.xSection)
      print("Sample IsData: ", self.isData)
      print("Sample LumWeight: ", self.lumWeight)
      print("#################################")


   def closeFiles(self):
       for _file in self.ftfiles:
              _file.Close()


   def getTH1F(self, lumi, name, var, nbin, xmin, xmax, cut, options, xlabel):

      ofBin = True
      ylabel = 'Events'
      if(xmin == xmax):                                          
          _nbins = len(nbin)-1
          _arr = array('d', nbin)
          h = TH1F(name+'_noOF', "", _nbins, _arr)
          _newarr = _arr + array('d', [ 2*_arr[-1]-_arr[-2] ])
          h_of = TH1F(name, "", _nbins+1, _newarr)                                     
      else:
           h = TH1F(name+'_noOF', "", nbin, xmin, xmax)
           bw = float((xmax-xmin)/nbin)
           ylabel = ylabel +"/ " + str(bw) + " GeV"
           h_of = TH1F(name, '', nbin+1, xmin, xmax+bw)
      h.Sumw2()
      h.GetXaxis().SetTitle(xlabel)
      h.GetYaxis().SetTitle(ylabel)

      h_of.Sumw2()
      h_of.GetXaxis().SetTitle(xlabel)
      h_of.GetYaxis().SetTitle(ylabel)

      addCut = ""
      
      if(self.isData == 0):
         cut = cut + "* ( " + str(self.lumWeight*lumi) + " * genWeight/abs(genWeight) " + " )" 

      self.ttree.Project(h.GetName(), var, cut, options)

      for _bin in range(1, h.GetNbinsX()+2):
          h_of.SetBinContent(_bin, h.GetBinContent(_bin))
          h_of.SetBinError  (_bin, h.GetBinError  (_bin))
      return (h_of if ofBin else h)

    
   def getTH2F(self, lumi, name, var, nbinx, xmin, xmax, nbiny, ymin, ymax, cut, options, xlabel, ylabel):
   
     if(xmin == xmax) and (ymax == ymin):
        h = TH2F(name, "", len(nbinx)-1, array('d', nbinx),len(nbiny)-1, array('d', nbiny))
     elif (xmin == xmax):
        h = TH2F(name, "", len(nbinx)-1, array('d', nbinx),nbiny,ymin,ymax)
     elif (ymin == ymax):
        h = TH2F(name, "", nbinx,xmin,xmax,len(nbiny)-1, array('d', nbiny))
     else: 
        h = TH2F(name, "", nbinx, xmin, xmax, nbiny, ymin, ymax)
     h.Sumw2()
     h.GetXaxis().SetTitle(xlabel)
     h.GetYaxis().SetTitle(ylabel)
     
     if(self.isData == 0):
        cut = cut + "* ( " + str(self.lumWeight*lumi) + " * genWeight/abs(genWeight) )" 
     self.ttree.Project(name, var, cut, options) 
     return h

   def getTH3F(self, lumi, name, var, nbinx, xmin, xmax, nbiny, ymin, ymax, nbinz, zmin, zmax, cut, options, xlabel, ylabel, zlabel):
   
     if(xmin == xmax) and (ymax == ymin) and (zmax == zmin):
        h = TH3F(name, "", len(nbinx)-1, array('d', nbinx), len(nbiny)-1, array('d', nbiny), len(nbinz)-1, array('d', nbinz))
     else: 
        h = TH3F(name, "", nbinx, xmin, xmax, nbiny, ymin, ymax, nbinz, zmin, zmax)
     h.Sumw2()
     h.GetXaxis().SetTitle(xlabel)
     h.GetYaxis().SetTitle(ylabel)
     h.GetZaxis().SetTitle(zlabel)
     
     if(self.isData == 0):
        cut = cut + "* ( " + str(self.lumWeight*lumi) + " * genWeight/abs(genWeight) )"
     self.ttree.Project(name, var, cut, options) 
     return h


########################################################################################
########################################################################################
#################################### Block Class #######################################
########################################################################################
########################################################################################
class Block:
   'Common base class for all Sample Blocks'

   def __init__(self, name, label, color, isdata):
      self.name  = name
      self.color = color
      self.isData = isdata
      self.label = label
      self.samples = []

   def printBlock(self):

      print("####################")
      print("Block Name: ", self.name)
      print("Block Color: ", self.color)
      print("Block IsData: ", self.isData)
      print("####################")
      print("This block contains the following Samples")

      for l in self.samples:
        l.printSample()
     

   def addSample(self, s):
      self.samples.append(s)

   def getTH1F(self, lumi, name, var, nbin, xmin, xmax, cut, options, xlabel):
     for _is,s in enumerate(self.samples):
       
       AuxName = "auxT1_sample" + s.name
       haux = s.getTH1F(lumi, AuxName, var, nbin, xmin, xmax, cut, options, xlabel)
       if not _is:
          h = haux.Clone(name+'_blockHisto')
       else:
          h.Add(haux)
       del haux

     h.SetLineColor(self.color)
     h.SetMarkerColor(self.color)
     h.GetYaxis().SetTitle('Events')
     h.SetTitle(self.label)

     return h

   def getTH2F(self, lumi, name, var, nbinx, xmin, xmax, nbiny, ymin, ymax, cut, options, xlabel, ylabel):
     if(xmin == xmax) and (ymax == ymin):
        h = TH2F(name, "", len(nbinx)-1, array('d', nbinx),len(nbiny)-1, array('d', nbiny))
     elif (xmin == xmax):
        h = TH2F(name, "", len(nbinx)-1, array('d', nbinx),nbiny,ymin,ymax)
     elif (ymin == ymax):
        h = TH2F(name, "", nbinx,xmin,xmax,len(nbiny)-1, array('d', nbiny))
     else: 
        h = TH2F(name, "", nbinx, xmin, xmax, nbiny, ymin, ymax)

     h.Sumw2()
     h.GetXaxis().SetTitle(xlabel)
     h.GetYaxis().SetTitle(ylabel)
     
     for s in self.samples:
     
       AuxName = "auxT2_block" + s.name
       haux = s.getTH2F(lumi, AuxName, var, nbinx, xmin, xmax, nbiny, ymin, ymax, cut, options, xlabel, ylabel)
       h.Add(haux)
       del haux

     return h   

   def getTH3F(self, lumi, name, var, nbinx, xmin, xmax, nbiny, ymin, ymax, nbinz, zmin, zmax, cut, options, xlabel, ylabel, zlabel):
     if(xmin == xmax) and (ymax == ymin) and (zmax == zmin):
        h = TH3F(name, "", len(nbinx)-1, array('d', nbinx),len(nbiny)-1, array('d', nbiny),len(nbinz)-1, array('d', nbinz))
     else: 
        h = TH3F(name, "", nbinx, xmin, xmax, nbiny, ymin, ymax, nbinz, zmin, zmax)

     h.Sumw2()
     h.GetXaxis().SetTitle(xlabel)
     h.GetYaxis().SetTitle(ylabel)
     h.GetZaxis().SetTitle(zlabel)
     
     for s in self.samples:
     
       AuxName = "auxT3_block" + s.name
       haux = s.getTH3F(lumi, AuxName, var, nbinx, xmin, xmax, nbiny, ymin, ymax, nbinz, zmin, zmax, cut, options, xlabel, ylabel, zlabel)
       h.Add(haux)
       del haux

     return h   

########################################################################################
########################################################################################
#################################### Tree Class ########################################
########################################################################################
########################################################################################
class Tree:
   'Common base class for a physics meaningful tree'

   def __init__(self, fileName, name, isdata, close = False):
      #print fileName
      self.name  = name
      self.isData = isdata
      self.blocks = []
      self.parseFileName(fileName, close)

   def parseFileName(self, fileName, close = False):
      f = open(fileName)

      for l in f.readlines():
        if (l[0] == "#" or len(l) < 2):
          continue

        splitedLine = str.split(l)
        block       = splitedLine[0]
        theColor    = splitedLine[1]
        name        = splitedLine[2]
        label       = splitedLine[3]
        flocation   = splitedLine[4]
        xsection    = float(splitedLine[5])
        isdata      = int(splitedLine[6])

        color = 0
        plusposition = theColor.find("+")
        if(plusposition == -1):
          color = eval(theColor)
        else:
          color = eval(theColor[0:plusposition])
          color = color + int(theColor[plusposition+1:len(theColor)])

        sample = Sample(name, label, theColor, flocation, xsection, isdata)
        coincidentBlock = [l for l in self.blocks if l.name == block]
        if(coincidentBlock == []):
          newBlock = Block(block, label, color, isdata)
          newBlock.addSample(sample)
          self.addBlock(newBlock)
        else:
          coincidentBlock[0].addSample(sample)

        if close:
            sample.closeFiles()



   def printTree(self):
      print("######")
      print("Tree Name: ", self.name)
      print("Tree IsData: ", self.isData)
      print("######")
      print("This Tree contains the following Blocks")

      for l in self.blocks:
        l.printBlock()
     

   def addBlock(self, b):
      self.blocks.append(b)



   def getYields(self, lumi, var, xmin, xmax, cut):
      h = self.getTH1F(lumi, "yields", var, 1, xmin, xmax, cut, "", "")
      nbinmin = h.FindBin(xmin)
      nbinmax = h.FindBin(xmax)
      error = r.Double()
      value = h.IntegralAndError(nbinmin, nbinmax, error)
      y = [value, error]
      
      del h
      return y


   def getStack(self, lumi, name, var, nbin, xmin, xmax, cut, options, xlabel):
     if cut == '':
       cut = '(1)'
     hs = THStack(name, "")
     SetOwnership(hs, 0 )
     for b in self.blocks:
     
       AuxName = "auxStack_block_" + name + "_" + b.name
       haux = b.getTH1F(lumi, AuxName, var, nbin, xmin, xmax, cut, options, xlabel)
       haux.SetFillColor(b.color)
       haux.SetLineColor(r.kBlack)
       haux.SetTitle(b.label)
       hs.Add(haux)
       del haux


     can_aux = TCanvas("can_%s_%s"%(name, b.name))
     can_aux.cd()
     hs.Draw()

     del can_aux

     ylabel = "Events"
     if xmax != xmin:
       hs.GetXaxis().SetTitle(xlabel)
       b = int((xmax-xmin)/nbin)
       ylabel = "Events / " + str(b) + " GeV"
     else:     
       ylabel = "Events"
   
     hs.GetYaxis().SetTitle(ylabel)
     return hs   


   def getTH1F(self, lumi, name, var, nbin, xmin, xmax, cut, options, xlabel):
     if cut == '':
       cut = '(1)'
     for ib,b in enumerate(self.blocks):
       AuxName = "auxh1_block_" + name + "_" + b.name
       haux = b.getTH1F(lumi, AuxName, var, nbin, xmin, xmax, cut, options, xlabel)
       if not ib:
          h = haux.Clone(name+'_treeHisto')
       else:
          h.Add(haux)
       del haux
       
     return h

   def getTH2F(self, lumi, name, var, nbinx, xmin, xmax, nbiny, ymin, ymax, cut, options, xlabel, ylabel):
     if cut == '':
       cut = '(1)'
     if(xmin == xmax) and (ymax == ymin):
        h = TH2F(name, "", len(nbinx)-1, array('d', nbinx),len(nbiny)-1, array('d', nbiny))
     elif (xmin == xmax):
        h = TH2F(name, "", len(nbinx)-1, array('d', nbinx),nbiny,ymin,ymax)
     elif (ymin == ymax):
        h = TH2F(name, "", nbinx,xmin,xmax,len(nbiny)-1, array('d', nbiny))
     else: 
        h = TH2F(name, "", nbinx, xmin, xmax, nbiny, ymin, ymax)
        
     h.Sumw2()
     h.GetXaxis().SetTitle(xlabel)
     h.GetYaxis().SetTitle(ylabel)
     
     for b in self.blocks:
     
       AuxName = "aux_block" + name + "_" + b.name
       haux = b.getTH2F(lumi, AuxName, var, nbinx, xmin, xmax, nbiny, ymin, ymax, cut, options, xlabel, ylabel)
       h.Add(haux)
       del haux

     return h   

   def getTH3F(self, lumi, name, var, nbinx, xmin, xmax, nbiny, ymin, ymax, nbinz, zmin, zmax, cut, options, xlabel, ylabel, zlabel):
     if cut == '':
       cut = '(1)'
     if(xmin == xmax) and (ymax == ymin) and (zmax == zmin):
        h = TH3F(name, "", len(nbinx)-1, array('d', nbinx),len(nbiny)-1, array('d', nbiny), len(nbinz)-1, array('d', nbinz))
     else: 
        h = TH3F(name, "", nbinx, xmin, xmax, nbiny, ymin, ymax, nbinz, zmin, zmax)
        
     h.Sumw2()
     h.GetXaxis().SetTitle(xlabel)
     h.GetYaxis().SetTitle(ylabel)
     h.GetZaxis().SetTitle(zlabel)
     
     for b in self.blocks:
     
       AuxName = "aux_block" + name + "_" + b.name
       haux = b.getTH3F(lumi, AuxName, var, nbinx, xmin, xmax, nbiny, ymin, ymax, nbinz, zmin, zmax, cut, options, xlabel, ylabel, zlabel)
       h.Add(haux)
       del haux

     return h   


   def Loop(self, lumi, outdir, mode, config, year = '2016', raw = False):

     #
     # Runs a loop over all the events of the trees, of the samples, of the blocks 
     # declared in the Tree, filling the histograms defined in include/processHandler.py
     # and saving them in a file
     #
     # mode: ['plot', 'yield', 'efficiency']

        
     for b in self.blocks:
       for s in b.samples:
         print("Reading samples: " + s.name)
         for t,ttree in enumerate(s.ttrees):
           if s.isData:
             if mode == 'plot':
               process = plotHandler(outdir, self.name, b.name, s.name, t, 1, True, config, year, raw)
             elif mode == 'yield':
               process = yieldHandler(outdir, self.name, b.name, s.name, t, 1, True, config, year, raw)
             elif mode == 'eff':
               process = effHandler(outdir, self.name, b.name, s.name, t, 1, True, config, year, raw)
             else:
               process = processHandler(outdir, self.name, b.name, s.name, t, 1, True, config, year, raw)
           else:
             if mode == 'plot':
               process = plotHandler(outdir, self.name, b.name, s.name, t, lumi*s.lumWeight, False, config, year, raw)
             elif mode == 'yield':
               process = yieldHandler(outdir, self.name, b.name, s.name, t, lumi*s.lumWeight, False, config, year, raw)
             elif mode == 'eff':
               process = effHandler(outdir, self.name, b.name, s.name, t, lumi*s.lumWeight, False, config, year, raw)
             else:
               process = processHandler(outdir, self.name, b.name, s.name, t, lumi*s.lumWeight, False, config, year, raw)
           for n,ev in enumerate(ttree):
             process.processEvent(ev)
           process.Write()


   def launchLoop(self, lumi, outdir, mode, config, queue = 'espresso', year = '2016', raw = False):

     #
     # Launches Loop function in CONDOR:
     # TTree  <----> Job
     # Sample <----> Cluster with x jobs (x = number of TTrees per sample)
     # 

     ## Create identifier to be able to launch multiple tasks at the same time
     # (otherwise they will overwritte)
     idcode = os.popen("date +%H%M").read()
     idcode = idcode.replace('\n', '')
     idcode = '_' + idcode

     outdir = outdir + '/' if outdir[-1] != '/' else outdir # outdir correction

     # Get absdir:
     absdir = ''
     for _p,path in enumerate(os.path.abspath(__main__.__file__).split('/')):
       if _p == len(os.path.abspath(__main__.__file__).split('/')) - 1: break
       absdir += path + '/'

     # Get command to launch:
     command = 'python {0}runLoop.py -f {1} -o {2} -n {3} -b {4} -s {5} -t {6} -l {7} -c {8} -y {9} -m {10} '
     if raw:
         command += '-r '


     # Get cmssw release:
     cmssw = ''
     for level in absdir.split('/'):
            cmssw += level + '/'
            if 'CMSSW' in level:
                cmssw += 'src'
                break

     # Get bash file template:
     bashfile = """#!/bin/bash
pushd {0}
eval `scramv1 runtime -sh`
pushd
{1}""".format(cmssw, '{0}')

     # Get condor submission file template:
     subfile = """
universe                = vanilla
executable              = {1}
arguments               = $(ProcId)
output                  = {2}.out
error                   = {2}.err
log                     = {2}.log
Notify_user             = fernance@cern.ch
+JobFlavour = "{0}" 
queue {3}
""".format(queue, '{0}', '{1}', '{2}')

     for b in self.blocks:
       for s in b.samples:
         for t,ttree in enumerate(s.ttrees):

           if s.isData:
               scommand = command.format(absdir, s.ftpaths[t], outdir, self.name, b.name, s.name, str(t), str(1.0), config, year, mode)
               scommand += '-d'
           else:
               scommand = command.format(absdir, s.ftpaths[t], outdir, self.name, b.name, s.name, str(t), str(lumi*s.lumWeight), config, year, mode)

           #print(scommand)


           ## Bash file
           if not os.path.exists(absdir + 'bash' + idcode + '/'): os.makedirs(absdir + 'bash' + idcode + '/')
           _bashname = absdir + 'bash' + idcode + '/' + 'bash_{0}_{1}_{2}_{3}.sh'.format(self.name, b.name, s.name, str(t))
           _bashfile = open(_bashname, 'w')
           _bashfile.write(bashfile.format(scommand))
           _bashfile.close()

         ## Submission file
         if not os.path.exists(absdir + 'sub' + idcode + '/'): os.makedirs(absdir + 'sub' + idcode + '/')
         _subname = absdir + 'sub' + idcode + '/' +'sub_{0}_{1}_{2}.sh'.format(self.name, b.name, s.name)
         _bashtemplate = absdir + 'bash' + idcode + '/' + 'bash_{0}_{1}_{2}_$(ProcId).sh'.format(self.name, b.name, s.name)
         _subfile = open(_subname, 'w')
         _subtext = subfile.format(_bashtemplate, outdir + '{0}_{1}_{2}_$(ProcId)'.format(self.name, b.name, s.name, str(t)), str(len(s.ttrees)))
         _subfile.write(_subtext)
         _subfile.close()

         ## Launch and clear
         os.system('chmod +x ' + _bashname)
         os.system('chmod +x ' + _subname)
         os.system('condor_submit ' + _subname + ' -batch-name ' + s.name + idcode)
         #os.system('rm ' + _subname)


   def getTH1FsFromDir(self, inputdir):

     #
     # Function to get the histo list available in a dir with root files
     # by exploring the content of the first file.
     #

     absdir = inputdir if inputdir[-1] == '/' else inputdir + '/'

     for _f in os.listdir(absdir):
       if '.root' in _f:
         file0 = absdir + _f
         break

     _tf = r.TFile(file0)

     histos = []
     for _key in _tf.GetListOfKeys():
       key = _key.GetName()
       ktype = str(type(_tf.Get(key)))
       if 'TH1F' in ktype:
         histos.append(key.split('__')[0])

     print(histos)
     return histos


   def getLoopStack(self, inputdir, hname, doOF = True):
     
     ## Correct input dir absolute path:
     inputdir = inputdir + '/' if inputdir[-1] != '/' else inputdir

     ## Init Stacked histograms:
     hstack = THStack(hname + "_stacked", "")
     SetOwnership(hstack, 0)

     for b in self.blocks:
 
       for si,s in enumerate(b.samples):
  
         ## Init Sample histogram:
         _f0 = r.TFile(inputdir + '{0}__{1}__{2}__0.root'.format(self.name, b.name, s.name))
         hsample = copy.deepcopy(_f0.Get(hname + '__{0}__{1}__{2}__0'.format(self.name, b.name, s.name)))
         if doOF: hsample.SetBinContent(hsample.GetNbinsX(), hsample.GetBinContent(hsample.GetNbinsX()) + hsample.GetBinContent(hsample.GetNbinsX() + 1) )
         _f0.Close()

         ## Constuct Sample histogram:
         for t in range(0, len(s.ttrees)):
           if t == 0: continue
           _ft = r.TFile(inputdir + '{0}__{1}__{2}__{3}.root'.format(self.name, b.name, s.name, str(t)))
           _haux = _ft.Get(hname + '__{0}__{1}__{2}__{3}'.format(self.name, b.name, s.name, str(t)))

           try:
               _h = _haux.Clone()
               if doOF: _h.SetBinContent(_h.GetNbinsX(), _h.GetBinContent(_h.GetNbinsX()) + _h.GetBinContent(_h.GetNbinsX() + 1) )
               hsample.Add(_h)
           except ReferenceError:
               print(hname + '__{0}__{1}__{2}__{3}'.format(self.name, b.name, s.name, str(t)) + ' cannot be accesed: Skipping')
               pass
           _ft.Close()

         ## Add sample histogram to block histogram:
         if not si: 
           hblock = hsample.Clone()
           hblock.SetTitle(b.label)
           SetOwnership(hblock, 0)
           hblock.SetFillColor(b.color)
           hblock.SetLineColor(r.kBlack)
         else: 
           hblock.Add(hsample)

       ## Add block histogram to stack histogram:
       hstack.Add(hblock)


     can_aux = TCanvas("can_{0}".format(hname))
     can_aux.cd()
     hstack.Draw('')

     ## Get some values:
     xmin = float(hstack.GetXaxis().GetXmin())
     xmax = float(hstack.GetXaxis().GetXmax())
     nbin = hstack.GetXaxis().GetNbins()

     ## Correct y axis
     ylabel = "Events"
     b = (xmax-xmin)/float(nbin)
     ylabel = "Events / " + "{:.2f}".format(b) + " units"
     hstack.GetYaxis().SetTitle(ylabel)
     hstack.GetXaxis().SetTitle(hsample.GetXaxis().GetTitle())

     return hstack 

   
   def getLoopTH1F(self, inputdir, hname, doOF = True):
     
     ## Correct input dir absolute path:
     inputdir = inputdir + '/' if inputdir[-1] != '/' else inputdir

     ## Init histogram:
     _f0 = r.TFile(inputdir + '{0}__{1}__{2}__0.root'.format(self.name, self.blocks[0].name, self.blocks[0].samples[0].name))
     hth1f = copy.deepcopy(_f0.Get(hname + '__{0}__{1}__{2}__0'.format(self.name, self.blocks[0].name, self.blocks[0].samples[0].name)))
     if doOF: 
         hth1f.SetBinContent(hth1f.GetNbinsX(), hth1f.GetBinContent(hth1f.GetNbinsX()) + hth1f.GetBinContent(hth1f.GetNbinsX() + 1) )
         hth1f.SetBinError(hth1f.GetNbinsX(), hth1f.GetBinError(hth1f.GetNbinsX()) + hth1f.GetBinError(hth1f.GetNbinsX() + 1) )
     _f0.Close()
     SetOwnership(hth1f, 0)

     ## Loop over files:
     for _b,b in enumerate(self.blocks):
       for _s,s in enumerate(b.samples):
         for t in range(0, len(s.ttrees)):
           if t == 0 and _s == 0 and _b == 0: continue
           _ft = r.TFile(inputdir + '{0}__{1}__{2}__{3}.root'.format(self.name, b.name, s.name, str(t)))
           _haux = _ft.Get(hname + '__{0}__{1}__{2}__{3}'.format(self.name, b.name, s.name, str(t)))
           try:
               _h = _haux.Clone()
               if doOF: 
                   _h.SetBinContent(_h.GetNbinsX(), _h.GetBinContent(_h.GetNbinsX()) + _h.GetBinContent(_h.GetNbinsX() + 1) )
                   _h.SetBinError(_h.GetNbinsX(), _h.GetBinError(_h.GetNbinsX()) + _h.GetBinError(_h.GetNbinsX() + 1) )
               hth1f.Add(_h)
           except ReferenceError:
               print(hname + '__{0}__{1}__{2}__{3}'.format(self.name, b.name, s.name, str(t)) + ' cannot be accesed: Skipping')
               pass
           _ft.Close()

     ## Get some values:
     xmin = float(hth1f.GetXaxis().GetXmin())
     xmax = float(hth1f.GetXaxis().GetXmax())
     nbin = hth1f.GetXaxis().GetNbins()

     ## Correct y axis
     ylabel = "Events"
     b = (xmax-xmin)/float(nbin)
     ylabel = "Events / " + "{:.2f}".format(b) + " units"
     hth1f.GetYaxis().SetTitle(ylabel)

     return hth1f


   def getLoopTH2F(self, inputdir, hname):
     
     ## Correct input dir absolute path:
     inputdir = inputdir + '/' if inputdir[-1] != '/' else inputdir

     ## Init histogram:
     _f0 = r.TFile(inputdir + '{0}__{1}__{2}__0.root'.format(self.name, self.blocks[0].name, self.blocks[0].samples[0].name))
     hth2f = copy.deepcopy(_f0.Get(hname + '__{0}__{1}__{2}__0'.format(self.name, self.blocks[0].name, self.blocks[0].samples[0].name)))
     _f0.Close()
     SetOwnership(hth2f, 0)

     ## Loop over files:
     for _b,b in enumerate(self.blocks):
       for _s,s in enumerate(b.samples):
         for t in range(0, len(s.ttrees)):
           if t == 0 and _s == 0 and _b == 0: continue
           _ft = r.TFile(inputdir + '{0}__{1}__{2}__{3}.root'.format(self.name, b.name, s.name, str(t)))
           _haux = _ft.Get(hname + '__{0}__{1}__{2}__{3}'.format(self.name, b.name, s.name, str(t)))
           try:
               _h = _haux.Clone()
               hth2f.Add(_h)
           except ReferenceError:
               print(hname + '__{0}__{1}__{2}__{3}'.format(self.name, b.name, s.name, str(t)) + ' cannot be accesed: Skipping')
               pass
           _ft.Close()

     return hth2f



