#if !defined(__CINT__) || defined(__MAKECINT__)

#include <PamLevel2.h>

#include <TTree.h>
#include <TChain.h>
#include <TFile.h>
#include <TList.h>
#include <TROOT.h>
#include <TString.h>
#include <TBenchmark.h>
#include <TFriendElement.h>
#include <TObjectTable.h>

#include <stdlib.h>
#include <iostream>
using namespace std;

#endif

//===================================
// global variables
//===================================
PamLevel2 *event = NULL;
TChain    *tree  = NULL;
TFile     *outfh = NULL;
TFile     *outft = NULL;
TTree     *otree = NULL;

bool fillTree   = false;
bool fillHistos = false;

//====================================
// Functions to be provided externally
//====================================
bool Select(PamLevel2*);
void CreateHistos(TFile *);
void FillHistos(PamLevel2*);
void SaveHistos(TFile *);

//==========================================
//000000000000000000000000000000000000000000
//==========================================
bool Begin(){
	
    //------------------------
    //  load magnetic field
    //------------------------
    TString fieldpath = gSystem->Getenv("PAM_CALIB");
    if(fieldpath.IsNull()){
	cout << " **ERROR** : No PAMELA environment variables defined "<<endl;
	return 0;
    }
    fieldpath.Append("/trk-param/field_param-0/");
    event->LoadField(fieldpath.Data());


    //------------------------------
    //  create output histos/trees
    //------------------------------
    if(fillHistos) CreateHistos(outfh);
    if(fillTree){
//	outft->cd();
//	event->CreateCloneTrees(tree,outft);
	event->CreateCloneTrees(outft);
    }
//    gDirectory->ls();

    cout << "\nBegin() - done\n\n";
    return 1;
	
}
//==========================================
//000000000000000000000000000000000000000000
//==========================================

bool Process(int iev){

    
    if( !Select(event) )return false;
//    cout <<event->TrkLevel2::ntrk()<<endl;


    if(fillTree)event->FillCloneTrees();
    if(fillHistos)FillHistos(event);

    return true;

}
//==========================================
//000000000000000000000000000000000000000000
//==========================================

bool Finish(){
    
    if(fillTree){
	outft->cd();
	event->WriteCloneTrees();
	outft->Close();
    }
    if(fillHistos){
	SaveHistos(outfh);
	outfh->Close();
    }
    
    cout << "Finish() - done\n";
    
    return 1;
}

//==========================================
//000000000000000000000000000000000000000000
//==========================================
Int_t Loop(TString ddir,TString list, ULong64_t nmax, TString options, TString outfile){

//    gObjectTable->Print();
	
    if(options.Contains("fillTree"))fillTree=true;
    if(options.Contains("fillHisto"))fillHistos=true;

//  -------------------
//  create output files
//  -------------------
    TString outfile_t =0;
    TString outfile_h =0;
    if( outfile.IsNull() ){
	if(!list.IsNull())outfile = list(0,list.Last('.'));	    
	else outfile = "output";	    
    }else{	
	if(outfile.Contains(".root"))outfile = outfile(0,outfile.Last('.'));
    }
    if(fillTree){
	outfile_t = outfile;
	outfile_t.Append("-tree.root");
	outft = (TFile*)gROOT->FindObject(outfile_t); if (outft) outft->Close();
	outft = new TFile(outfile_t,"RECREATE");
	if(outft->IsZombie()){
	    cout << "Output file could not be created\n";
	    return 1;
	};
	cout << "Created output file: "<<outft->GetName()<<endl;
    }
    if(fillHistos){
	outfile_h = outfile;
	outfile_h.Append("-histo.root");
	outfh = (TFile*)gROOT->FindObject(outfile_h); if (outfh) outfh->Close();
	outfh = new TFile(outfile_h,"RECREATE");
	if(outfh->IsZombie()){
	    cout << "Output file could not be created\n";
	    return 1;
	};
	cout << "Created output file: "<<outfh->GetName()<<endl;
    }
    
//  --------------------
//  read input file/list
//  --------------------
    event = new PamLevel2();
    if(list.Contains(".root")){
	stringstream command;
	command.str("");
	command << " echo "<<list<<" > list-temp.txt";
	cout << command.str().c_str() << endl;
	gSystem->Exec(command.str().c_str());
	tree  = event->GetPamTree(ddir,"list-temp.txt",options);
    }else{	 
	tree  = event->GetPamTree(ddir,list,options);
    };
    tree->SetCacheSize(0);

//  ---------------
//  initializations
//  ---------------
    if( !Begin() )return 0;;

//  -----------------
//  loop over events
//  -----------------
    ULong64_t nevents = tree->GetEntries();	
    if(!nmax)nmax = numeric_limits<ULong64_t>::max();	
    if(nevents < nmax)nmax=nevents;
    
    cout << endl<<" Start loop over events:  "<< nmax<<endl;
    Int_t ntrk = 0;
    Int_t sel  = 0;
    Int_t get  = 0;
    TBenchmark *benchmark = new TBenchmark();
    benchmark->Start("event-loop");
    
    TString current_file = "";
//    gObjectTable->Print();
    for(ULong64_t iev=0; iev<nmax; iev++){
	
	event->Clear();
	if( tree->GetEntry(iev) ){
	    get++;
	    if( Process(iev) ){
		sel++;
		if(event->TrkLevel2::ntrk() >0)ntrk++;	
	    }
	    if(current_file.CompareTo(tree->GetFile()->GetName())){
		current_file=tree->GetFile()->GetName();
		cout << iev<< " -> "<< current_file << endl;
//	    cout << tree->GetFile()->GetName() << endl;
	    };
//	    if( fillTree && !(sel%10000) )
// 	    if(event->TrkLevel2::ntrk() >0)ntrk++;	
	}else{
	    cout << "Chain entry "<<iev<<" -- ERROR --"<<endl;
	};
//	if(!(iev%100))cout << iev << endl;
	
    };
    benchmark->Show("event-loop");
    cout << sel <<" selected events over "<<get;
    if(get)cout<<" ("<< 100*sel/get<<"%)"<<endl;
//    cout << "Fitted tracks: "<<ntrk<<endl;
//    gObjectTable->Print();
//  --------------
//  close and exit
//  --------------
    Finish();

    return 0;
    
}

