############################################################################
#    Copyright (C) 2006 by Maurizio Nagni   #
#    nagni@roma2.infn.it   #
#                                                                          #
#    This program is free software; you can redistribute it and#or modify  #
#    it under the terms of the GNU General Public License as published by  #
#    the Free Software Foundation; either version 2 of the License, or     #
#    (at your option) any later version.                                   #
#                                                                          #
#    This program is distributed in the hope that it will be useful,       #
#    but WITHOUT ANY WARRANTY; without even the implied warranty of        #
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
#    GNU General Public License for more details.                          #
#                                                                          #
#    You should have received a copy of the GNU General Public License     #
#    along with this program; if not, write to the                         #
#    Free Software Foundation, Inc.,                                       #
#    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             #
############################################################################
#!/usr/bin/env python
# l2manager.py 
# Author: Maurizio Nagni
# Date: 4 February 2006
#
# Description:
# 	First implementation of the L2Manager for the processing of the
# 	PAMELA RUNs up to Level2 data.

import time, os, logging
from ROOT import *
from ngn.pamela.process.L2Process import L2Process


class L2Manager:
	def __init__(self, runs, libpath, logger, dizio, main_tree):
		self.runs 	= runs
		self.libpath 	= libpath
		self.finalFile  = str(time.time()) + '.Level2.root'
		self.runFiles 	= {}
		self.__logger	= logger
		self.__DETECTORS_BRANCHES = dizio
		self.__MAIN_TREE = main_tree
		
	def processRuns(self):
		#Start the jobs
		for RUN in self.runs:
			#define the name of the output file RUN_number.root
			outputRunFileName = 'RUN_' + str(RUN) + '_' + str(time.time()) + '.root'
			
			#define the name of the error output file RUN_number.root
			errorRunFileName = 'RUN_' + str(RUN) + '_' + str(time.time()) + '.err'
			
			# Launch the job related to the RUN
			self.startJob(RUN, outputRunFileName, errorRunFileName)
			
			#Create the dictionary (key, value) = (out, err)
			self.runFiles[outputRunFileName] = errorRunFileName
			
		#Wait for jobs to return files
		toBeControlledList = self.runFiles.copy()
		while(len(toBeControlledList)):
			controlledList = {}
			time.sleep(0.1)

			#Loop on still missing files.
			for outFile, errFile in toBeControlledList.iteritems():
				#The error file have been returned?
				print errFile
				if (os.access(errFile, os.F_OK)):
					self.__logger.debug('Error file ' + errFile + ' \n')

				#The file have been returned?
				print outFile
				if (os.access(outFile, os.F_OK)):
					self.__logger.debug('Run file ' + outFile + ' \n')
					#The file have been correctly processed?
					controlledList[outFile] = errFile
					if not (self.checkConsistence(outFile)):
						#Here should be implemented a more detailed output
						return False
					
			#Remove the already arrived/checked files
			for keyName in controlledList.iterkeys():
				toBeControlledList.pop(keyName)
			
		#Merge with previously returned files.
		self.mergeFile()
		
		self.__logger.debug('L2Manager terminated \n')
		#moveToCastor(finalFile)
	
	
	#Chech if every branch in the file have the same numbers of entries
	def checkConsistence(self, fileName):
		oldEntries = -1
		gSystem.Load(self.libpath)
		file = TFile(fileName)
		if not (file.IsZombie()):
			for detector in self.__DETECTORS_BRANCHES:
				tree       = file.Get(self.__MAIN_TREE)
				branch     = tree.GetBranch(detector)
				newEntries = branch.GetEntries()
				#print 'detector: ' + detector
				#print 'entries for detector ' + detector + ' = ' + str(branch.GetEntries())
				if ((not (oldEntries < 0)) and (newEntries != oldEntries)):
					self.__logger.error('Detector ' + detector + 'seems not not consistent! \n')
					return False
				oldEntries = newEntries
			file.Close()
			return True	

	
	#Submit a job to the LSF/GRID system
	def startJob(self, run, runFileName, errorRunFileName):
		self.__logger.debug('Starting run n.' + str(run) + ' on waiting for return of file: ' + runFileName + '\n')
		print 
		
		#--- versione stand alone-----
		process = L2Process(run, runFileName)
		process.processDetectors()
		#--- versione stand alone-----
		
		#--- versione GRID -----
		# TO BE DONE
		#--- versione GRID -----
		
		#if (the job have been succesfully submitted)
		#---->Log Something
		return True
		#else
		#---->Log Something
		#return False
		
	
	#Merge the TTrees from a collection of similar root files
	def mergeFile(self):
		gSystem.Load(self.libpath)
		chain = TChain('Physics')
		for outFile, errFile in self.runFiles.iteritems():
			chain.Add(outFile)
			
		#Global merge 
		chain.Merge(self.finalFile)

