//============================================================================
// $Id: PacketUser.h,v 1.6 2009/12/24 10:31:13 mocchiut Exp $ 
// Description : 
//============================================================================
#ifndef PACKETUSER_H_
#define PACKETUSER_H_
#include "PamInclude.h"
#include <TTimeStamp.h>
#include "../event/PacketType.h"
#include "EventReader.h"
#include "ReaderAlgorithms.h"
#include "../event/mcmd/McmdEvent.h"
#include "../event/mcmd/McmdRecord.h"

#include "TROOT.h" //ROOT version > 5.14
#include "TSystem.h" // EMI
#include "TArrayI.h" // EMI

#include <vector>

using namespace pamela;
using namespace pamela::techmodel;

namespace PamOffLineSW {

 
/* class dbinfo{ */
/*   public: */
/*   dbinfo( */
/*   char * v_folder_name,  */
/*   char* v_file_name, */
/*   unsigned long int v_pkt_number_in,  */
/*   unsigned long int v_pkt_number_fin,  */
/*   unsigned long int v_obt_in, */
/*   unsigned long int v_obt_fin,  */
/*   unsigned long int v_mboot_num,  */
/*   unsigned long int v_time_offset,  */
/*   int v_bad_pkt, */
/*   int v_bad_pkt_read,  */
/*   int v_bad_pkt_CalRead,  */
/*   int v_num_PKT_Saved,  */
/*   char* v_nome_input,  */
/*   bool v__time_is_estimated */
/*   ){ */
/*     folder_name = strdup(v_folder_name);  */
/*     file_name = strdup(v_file_name); */
/*     pkt_number_in = v_pkt_number_in;  */
/*     pkt_number_fin = v_pkt_number_fin;  */
/*     obt_in = v_obt_in; */
/*     obt_fin = v_obt_fin;  */
/*     mboot_num = v_mboot_num;  */
/*     time_offset = v_time_offset;  */
/*     bad_pkt = v_bad_pkt; */
/*     bad_pkt_read = v_bad_pkt_read;  */
/*     bad_pkt_CalRead = v_bad_pkt_CalRead;  */
/*     num_PKT_Saved = v_num_PKT_Saved;  */
/*     nome_input = v_nome_input;  */
/*     _time_is_estimated = v__time_is_estimated; */
/*   } */
/*   ~dbinfo(){ */
/*     free(folder_name);  */
/*     free(file_name); */
/*   } */
/*   char* folder_name;  */
/*   char* file_name; */
/*   unsigned long int pkt_number_in;  */
/*   unsigned long int pkt_number_fin;  */
/*   unsigned long int obt_in; */
/*   unsigned long int obt_fin;  */
/*   unsigned long int mboot_num;  */
/*   unsigned long int time_offset;  */
/*   int bad_pkt; */
/*   int bad_pkt_read;  */
/*   int bad_pkt_CalRead;  */
/*   int num_PKT_Saved;  */
/*   char* nome_input;  */
/*   bool _time_is_estimated; */
/* }; */
 
class PacketUser {

public:
  //destructor
  virtual ~PacketUser();
  //the interface called by the external module: saves packets in ROOT files using the YODA part
  void usePKT(char*& headerPkt, char*& pamPkt, long int length, bool isCons, bool isPKTGood, const PacketType* type,
      unsigned long int counter, unsigned long int obt);

  //return the instance of the singleton
  static PacketUser& getInstance();
  //to be called at the end of the game
  void FinishLastGroup();

private:
  
  // store dbinfo when file is bad but num. packet more than 1000 
  //  vector <dbinfo*> m_dbinfos;
 
  //the Event Reader handler
  pamela::techmodel::EventReader* reader;
  //the Pamela Run handler,  one for ech ROOT file created
  pamela::PamelaRun* pRun;
  //Constructor
  PacketUser();
  //The istance
  static PacketUser instance;
  //How many times I found a discontinuity
  static int numDiscontinity;
  //How many packets arrived here,
  static int numPKT;
  //How many packetS saved in each ROOT files
  static int numPKTSaved;
  //Name of the final ROOT file
  char rootfilename[80];
  //pkt counter of the first packet of the group
  unsigned long int pkt_number_init;
  //pkt OBT of the first packet of the group
  unsigned long int obt_init;
  //pkt counter of the last packet of the group
  unsigned long int pkt_number_last;
  //pkt OBT of the last packet of the group
  unsigned long int obt_last;
  //the first packet's absolute time
  unsigned long int real_time_init;
  //the last packet's absolute time
  unsigned long int real_time_last;
  //tymesync and OBT informations
  unsigned long int obt_time_sync;
  unsigned long int last_time_sync_info;
  // (tassa) keep previous value of time_sync
  unsigned long int obt_time_sync_prevvalue;
  unsigned long int last_time_sync_info_prevvalue;
  bool time_is_estimated;
  //TimeOffset used to obtain absolute time
  unsigned long int timeOffset;
  //part of the ROOT filename used to retrieve timeOffset for special files
  char nnnn_mmm_ppp[80];
  //boot number
  unsigned long int boot_number;
  unsigned long int boot_number_prevvalue;
  //(tassa)
  unsigned int id_to_recover[1000];
  int id_to_recover_index;
  //number of packets with problems( in general CRC problems) detected in EventReader:
  int bad_pkt_EventReader;
  //num  ber of Calibration packets with problems( in general CRC problems) detected in EventReader:
  int bad_pkt_CalibReader;
  //number of good packets that comes from one or more corrupted cadres
  int bad_pkt;

