/**
 * \file TrackerLevel2.cpp
 * \author Elena Vannuccini
 */
#include <stdlib.h>
#include <iostream>
#include <TSQLServer.h>
#include <TSystem.h>
#include <TSystemDirectory.h>
#include <TString.h>
//
#include <TrkCore.h>
#include <TrkVerl2.h>
//
using namespace std;
bool DEBUG;

/**
 * The program handles input parameters, open the connection to the DB and call the TrkCore() routine.
 */
int main(int argc, char *argv[]){
    
    try{ 
		
	TSQLServer *dbc = 0;
	TFile     *f2       = 0;
// -----------------------
// Default input parameters
// -----------------------
	DEBUG = 0;
	ULong64_t run = 0;
	int get1 = 0;
	int get2 = 1;
	bool standalone = false;
	TString frame2 = "root";
	TString frame1 = "hbook";
	TString file1 ; 
	TString file2 ;
	TString outdir =  gSystem->WorkingDirectory(); // "./"; 
	TString pfolder = "/TrackerFolder"; 
	TString host = "mysql://localhost/pamelaprod";
	TString user = "anonymous";
	TString psw = "";	
	
	if(argc<2)throw -1;
// -----------------------------
// program help and version info
// -----------------------------	
	if ( !strcmp(argv[1],"--version")  ){
	    TrkInfo(true);
	    return(0);
//  ----------------------------------------------------------------
	} else if ( !strcmp(argv[1],"-h") || !strcmp(argv[1],"--help") ){
		printf( "\n\n USAGE\n\n TrackerLevel2 -idRun xxxxx [options] \n \n");
		printf( "\n --version          : Print tracker software version and exit ");	
		printf( "\n --help, -h         : Print this help and exit \n");	
		printf( "\n -idRun RUN         : ID number of the run to be processed (for reprocessing RUN=0) \n");
		printf( "\n -outDir OUTDIR     : Path where to put the LEVEL2 output                    [default ./ ] ");
		printf( "\n -processFolder DIR : Directory (relative to OUTDIR) for other output files  [default TrackerFolder/ ] ");
		printf( "\n -processFile FILE  : Name of the LEVEL2 output file                         [default RUN.Level2.root]");
		printf( "\n -processFile1 FILE : Name of the LEVEL1 output file                         [default RUN.Level1.rz]");
		printf( "\n -frame1 FRAME      : type of output for LEVEL1, root/hbook                  [default hbook ] ");
		printf( "\n -frame2 FRAME      : type of output for LEVEL2, root/hbook                  [default root  ] ");		
		printf( "\n --get1             : flag to get LEVEL1 output                              [default (no LEVEL1 output) ]  ");
		printf( "\n --dontget2         : flag to do not get LEVEL2 output                       [default (get LEVEL2 output)]");
		printf( "\n --verbose, -v      : Run the program in debug mode ");	
		printf( "\n --standalone, -s   : Run the program in standalone mode (without RunInfo) \n");	
		printf( "\n -host HOST         : Name for the host                                      [default mysql://localhost/pamelaprod ]");
		printf( "\n -user USER         : Username for the DB                                    [default anonymous] ");
		printf( "\n -psw  PSW          : Password for the DB                                    [default (none)]\n \n \n");
		exit(-12);
		//  ----------------------------------------------------------------
	}

//	cout << "bbb "<< gDirectory->pwd()<< endl;
	
// -----------------------
// Read input parameters
// -----------------------  
	TString input_parameters=0;
	int ncustom =0;
	char* vcustom[30];
	for (int i = 1; i < argc; i++){		
//		cout << i << " "<< argv[i] << endl;
	    vcustom[ncustom] = argv[i];
	    ncustom++;
    	// -----------------------------------------------------//
	    if (!strcmp(argv[i], "-idRun")){
		if (++i >= argc) throw -1;
		run = atoi(argv[i]);
		continue;
	    }
	    // -----------------------------------------------------//
	    else if (!strcmp(argv[i], "-outDir")){
		if (++i >= argc)throw -3;
		outdir = argv[i];
		continue;
	    }  
	    // -----------------------------------------------------//
	    else if (!strcmp(argv[i], "-processFolder")){
		if (++i >= argc) throw -3;
		pfolder = argv[i];
		continue;
	    }  
	    // -----------------------------------------------------//    
	    else if (!strcmp(argv[i], "-processFile")){
		if (++i >= argc) throw -3;
		get2 = 1;
		file2 = argv[i];
		continue;
	    }  
	    // -----------------------------------------------------//    
	    else if (!strcmp(argv[i], "--get1")){
		get1 = 1;
		continue;
	    }  
	    //-----------------------------------------------------//    
	    else if (!strcmp(argv[i], "--dontget2")){
		get2 = 0;
		continue;
	    }  
	    //-----------------------------------------------------//    
	    else if (!strcmp(argv[i], "--standalone") || !strcmp(argv[i], "-s")){
		standalone = true;
		continue;
	    }  
	    //-----------------------------------------------------//    
	    else if (!strcmp(argv[i], "-processFile1")){
		if (++i >= argc) throw -3;
		get1 = 1;
		file1 = argv[i];
		continue;
	    }  
	    //-----------------------------------------------------//    
	    else if (!strcmp(argv[i], "-frame1")){
		if (++i >= argc)throw -3;
		get1 = 1;
		frame1 = argv[i];
		continue;
	    }  
	    //-----------------------------------------------------//    
	    else if (!strcmp(argv[i], "-frame2")){
		if (++i >= argc)throw -3;
		get2 = 1;
		frame2 = argv[i];
		continue;
	    }  
	    // -----------------------------------------------------//    
	    else if (!strcmp(argv[i], "-host")){
		if (++i >= argc)throw -3;
		host = argv[i];
		continue;
	    }
	    // -----------------------------------------------------//    
	    else if (!strcmp(argv[i], "-user")){
		if (++i >= argc)throw -3;
		user = argv[i];
		continue;
	    } 
	    // -----------------------------------------------------//    
	    else if (!strcmp(argv[i], "-psw")){
		if (++i >= argc)throw -3;
		psw = argv[i];
		continue;
	    }
	    //-----------------------------------------------------//    
	    else if (!strcmp(argv[i], "--verbose") || !strcmp(argv[i], "-v")){
		DEBUG = 1;
		continue;
	    }else{
	    };
	}
	
	
// -----------------------
// Handle input parameters
// -----------------------
// check  patameter consistency	
//	if(run == -1 || (run < 0 && run != 0)) throw -1;      
	if( get1 == 0 && get2 == 0) throw -202;  
	if( get1 == 1 && get2 == 0 && run == 0) throw -204; 
	if( standalone && run == 0) throw -298; 
// compose outputfile names	
/*	if(get1){		
		TString filety;
		if      (!frame1.CompareTo("root", TString::kIgnoreCase))  filety=".root";		
		else if (!frame1.CompareTo("hbook", TString::kIgnoreCase)) filety=".rz";
		else    throw -200;
		if(file1.IsNull()){
		    file1 += run; 
		    file1 += ".Level1";
		    file1 += filety;
		}else if (!file1.Contains(filety.Data())) file1 += filety;
		file1 = outdir + "/"+ pfolder + "/" + file1;
	};*/
	if(get2){
		if(run == 0 && file2.IsNull()) throw -4;
		TString filety;
		if      (!frame2.CompareTo("root", TString::kIgnoreCase))  filety=".root";		
		else if (!frame2.CompareTo("hbook", TString::kIgnoreCase)) filety=".rz";
		else    throw -201;
		if(file2.IsNull()){
		    file2 += (Int_t)run; 
		    file2 += ".Level2";
		    file2 += filety;
		}else if (!file2.Contains(filety.Data())) file2 += filety;
		file2 = outdir + "/" + file2;
		f2= new TFile(file2,"UPDATE");
		if ( !f2->IsOpen() ) throw -204;

	};
    
	if(DEBUG){
	    cout << endl << "Input parameters: " << endl;
	    cout << "idRun         "<< run << endl;
	    cout << "get1          "<< get1 << endl;
	    cout << "get2          "<< get2 << endl;
	    cout << "LEVEL1 output "<< file1 << endl;
	    cout << "LEVEL2 output "<< file2 << endl;
	    cout << "host          "<< host << endl;
	    cout << "user          "<< user << endl;
	    cout << "password      "<< psw << endl;
	}
// -----------------------
// connect to the database
// -----------------------
	if(DEBUG) printf("\nConnecting to database... \n"); 
//    dbc = TSQLServer::Connect("mysql://localhost/pamelaprod","anonymous","");
	dbc = TSQLServer::Connect(host,user,psw);
	Bool_t connect = dbc->IsConnected();
	if( !connect ) throw -2;
	if(DEBUG) printf("...connected! \n\n");
// -------------------------
// CALL REDUCTION ROUTINE
// -------------------------
//    TrkCore(run,dbc,file1,file2,standalone);
	TrkCore(run,f2,dbc,ncustom,vcustom);
// -----------------------
// close connection to db
// -----------------------
	if(DEBUG) printf("\nClose the connection to the database... \n");
	dbc->Close(); 
	if(DEBUG) printf("...connection terminated!\n\n");   
	
	if(get2)f2->Close();
	
	return 0;
    }
    catch(int e){
	
	TString message;
	switch(e){
	case -1:   message += "Missing/wrong run ID input parameter"; break;
	case -2:   message += "DB connection failure"; break;
	case -3:   message += "Error in input parameters (check format)"; break;
	case -4:   message += "Request reprocessing of all runs (idRun = 0) but processFile is missing"; break;
	case -6:   message += "No LEVEL0 file "; break;
	case -7:   message += "No \"Physics\" tree in LEVEL0 file"; break;
	case -8:   message += "No \"Header\" branch in LEVEL0 \"Physics\" tree"; break;
	case -9:   message += "No \"Registry\" branch in LEVEL0 \"Physics\" tree"; break;
	case -11:  message += "LEVEL0 \"Physics\" tree is empty"; break;
	case -12:  message += "LEVEL2 output directory does not exists"; break;
	case -13:  message += "Cannot create processFolder directory"; break;
	
	case -50:  message += "No entries matching GL_RUN query"; break;
	case -51:  message += "No entries matching GL_ROOT query"; break;
	case -52:  message += "No entries matching GL_PARAM query"; break;
	case -53:  message += "No entries matching GL_TRK_CALIB query"; break;
	case -54:  message += "No entries matching GL_CALO_CALIB query"; break;
	
	
	case -200: message += "LEVEL1 framework unknown (HBOOK/ROOT)"; break;
	case -201: message += "LEVEL2 framework unknown (HBOOK/ROOT)"; break;
	case -202: message += "Neither LEVEL1 nor LEVEL2 output requested"; break;
	case -203: message += "No \"Tracker\" branch in LEVEL0 \"Physics\" tree"; break;
	case -204: message += "No reprocessing implemented for LEVEL1 output"; break;
	case -205: message += "Error accessing \"RunInfo\" "; break;
	
	case -210: message += "Error opening/reading \"trk mask\" GL_PARAM parameters "; break;
	case -211: message += "Error opening/reading \"trk alignment\" GL_PARAM parameters"; break;
	case -212: message += "Error opening/reading \"trk mip\" GL_PARAM parameters"; break;
	case -213: message += "Error opening/reading \"trk charge\" GL_PARAM parameters"; break;
	case -214: message += "Error opening/reading \"trk pfa\" GL_PARAM parameters"; break;
	case -215: message += "Error opening/reading \"field\" GL_PARAM parameters"; break;
	case -216: message += "Error opening/reading \"default calibration\" GL_PARAM parameters"; break;
	
	case -298: message += "Reprocessing not implemented in standalone mode"; break;
	case -299: message += "Not yet implemented"; break;
	
	default: message += "Unidentified"; break;
	}
	cout << "TrackerLevel2 - ERROR ("<< e << ") "<< message <<endl;
	exit(e);
}
}


