//
// C/C++ headers
//
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
//
// ROOT headers
//
#include <TString.h>
#include <TTimeStamp.h>
#include <TSQLServer.h>
#include <TFile.h>
#include <TSystem.h>
//
// Detector's package headers
//
#include <GLTables.h>
//
using namespace std;
//
//
//
#include <YodaProfilerVerl2.h>
//
// Usage subroutine
//
void r2d2usage(){
  printf("\nUsage:\n");
  printf("\n R2-D2 [-h | --help] [--version] [-idRun ID_RUN] [-filename filename]\n");
  printf("\n            [-host host] [-user username] [-psw password] \n");
  printf("\n --version        print informations about compilation and exit\n");
  printf("\n -h | --help      print this help and exit \n");
  printf("\n -v | --verbose   be verbose [default: print nothing on STDOUT]\n");
  printf("\n -idRun run       ID_RUN: ID number of the run \n");
  printf("\n -filename file   output yoda filename \n");
  printf("\n -host            name for the host [default = $PAM_DBHOST or mysql://localhost/pamelaprod]\n");
  printf("\n -user            username for the DB [default = $PAM_DBUSER or \"anonymous\"] \n");
  printf("\n -psw             password for the DB [default = $PAM_DBPSW or \"\"]\n");
  printf("\n -tzone timezone  the time zone: UTC,GMT,MSK,MSD,CET,CEST are accepted \n");
  printf("\n -convert dbtime  convert the dbtime given in seconds (from the DB) to a string\n");
  printf("\n -runat date      returns run number which contains the given date,\n");
  printf("\n                  for date use the SQL format \"yyyy-mm-dd hh:mm:ss\" \n");
  printf("\n -runatDB time    returns run number which contains the given DB time\n");
  printf("\n -tsfile file     yoda filename for the time sync (to be used with -obt)\n");
  printf("\n -obt OBT         OBT in ms returns a date (to be used with -tsfile)\n");
  printf("\n -getRTime OBT    OBT in ms returns Resurs time (to be used with -tsfile)\n");
  printf("\n -dumpTLEfor date save into file tle.txt the TLE for the given date,\n");
  printf("\n                  for date use the SQL format \"yyyy-mm-dd hh:mm:ss\" \n");
  printf("\nExamples: \n");
  printf("\n R2-D2 -idRun 1085 \n");
  printf("\n R2-D2 -filename DW_050208_00900.root \n");
  printf("\n R2-D2 -idRun 1085 -filename DW_050208_00900.root \n");
};
//
// Here the main
//
int main(int numinp, char *inps[]){
  //
  // Variables booking
  //
  TString message;
  Int_t error = 0;
  //
  UInt_t run = 0ULL;
  //
  TString filename = "";
  //
  TSQLServer *dbc = 0;
  TString host = "mysql://localhost/pamelaprod";
  TString user = "anonymous";
  TString psw = "";
  //
  const char *pamdbhost=gSystem->Getenv("PAM_DBHOST");
  const char *pamdbuser=gSystem->Getenv("PAM_DBUSER");
  const char *pamdbpsw=gSystem->Getenv("PAM_DBPSW");
  if ( !pamdbhost ) pamdbhost = "";
  if ( !pamdbuser ) pamdbuser = "";
  if ( !pamdbpsw ) pamdbpsw = "";
  if ( strcmp(pamdbhost,"") ) host = pamdbhost;
  if ( strcmp(pamdbuser,"") ) user = pamdbuser;
  if ( strcmp(pamdbpsw,"") ) psw = pamdbpsw;
  //
  //  printf(" host %s user %s psw %s \n",host.Data(),user.Data(),psw.Data());
  //
  TString tzone = "UTC";
  TString runtime = "1970-01-01 00:00:00";
  TString tletime = "1970-01-01 00:00:00";
  UInt_t dbti = 0;
  Bool_t convert = false;
  Bool_t convres = false;
  Bool_t ruti = false;
  Bool_t dtle = false;
  Bool_t ruti2 = false;
  Bool_t convobt = false;
  Bool_t convobtts = false;
  //
  UInt_t runtime2 = 0;
  UInt_t obt = 0;
  UInt_t res = 0;
  TString tsfile = "";
  //
  TSQLResult *pResult;
  TSQLRow *Row;
  int t;
  int r;
  stringstream myquery;
  //
  // Checking input parameters
  //
  Int_t i = 0;
  if ( numinp > 1 ){
    while ( i < numinp ){
      if ( !strcmp(inps[i],"--version") ){
	YodaProfilerInfo(true);
	exit(0);
      };
      if ( !strcmp(inps[i],"-h") || !strcmp(inps[i],"--help") ){
	r2d2usage();
	exit(0);
      };
      if ( !strcmp(inps[i],"-idRun") ) {
	if ( numinp-1 < i+1 ) {
	  r2d2usage();
	  exit(-3);
	};
	run = (UInt_t)atoll(inps[i+1]);	
      };
      if ( !strcmp(inps[i],"-filename") ) {
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	filename = (TString)inps[i+1];	
      };
      if ( !strcmp(inps[i],"-host") ) {
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	host = (TString)inps[i+1];	
      };
      if ( !strcmp(inps[i],"-user") ) {
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	user = (TString)inps[i+1];	
      };
      if ( !strcmp(inps[i],"-psw") ) {
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	psw = (TString)inps[i+1];	
      };
      //
      if ( !strcmp(inps[i],"-tsfile") ) {
	convobtts = true;
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	tsfile = (TString)inps[i+1];	
      };
      //
      if ( !strcmp(inps[i],"-obt") ) {
	convobt = true;
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	obt = (UInt_t)atoll(inps[i+1]);	
      };
      //
     if ( !strcmp(inps[i],"-getRTime") ) {
	convres = true;
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	res = (UInt_t)atoll(inps[i+1]);	
      };
      //
      //
      if ( !strcmp(inps[i],"-tzone") ) {
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	tzone = (TString)inps[i+1];	
      };
      //
      if ( !strcmp(inps[i],"-convert") ) {
	convert = true;
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	dbti = (UInt_t)atoll(inps[i+1]);	
      };
      //
      if ( !strcmp(inps[i],"-runat") ) {
	ruti = true;
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	runtime = (TString)inps[i+1];	
      };
      //
      if ( !strcmp(inps[i],"-dumpTLEfor") ) {
	dtle = true;
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	tletime = (TString)inps[i+1];	
      };
      //
      //
      if ( !strcmp(inps[i],"-runatDB") ) {
	ruti2 = true;
	if ( numinp-1 < i+1 ){
	  r2d2usage();
	  exit(-3);
	};
	runtime2 = (UInt_t)atoll(inps[i+1]);	
      };
      //
      i++;
    };
    //
  } else {
    //
    // no input parameters exit with error, we need at least the run id.
    //
    r2d2usage();
    exit(-2);
  };
  //
  // Connect to the DB
  //
  dbc = TSQLServer::Connect(host.Data(),user.Data(),psw.Data());
  if( !dbc ) throw -2;    
  //
  bool connect = dbc->IsConnected();
  //
  if( !connect ){
    printf(" Error, not connected to DB\n");
    exit(-1);
  };    
  //
  myquery.str("");
  myquery << "SET time_zone='+0:00'";
  dbc->Query(myquery.str().c_str());
  //
  GL_ROOT *glroot = new GL_ROOT();
  GL_RUN *glrun = new GL_RUN();
  GL_TIMESYNC *dbtime = new GL_TIMESYNC();
  //
  // At which date correspond the DB time "dbti"?
  //
  if ( convert ){
    printf("\n DB time %u is %s %s \n",dbti,dbtime->ConvertTime(tzone,dbti).Data(),tzone.Data());
  };
  //
  // convert OBT to date
  //
  if ( convobt && convobtts ){
    UInt_t id = 0;
    myquery.str("");
    myquery << "select ";
    myquery << " ID"; 
    myquery << " from GL_ROOT where NAME=\"" << tsfile.Data() << "\";";    
    pResult = dbc->Query(myquery.str().c_str());
    if ( pResult ){
      Row = pResult->Next();      
      if ( Row ){
	id = (UInt_t)atoll(Row->GetField(0));
	delete pResult;       
	GL_TIMESYNC *ctime = new GL_TIMESYNC(id,"ID",dbc);
	UInt_t abtime = ctime->DBabsTime(obt);
	TString thetime = dbtime->ConvertTime(tzone,abtime);
	printf("\n OBT %u in the file %s corresponds to DBtime %u and date %s %s \n",obt,tsfile.Data(),abtime,thetime.Data(),tzone.Data());
	delete ctime;
      };
    };
  };
  if ( (convobt && !convobtts) ){
    printf("\n To convert a OBT to a date you must provide both OBT and file to be used for time sync \n");
  };
  //
  // convert OBT to Resurs seconds
  //
  if ( convres && convobtts ){
    UInt_t id = 0;
    myquery.str("");
    myquery << "select ";
    myquery << " ID"; 
    myquery << " from GL_ROOT where NAME=\"" << tsfile.Data() << "\";";    
    pResult = dbc->Query(myquery.str().c_str());
    if ( pResult ){
      Row = pResult->Next();      
      if ( Row ){
	id = (UInt_t)atoll(Row->GetField(0));
	delete pResult;       
	GL_TIMESYNC *ctime = new GL_TIMESYNC(id,"ID",dbc);
	UInt_t restime = ctime->ResursTime(res);
	//UInt_t abtime = ctime->DBabsTime(obt);
	//
	//	TString thetime = dbtime->ConvertTime(tzone,abtime);
	printf("\n OBT %u in the file %s corresponds to Resurs time %u  \n",res,tsfile.Data(),restime);
	delete ctime;
      };
    };
  };
  if ( (convres && !convobtts) ){
    printf("\n To convert a OBT to the Resurs time you must provide both OBT and file to be used for time sync \n");
  };
  //
  // Which run contains the date "runtime"?
  //
  if ( ruti ){
    //
    TDatime ti = TDatime(runtime.Data());
    //
    TTimeStamp *time = new TTimeStamp((UInt_t)ti.GetYear(),(UInt_t)ti.GetMonth(),(UInt_t)ti.GetDay(),(UInt_t)ti.GetHour(),(UInt_t)ti.GetMinute(),(UInt_t)ti.GetSecond(),0,true,0);
    //
    UInt_t dbti = time->GetSec();
    //
    TString thetime = dbtime->UnConvertTime(tzone,dbti);
    //
    ti = TDatime(thetime.Data());
    TTimeStamp *time2 = new TTimeStamp((UInt_t)ti.GetYear(),(UInt_t)ti.GetMonth(),(UInt_t)ti.GetDay(),(UInt_t)ti.GetHour(),(UInt_t)ti.GetMinute(),(UInt_t)ti.GetSecond(),0,true,0);
    //
    UInt_t mytime = time2->GetSec();
    //
    Bool_t found = false;
    //
    myquery.str("");
    myquery << "select ";
    myquery << " ID "; 
    myquery << " from GL_RUN where RUNHEADER_TIME<=" << mytime << " AND "
	    << " RUNTRAILER_TIME>=" << mytime  << " ;";
    //    printf("myquery is %s \n",myquery.str().c_str());
    pResult = dbc->Query(myquery.str().c_str());
    for( r=0; r < 1000; r++){ 
      Row = pResult->Next();      
      if( Row == NULL ) break;
      found = true;
      printf("\n Date %s %s (DB time %u ) is contained in run %u \n",runtime.Data(),tzone.Data(),mytime,(UInt_t)atoll(Row->GetField(0)));
    };    
    myquery.str("");
    myquery << "select ";
    myquery << " ID "; 
    myquery << " from GL_RUN_TRASH where BELONGED_TO='GL_RUN' AND RUNHEADER_TIME<=" << mytime << " AND "
	    << " RUNTRAILER_TIME>=" << mytime  << " ;";
    //    printf("myquery is %s \n",myquery.str().c_str());
    pResult = dbc->Query(myquery.str().c_str());
    for( r=0; r < 1000; r++){ 
      Row = pResult->Next();      
      if( Row == NULL ) break;
      printf("\n Date %s %s (DB time %u ) is contained in run %u in the GL_RUN_TRASH table \n",runtime.Data(),tzone.Data(),mytime,(UInt_t)atoll(Row->GetField(0)));
      found = true;
    };    
    //
    if ( !found ){
      printf("\n No run contains date %s %s (DB time %u )\n",runtime.Data(),tzone.Data(),mytime);
    };
    //
  };
  //
  // Which tle must be used for the date "tletime"?
  //
  if ( dtle ){
    //
    //
    TDatime ti = TDatime(runtime.Data());
    //
    TTimeStamp *time = new TTimeStamp((UInt_t)ti.GetYear(),(UInt_t)ti.GetMonth(),(UInt_t)ti.GetDay(),(UInt_t)ti.GetHour(),(UInt_t)ti.GetMinute(),(UInt_t)ti.GetSecond(),0,true,0);
    //
    UInt_t dbti = time->GetSec();
    //
    TString thetime = dbtime->UnConvertTime(tzone,dbti);
    //
    ti = TDatime(thetime.Data());
    TTimeStamp *time2 = new TTimeStamp((UInt_t)ti.GetYear(),(UInt_t)ti.GetMonth(),(UInt_t)ti.GetDay(),(UInt_t)ti.GetHour(),(UInt_t)ti.GetMinute(),(UInt_t)ti.GetSecond(),0,true,0);
    //
    UInt_t mytime = time2->GetSec();
    //
    myquery.str("");
    myquery << " select ID,TLE1,TLE2,TLE3 from GL_TLE where FROM_TIME<='" << time2->AsString("s") << "' ORDER BY FROM_TIME DESC LIMIT 1;";
    //    myquery << " from GL_TLE where FROM_TIME>=" << mytime << " ORDER BY FROM_TIME ASC LIMIT 1;";
    //    printf("myquery is %s \n",myquery.str().c_str());
    pResult = dbc->Query(myquery.str().c_str());
    Row = pResult->Next();      
    if ( !Row ){
      printf("\n No TLE in the DB for date %s %s (DB time %u )\n",tletime.Data(),tzone.Data(),mytime);
    };
    printf("\n Date %s %s (DB time %u ) is contained in TLE %u \n",tletime.Data(),tzone.Data(),mytime,(UInt_t)atoll(Row->GetField(0)));
    printf("\n%s\n",Row->GetField(1));
    printf("%s\n",Row->GetField(2));
    printf("%s\n",Row->GetField(3));
    //
    FILE *tlefile;
    tlefile = fopen("tle.txt","w"); 
    fprintf(tlefile,"%s\n",Row->GetField(1));
    fprintf(tlefile,"%s\n",Row->GetField(2));
    fprintf(tlefile,"%s\n",Row->GetField(3));
    fclose (tlefile);
    //
    printf("\n TLE has been dumped in file tle.txt \n");
  };
  //
  // Which run contains the dbtime "runtime2"?
  //
  if ( ruti2 ){
    //
    UInt_t mytime = runtime2;
    //
    Bool_t found = false;
    myquery.str("");
    myquery << "select ";
    myquery << " ID "; 
    myquery << " from GL_RUN where RUNHEADER_TIME<=" << mytime << " AND "
	    << " RUNTRAILER_TIME>=" << mytime  << " ;";
    //    printf("myquery is %s \n",myquery.str().c_str());
    pResult = dbc->Query(myquery.str().c_str());
    for( r=0; r < 1000; r++){ 
      Row = pResult->Next();      
      if( Row == NULL ) break;
      printf("\n DB time %u is contained in run %u \n",mytime,(UInt_t)atoll(Row->GetField(0)));
      found = true;
    };    
    //
    myquery.str("");
    myquery << "select ";
    myquery << " ID "; 
    myquery << " from GL_RUN_TRASH where BELONGED_TO='GL_RUN' AND RUNHEADER_TIME<=" << mytime << " AND "
	    << " RUNTRAILER_TIME>=" << mytime  << " ;";
    //    printf("myquery is %s \n",myquery.str().c_str());
    pResult = dbc->Query(myquery.str().c_str());
    for( r=0; r < 1000; r++){ 
      Row = pResult->Next();      
      if( Row == NULL ) break;
      printf("\n DB time %u is contained in run %u in the GL_RUN_TRASH table \n",mytime,(UInt_t)atoll(Row->GetField(0)));
      found = true;
    };    
    //
    if ( !found ){
      printf("\n No run contains DB time %u \n",mytime);
    };
    //
  };
  //
  // To which file the run "run" belongs?
  //
  if ( run != 0 ){
    Bool_t found = false;
    glrun->Clear();
    error = glrun->Query_GL_RUN(run,dbc);
    glroot->Clear();
    error = glroot->Query_GL_ROOT(glrun->ID_ROOT_L0,dbc);
    if ( glrun->ID_ROOT_L0 ){
      if ( error ){
	printf(" Error querying the DB! \n");
	exit(-4);
      };
      printf("\n Run %u belongs to file %s \n",run,(glroot->PATH+glroot->NAME).Data());
      found = true;
    };
    //
    myquery.str("");
    myquery << "select ";
    myquery << " ID,FILENAMEL0,FILENAMEL2 "; 
    myquery << " from GL_RUN_TRASH where BELONGED_TO='GL_RUN' AND ID=" << run << "; ";
    pResult = dbc->Query(myquery.str().c_str());
    for( r=0; r < 1000; r++){ 
      Row = pResult->Next();      
      if( Row == NULL ) break;
      printf("\n RUN %u has been deleted and now is contained in the GL_RUN_TRASH table \n",run);
      printf("\n RUN %u belonged to L0 file %s and L2 file %s \n",run,Row->GetField(1),Row->GetField(2));
      found = true;
    };    
    //
    if ( !found ) printf("\n No run with ID=%u in the DB!\n",run);
  };
  //
  // Which runs are contained in the file "filename"?
  //
  if ( strcmp(filename.Data(),"") ){
    // ----------------
    Bool_t found = false;
    Int_t ID = 0;
    Int_t ID_RAW = 0;
    //    
    const char *rawpath = "";
    const char *rawname = "";
    //
    myquery.str("");
    myquery << "select ";
    myquery << " ID"; 
    myquery << ",ID_RAW"; 
    myquery << ",PATH"; 
    myquery << ",NAME"; 
    myquery << " from GL_ROOT where NAME=\"" << filename.Data() << "\";";    
    pResult = dbc->Query(myquery.str().c_str());
    for( r=0; r < 1000; r++){ 
      Row = pResult->Next();      
      if( Row == NULL ) break;
      for( t = 0; t < pResult->GetFieldCount(); t++){ 
	if(t==0) ID     = atoi(Row->GetField(t));
	if(t==1) ID_RAW = atoi(Row->GetField(t));
      };
    };
    delete pResult;   
    if ( !ID && !ID_RAW ){
      printf("\n No file with name %s in the DB!\n",filename.Data());
    } else {
      myquery.str("");
      myquery << "select ";
      myquery << " ID,RUNHEADER_TIME,RUNTRAILER_TIME "; 
      myquery << " from GL_RUN where ID_ROOT_L0=" << ID << ";";    
      pResult = dbc->Query(myquery.str().c_str());
      for( r=0; r < 1000; r++){ 
	Row = pResult->Next();      
	if( Row == NULL ) break;
	found = true;
	if ( !r ) printf("\n File %s contains the following runs: \n\n",filename.Data());
	TString UTC="UTC";
	printf(" => ID = %i --> the run started at %s UTC ended at %s UTC \n\n",(UInt_t)atoll(Row->GetField(0)),dbtime->ConvertTime(UTC,(UInt_t)atoll(Row->GetField(1))).Data(),dbtime->ConvertTime(UTC,(UInt_t)atoll(Row->GetField(2))).Data());
      };
      delete pResult;   
      myquery.str("");
      myquery << "select ";
      myquery << " ID,RUNHEADER_TIME,RUNTRAILER_TIME "; 
      myquery << " from GL_RUN_TRASH where BELONGED_TO='GL_RUN' AND FILENAMEL0='" << filename.Data() << "' ;";    
      pResult = dbc->Query(myquery.str().c_str());
      for( r=0; r < 1000; r++){ 
	Row = pResult->Next();      
	if( Row == NULL ) break;
	if ( !r ) printf("\n File %s contains the following DELETED runs: \n\n",filename.Data());
	TString UTC="UTC";
	printf(" => ID = %i --> the run started at %s UTC ended at %s UTC \n\n",(UInt_t)atoll(Row->GetField(0)),dbtime->ConvertTime(UTC,(UInt_t)atoll(Row->GetField(1))).Data(),dbtime->ConvertTime(UTC,(UInt_t)atoll(Row->GetField(2))).Data());
      };
      //
      if ( !found ){
	printf("\n No run associated to the file %s \n",filename.Data());
      };
      myquery.str("");
      myquery << "select ";
      myquery << " PATH,NAME"; 
      myquery << " from GL_RAW where ID=" << ID_RAW << ";";    
      pResult = dbc->Query(myquery.str().c_str());
      for( r=0; r < 1000; r++){ 
	Row = pResult->Next();      
	if( Row == NULL ) break;
	for( t = 0; t < pResult->GetFieldCount(); t++){ 
	  if(t==0) rawpath = Row->GetField(t);
	  if(t==1) rawname = Row->GetField(t);
	};
      };
      delete pResult;   
      printf("\n File %s belongs to raw data file %s/%s \n",filename.Data(),rawpath,rawname);
    };
  };  
  //
  // Close the DB connection
  //
  if ( dbc ) dbc->Close();
  //
  printf("\n");
  //
  exit(0);
}