  //marco_new:
  //the ID of the current ROOT file in table Table_ROOT_Good
  unsigned int my_id;

  //number of good Calibration packets in the ROOT files
  //	int good_pkt_Calib;//maybe I will use this in future

  //the table name in our DB for the ROOT files
  const char* Table_ROOT_Good;
  //the table name in our DB where I put the ROOT files that have not Real time associated
  const char* Table_ROOT_Bad;
  //table used to retrieve TimeOffset
  const char* Table_GL_RESURS_OFFSET;
  //the table name in our DB for MERGING
  const char* Table_ROOT_Merging;

  // 
  Int_t recoverlimit;
  // list of ID in root_table_bad with more than XXX packets
  TArrayI *idtorecover;
  // 
  Int_t arsize;
  // delete small files in root_table_bad from disk
  void CleanDisk();

  //starts a new root file
  void StartGroup();
  //set the value of the counter and obt of the first packet of the group
  void setInit(unsigned long int counter, unsigned long int obt);
  //finish the old ROOT file
  void FinishGroup(char * filename);
  //set the value of the counter and obt of the last packet of the group
  void setLast(unsigned long int counter, unsigned long int obt);
  //retrieve OBT_TIME_SYNC and LAST_TIME_SYNC_INFO from packet
  void setTimeSync(char* packet, long int pktLenght, const PacketType* type);
  //retrieve boot number
  void setBootNumber(char* packet, long int pktLenght, const PacketType* type);
  //set real_time_init and real_time_last
  void setReal_Time();
  
  void setReal_TimeRECOVERY(
			    unsigned long int & _real_time_init,
			    unsigned long int & _real_time_last,
			    unsigned long int _obt_init,
			    unsigned long int _obt_last
			    );
  
//
  void recover_boot_number();

  //retrieve the timeOffset from table=Table_GL_RESURS_OFFSET
  unsigned long int retrieveTimeOffset(const char * table);

  unsigned int select_maxIDN_DB(const char* table_name, const char* file_name);

  //function that saves informations in our DB
  bool saveROOT_DB(const char* table_name, const char* folder_name, const char* file_name, unsigned long int pkt_number_in,
      unsigned long int pkt_number_fin, unsigned long int obt_in, unsigned long int obt_fin, unsigned long int oT_sync,
      unsigned long int lT_sync_info, unsigned long int mtime_init, unsigned long int mtime_last,
      unsigned long int mboot_num, unsigned long int time_offset, int bad_pkt, int bad_pkt_read, int bad_pkt_CalRead,
      int num_PKT_Saved, const char* nome_input, bool _time_is_estimated);

  ///new part merging

  //tipi di relazioni che il ROOT file puo' avere con un ROOT gia salvatto in DB
  //0 =AFTER  se c'e' una sovrapposizione temporale parziale, inizia dopo l'inizio di quello associato e finisce dopo la sua fine
  //1 =BEFORE se c'e' una sovrapposizione temporale parziale, ossia finisce prima della fine di quello associato ma inizia prima
  //2 =SMALLER se c'e' una sovrapposizione temporale parziale: e' contenuto nel ROOT file associato
  //3 =BIGGER  se c'e' una sovrapposizione temporale parziale: contiene il ROOT file associato
  enum type_Rel_ROOT {
    AFTER, //se inizia dentro e finisce fuori
    BEFORE, //inizia prima ma finisce dentro
    SMALLER, //se inizia e finisce dentro
    BIGGER
  //se inizia prima e finisce dopo
  };

  bool merge_ROOTfiles();

  bool saveMergeROOT_DB(const char* table_name, unsigned int root_id, unsigned long int pkt_number_in,
      unsigned long int pkt_number_fin, unsigned long int obt_in, unsigned long int obt_fin,
      unsigned long int mtime_init, unsigned long int mtime_last, unsigned long int mboot_num, double percentage);

  bool updateMergeROOT_DB(const char* table_name, unsigned int root_id, unsigned long int pkt_number_in,
      unsigned long int pkt_number_fin, unsigned long int obt_in, unsigned long int obt_fin,
      unsigned long int mtime_init, unsigned long int mtime_last, unsigned long int mboot_num, double bad_perc,
      unsigned int ID_record, type_Rel_ROOT type_rel);

  //search in DB if there are ROOT files in the temporal range of interest and with the given relation
  TSQLResult* Select_merging(const char* table_name, unsigned long int mtime_init, unsigned long int mtime_last,
      type_Rel_ROOT type_rel);

  //Lock the tableTobeLocked table or all the tables I know if par=NULL
  int LockTables(const char* tableTobeLocked);
  //Unlock all the lockedtables
  int UnLockTables();
  //Open DB connection and lock table
  void OpenDBConnection(const char* tableTobeLocked);
  //Close DB connection and UNlock tables
  void CloseDBConnection();

  /***************************************************************************************/
  //UNUSED: return the system time in ms
  unsigned long long Record_Time();
  //DBG functions that saves pkt
  void saveALL_PKT(char* headerPkt, char* pamPkt, long int length, bool append);
  //function used to save in a file the packet
  void savePKT_file(char* headerPkt, char* pamPkt, long int length, bool append, char* nomefile);

};

}

#endif /*PACKETUSER_H_*/