/////////////////////////////////////////////////////////////////

#if !defined(__CINT__) 

// input parameters
Bool_t    DEBUG;
TString   DIR;
TString   LIST;
TString   OPTIONS;
ULong64_t MAXEV;
TString   OUTFILE;

void usage(){

    cout << "------------------------------------------------------------"<<endl;
    cout << "Loop over events (on one or more Level2-files), applying some selection cuts (defined in My-Selection.cpp), \n";
    cout << "creating output histograms (defined in My-Histos.cpp) and/or trees with selected events. \n \n ";
    cout << "USAGE:"<<endl;
    cout << "-processDir  DIR     -  Level2 data directory \n";
    cout << "-processList LIST    -  list  of files (.txt) or single file (.root) to be analysed \n";
    cout << "-outputFile  PATH    -  name of the output file \n";
    cout << "-NumEvents   XXX     -  number of events to be analysed \n";
    cout << "--debug, -g          -  debug mode \n";
    cout << "--help, -h           -  print this help \n";
    cout << "-options [ options ] -  options: \n";
    cout << "                        fillHistos --> create an output file with histograms  \n";
    cout << "                        fillTree   --> create an output file with trees storing the selected events \n ";
    cout << "                        +(-)ALL    --> inlcude(exclude) all trees and branches \n "   ;
    cout << "                        +(-)TRK1 +(-)TRK2 +(-)CAL1 +(-)CAL2 +(-)TOF +(-)TRG +(-)ND +(-)S4 +(-)ORB --> inlcude(exclude) trees and branches  \n"  ; 
    cout << "------------------------------------------------------------"<<endl;
}
//
int HandleInputPar(int argc, char **argv){

    if(argc>1){
		
	if(!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") ){
	    usage();
	    return(1);
	};
// -----------------------
// Read input parameters
// -----------------------  
	DEBUG   = false;
	DIR     = gSystem->WorkingDirectory();
	LIST    = "";
	OUTFILE = "";
	OPTIONS = "+ALL fillTree";
	MAXEV   = 0;	
		

	for (int i = 1; i < argc; i++){		
	    // -----------------------------------------------------//
	    if (!strcmp(argv[i], "-processDir")){
		if (++i >= argc) throw -1;
		DIR = argv[i];
		cout << "processDir "<<DIR<<endl;
		continue;
	    }
	    // -----------------------------------------------------//
	    else if (!strcmp(argv[i], "-processList")){
		if (++i >= argc) throw -1;
		LIST = argv[i];
		cout << "processList "<<LIST<<endl;
		continue;
	    }  
	    // -----------------------------------------------------//
	    else if (!strcmp(argv[i], "-outputFile")){
		if (++i >= argc) throw -1;
		OUTFILE = argv[i];
		cout << "outputFile "<<OUTFILE<<endl;
		continue;
	    }  
	    // -----------------------------------------------------//
	    else if (!strcmp(argv[i], "-NumEvents")){
		if (++i >= argc) throw -1;
		MAXEV = atoi(argv[i]);
		cout << "NumEvents "<<MAXEV<<endl;
		continue;	
	    }
	    // -----------------------------------------------------//
	    else if (!strcmp(argv[i], "-options")){
		if (++i >= argc) throw -1;
		OPTIONS = argv[i];
		if( OPTIONS.Contains("[") ){
		    do{
			if (++i >= argc) throw -1;
			OPTIONS.Append(argv[i]);
		    }while(!OPTIONS.Contains("]"));
		}else cout << "wrong option format --> ignoring " << endl;
	    }
	    // -----------------------------------------------------//
	    else if (!strcmp(argv[i], "--debug") || !strcmp(argv[i], "-g")){
		DEBUG = true;
		continue;	
	    }
	    // -----------------------------------------------------//
	    else{
		cout << "Unidentified input parameter. Ignored."<< endl;
	    };
	};
    }else{
	usage();
	return(1);
    };
// -----------------------
// Check input parameters
// -----------------------  
	
		
    return(0);
	
};
// 

int main(int argc, char **argv)
{
	
    if( HandleInputPar(argc,argv) )return(1);
	
//    Loop(DIR,LIST,MAXEV,"-ALL+TRK1+TRK2+CAL1+CAL2+TOF+AC",OUTFILE);
    cout << "OPTIONS "<<OPTIONS<<endl;
    Loop(DIR,LIST,MAXEV,OPTIONS,OUTFILE);
    
    cout << "Back to main - end"<<endl;
    
    return 0;
	
};

#endif
