//************************************************
// Author: Federica Lionetto
// Created on: 09/04/2015
//************************************************

/*

PlotTrends creates a ROOT file with temperature, relative humidity, and dew point trends.

Compile with:

make

Run with:

./PlotTrends [sensor] [from] [to] [additional folder]

where

- [sensor] is the type of sensor (Hans410, ...);
- [from] is the optional starting time from which one wants to display the trends, according to the "ddd mmm  d hh:mm:ss yyyy" format;
- [to] is the optional stopping time to which one wants to display the trends, according to the "ddd mmm  d hh:mm:ss yyyy" format;
- [additional folder] is the optional additional folder where the output will be saved.

For example:

./PlotTrends Hans320

or 

./PlotTrends Hans320 "Thu Apr  9 16:55:00 2015" "Thu Apr  9 16:55:52 2015"

A folder named AnalysisResults will be created in a fixed location and a ROOT file will be saved in there. A folder named Figures will be created inside the folder named AnalysisResults, with some monitoring plots.

If needed, an additional folder can be specified, that will be created inside the folder named AnalysisResults.
*/

#include "../Tools/Lib.C"
#include "../Tools/UsefulFunctions.C"
#include "../Tools/lhcbStyle.C"
#include "../Tools/Style.C"

#include "../Tools/Par.C"

void PlotTrends(char *sensor, char *from=0, char *to=0, char *externalPath=0);

vector<string> SelectFiles(string inputDirectory, vector<string> list_of_files, time_t t_from, time_t t_to);


int main(int argc, char *argv[])
{
  getLHCbStyle();
  PersonalStyle();

  if ((argc ==2) && (string(argv[1]) == "--info"))
  {
    cout << "**************************************************" << endl;

    cout << "PlotTrends creates a ROOT file with temperature, relative humidity, and dew point trends." << endl;

    cout << "Compile with:" << endl;

    cout << "make" << endl;

    cout << "Run with:" << endl;

    cout << "./PlotTrends [sensor] [from] [to] [additional folder]" << endl;

    cout << "where" << endl;

    cout << "- [sensor] is the type of sensor (Hans410, ...);" << endl;
    cout << "- [from] is the optional starting time from which one wants to display the trends, according to the 'ddd mmm  d hh:mm:ss yyyy' format;" << endl;
    cout << "- [to] is the optional stopping time to which one wants to display the trends, according to the 'ddd mmm  d hh:mm:ss yyyy' format;" << endl;
    cout << "- [additional folder] is the optional additional folder where the output will be saved." << endl;

    cout << "For example:" << endl;

    cout << "./PlotTrends Hans320" << endl;

    cout << "or" << endl; 

    cout << "./PlotTrends Hans320 'Thu Apr  9 16:55:00 2015' 'Thu Apr  9 16:55:52 2015'" << endl;

    cout << "A folder named AnalysisResults will be created in a fixed location and a ROOT file will be saved in there. A folder named Figures will be created inside the folder named AnalysisResults, with some monitoring plots." << endl;

    cout << "If needed, an additional folder can be specified, that will be created inside the folder named AnalysisResults." << endl;
    
    cout << "**************************************************" << endl;

    return 0;
  }
  else if (argc < 2)
  {
    cout << "**************************************************" << endl;
    
    cout << "Error! Input information missing..." << endl;
    cout << "Please use the following format:" << endl;
    cout << "./PlotTrends [1] [2] [3] [4]" << endl;
    cout << "with:" << endl;
    cout << "[1] = Type of sensor (Hans410, ...);" << endl;
    cout << "[2] = Starting time, optional;" << endl;
    cout << "[3] = Stopping time, optional;" << endl;
    cout << "[4] = Additional folder, optional." << endl;
    cout << "Type ./PlotTrends --info for more information." << endl;

    cout << "**************************************************" << endl;

    return 0;  
  }
  else
  {
    cout << "Type of sensor: " << argv[1] << endl;
    if (argc == 2)
      PlotTrends(argv[1]);
    else if (argc == 3)
    {
      cout << "**************************************************" << endl;

      cout << "Error! Stopping time not specified..." << endl;
      
      cout << "**************************************************" << endl;
    
      return 0;
    }
    else if (argc == 4)
    {
      cout << "Starting time: " << argv[2] << endl;
      cout << "Stopping time: " << argv[3] << endl;
      PlotTrends(argv[1],argv[2],argv[3]);
    }
    else if (argc == 5)
    {
      cout << "Staring time: " << argv[2] << endl;
      cout << "Stopping time: " << argv[3] << endl;
      cout << "Additional folder: " << argv[4] << endl;
      PlotTrends(argv[1],argv[2],argv[3],argv[4]);
    }
    else
    {
      cout << "Error! Too many arguments given..." << endl;
      
      return 0;
    }
    
    return 0;  
  }  
}

void PlotTrends(char *sensor, char *from, char *to, char *externalPath)
{
  cout << "**************************************************" << endl;
  cout << "Plotting trends..." << endl;
  cout << "**************************************************" << endl;

  // Do not comment this line.
  gROOT->ProcessLine("#include <vector>");

  // Adjust time format for output ROOT file and figures.
  string s_from = "";
  string s_to = "";
  
  struct tm tm_from;
  time_t t_from;

  struct tm tm_to;
  time_t t_to;

  if ((from != 0) && (to != 0))
  {
    s_from = string(from);
    s_to = string(to);

    // Remove white spaces from s_from and s_to.
    s_from.erase(remove(s_from.begin(), s_from.end(), ' '), s_from.end());
    s_to.erase(remove(s_to.begin(), s_to.end(), ' '), s_to.end());

    // Convert the string with date and time to something that is interpreted as date and time. tm_from is a tm object, t_from is a time_t object and corresponds to the number of seconds since epoch. The format specifier %c stands for date and time representation.

    memset(&tm_from, 0, sizeof(struct tm));
    strptime(from,"%c",&tm_from);
    t_from = mktime(&tm_from);
    
    /*
      cout << tm_from.tm_year << endl;
      cout << t_from << endl;
    */
    
    memset(&tm_to, 0, sizeof(struct tm));
    strptime(to,"%c",&tm_to);
    t_to = mktime(&tm_to);
    
    /*
      cout << tm_to.tm_year << endl;
      cout << t_to << endl;
    */
    
    // Check that the starting time is earlier than the stopping time.
    if (t_from >= t_to)
    {
      cout << "Error! Starting time earlier than stopping time..." << endl;
      return;
    }
  }

  // Do some fanciness to get the directory right.
  string inputDirectory = "/disk/groups/hep/flionett/TestStand/Data/"+string(sensor)+"/Monitoring";
  string outputDirectory = "/disk/groups/hep/flionett/TestStand/AnalysisResults/"+string(sensor)+"/Monitoring";
  if (externalPath!=0)
    outputDirectory = string(outputDirectory+"/"+externalPath);
  cout << "The input directory is: " << inputDirectory << endl;
  cout << "The output directory is: " << outputDirectory << endl;

  // Create the outputDirectory directory if it does not exist.
  string path_to_make = "mkdir -p "+outputDirectory;
  system(path_to_make.c_str());

  cout << "Figures stored in: " << outputDirectory+"/Figures" << endl;

  // Create a directory named Figures inside the directory named outputDirectory if it does not exist.
  string path_to_make_figures = "mkdir -p "+outputDirectory+"/Figures";
  if ((from != 0) && (to != 0))
    path_to_make_figures = path_to_make_figures+"/PlotTrends-"+"from"+s_from+"to"+s_to;
  else
    path_to_make_figures = path_to_make_figures+"/PlotTrends-all";
  system(path_to_make_figures.c_str());

  TString path_to_figures = (string(path_to_make_figures)).substr((string(path_to_make_figures)).find_last_of(' ')+1);



  TDatime *time;
  vector<double> vtime;

  double T;
  vector<double> vT;

  double RH;
  vector<double> vRH;

  double DP;
  vector<double> vDP;

  string trash1;
  string trash2;
  string trash3;
  string trash4;
  string trash5;

  // Given starting and stopping time, find the corresponding input text files.
  vector<string> list_of_files;
  vector<string> list_of_selected_files;

  list_of_files = open(inputDirectory);
  if ((from != 0) && (to != 0))
    list_of_selected_files = SelectFiles(inputDirectory, list_of_files, t_from, t_to);
  else
    list_of_selected_files = list_of_files;

  if (list_of_selected_files.size() == 0) {
    cout << "Error! No input text file selected..." << endl;
    return;
  }

  ifstream file;
  string header;
  string line;
  struct tm tm_time_in_line;
  time_t t_time_in_line;

  // Read data from selected input text files.
  for (vector<string>::const_iterator i = list_of_selected_files.begin(); i != list_of_selected_files.end(); ++i)
  {
    // Open file.
    cout << "Selected input text file #" << i-list_of_selected_files.begin() << ": " << *i << endl;
    file.open((inputDirectory+"/"+*i).c_str());
    if (file.is_open())
    {
      // cout << "Great! File opened..." << endl;
      
      // Skip header.
      if (getline(file,header)) 
      {
	// Read time in each line.
	while (getline(file,line))
	{
	  memset(&tm_time_in_line, 0, sizeof(struct tm));
	  strptime(line.c_str(),"%c",&tm_time_in_line);
	  t_time_in_line = mktime(&tm_time_in_line);
	  
	  if ((from != 0) && (to != 0))
	  {	  
	    if ((t_time_in_line <= t_to) && (t_time_in_line >= t_from))
	    {
	      // cout << "Time in line: " << t_time_in_line << " from epoch time" << endl;
	      time = new TDatime(tm_time_in_line.tm_year,tm_time_in_line.tm_mon+1,tm_time_in_line.tm_mday,tm_time_in_line.tm_hour+1,tm_time_in_line.tm_min,tm_time_in_line.tm_sec);
	      // cout << "Time going in the ROOT file: " << time->Convert() << endl;
	      // Get time, temperature, humidity, and dew point.
	      istringstream iss(line);
	      iss >> trash1 >> trash2 >> trash3 >> trash4 >> trash5 >> T >> RH >> DP;
	      vtime.push_back(time->Convert());
	      vT.push_back(T);
	      vRH.push_back(RH);
	      vDP.push_back(DP);
	    }
	  }
	  else 
	  {
	    // cout << "Time in line: " << t_time_in_line << " from epoch time" << endl;
	    time = new TDatime(tm_time_in_line.tm_year,tm_time_in_line.tm_mon+1,tm_time_in_line.tm_mday,tm_time_in_line.tm_hour+1,tm_time_in_line.tm_min,tm_time_in_line.tm_sec);
	    // cout << "Time going in the ROOT file: " << time->Convert() << endl;
	    // Get time, temperature, humidity, and dew point.
	    istringstream iss(line);
	    iss >> trash1 >> trash2 >> trash3 >> trash4 >> trash5 >> T >> RH >> DP;
	    vtime.push_back(time->Convert());
	    vT.push_back(T);
	    vRH.push_back(RH);
	    vDP.push_back(DP);
	  }
	}
      }
      else
      {
	cout << "Error! Unable to read header..." << endl;
	return;
      }
    
      // Close file.
      file.close();
    }
    else {
      cout << "Error! Unable to open file." << endl; // To be modified to stop everything if there is a problem.
      return;
    }
  }

  double *aT = &vT[0];
  double *aRH = &vRH[0];
  double *aDP = &vDP[0];
  double *atime = &vtime[0];

  /*
  cout << vT.size() << endl;
  cout << vtime.size() << endl;

  cout << vT[0] << endl;
  cout << vtime[0] << endl;

  cout << vT[10] << endl;
  cout << vtime[10] << endl;
  */

  // Open output ROOT file.
  string output_ROOT;
  if ((from != 0) && (to !=0))
    output_ROOT = outputDirectory+"/PlotTrends-"+"from"+s_from+"to"+s_to+".root";
  else
    output_ROOT = outputDirectory+"/PlotTrends-all.root";
  TFile *output = TFile::Open(TString(output_ROOT),"RECREATE");

  // Temperature trends.
  TCanvas *cT = new TCanvas("PlotTrends-T","",400,300);

  cT->SetLeftMargin(0.1363636);
  cT->SetRightMargin(0.08808081);
  cT->SetBottomMargin(0.2095588);
  
  TGraph *gT = new TGraph(vT.size(),atime,aT);
  InitGraph(gT,"Temperature trends","Time","Temperature (#circC)");
  gT->GetXaxis()->SetTimeDisplay(1);
  gT->GetXaxis()->SetLabelOffset(0.04);
  gT->GetXaxis()->SetTitleOffset(1.50);
  gT->GetYaxis()->SetTitleOffset(0.95);
  gT->GetXaxis()->SetTimeFormat("#splitline{%Y-%m-%d}{%H:%M:%S}");
  gT->GetXaxis()->SetNdivisions(-503);
  gT->GetXaxis()->SetTimeOffset(0,"gmt");
  DrawGraph(cT,gT,"AP",path_to_figures);

  // Relative humidity trends.
  TCanvas *cRH = new TCanvas("PlotTrends-RH","",400,300);

  cRH->SetLeftMargin(0.1363636);
  cRH->SetRightMargin(0.08808081);
  cRH->SetBottomMargin(0.2095588);
  
  TGraph *gRH = new TGraph(vRH.size(),atime,aRH);
  InitGraph(gRH,"Relative humidity trends","Time","Relative humidity (%)");
  gRH->GetXaxis()->SetTimeDisplay(1);
  gRH->GetXaxis()->SetLabelOffset(0.04);
  gRH->GetXaxis()->SetTitleOffset(1.50);
  gRH->GetYaxis()->SetTitleOffset(0.95);
  gRH->GetXaxis()->SetTimeFormat("#splitline{%Y-%m-%d}{%H:%M:%S}");
  gRH->GetXaxis()->SetNdivisions(-503);
  gRH->GetXaxis()->SetTimeOffset(0,"gmt");
  DrawGraph(cRH,gRH,"AP",path_to_figures);

  // Dew point trends.
  TCanvas *cDP = new TCanvas("PlotTrends-DP","",400,300);

  cDP->SetLeftMargin(0.1363636);
  cDP->SetRightMargin(0.08808081);
  cDP->SetBottomMargin(0.2095588);
  
  TGraph *gDP = new TGraph(vDP.size(),atime,aDP);
  InitGraph(gDP,"Dew point trends","Time","Dew point (#circC)");
  gDP->GetXaxis()->SetTimeDisplay(1);
  gDP->GetXaxis()->SetLabelOffset(0.04);
  gDP->GetXaxis()->SetTitleOffset(1.50);
  gDP->GetYaxis()->SetTitleOffset(0.95);
  gDP->GetXaxis()->SetTimeFormat("#splitline{%Y-%m-%d}{%H:%M:%S}");
  gDP->GetXaxis()->SetNdivisions(-503);
  gDP->GetXaxis()->SetTimeOffset(0,"gmt");
  DrawGraph(cDP,gDP,"AP",path_to_figures);

  // Temperature and dew point trends.
  TCanvas *cTandDP = new TCanvas("PlotTrends-TandDP","",400,300);

  cTandDP->SetLeftMargin(0.1363636);
  cTandDP->SetRightMargin(0.08808081);
  cTandDP->SetBottomMargin(0.2095588);
  
  TMultiGraph *mgTandDP = new TMultiGraph();

  gT->SetMarkerColor(kGreen);
  gT->SetLineColor(kGreen);
  gDP->SetMarkerColor(kRed);
  gDP->SetLineColor(kRed);
  
  TLegend *legTandDP = CreateLegend2(gT,"temperature",gDP,"dew point","lpw",0.63,0.59,0.88,0.84);

  mgTandDP->Add(gT);
  mgTandDP->Add(gDP);
  
  cTandDP->cd();
  mgTandDP->Draw("AP");

  mgTandDP->GetXaxis()->SetTimeDisplay(1);
  mgTandDP->GetXaxis()->SetLabelOffset(0.04);
  mgTandDP->GetXaxis()->SetTitleOffset(1.50);
  mgTandDP->GetYaxis()->SetTitleOffset(0.95);
  mgTandDP->GetXaxis()->SetTimeFormat("#splitline{%Y-%m-%d}{%H:%M:%S}");
  mgTandDP->GetXaxis()->SetNdivisions(-503);
  mgTandDP->GetXaxis()->SetTimeOffset(0,"gmt");

  DrawGraphCompare(cTandDP,mgTandDP,legTandDP,"Temperature and dew point trends","Time","Temperature (#circC)","AP",path_to_figures);
  


  // Write output ROOT file.
  output->Write();

  // Close output ROOT file.
  output->Close();

  return;
}



vector<string> SelectFiles(string inputDirectory, vector<string> list_of_files, time_t t_from, time_t t_to) {
  ifstream file;

  string header;
  string first_line;
  string last_line;

  struct tm tm_time_in_first_line;
  struct tm tm_time_in_last_line;

  time_t t_time_in_first_line;
  time_t t_time_in_last_line;

  vector<string> list_of_selected_files;

  for (vector<string>::const_iterator i = list_of_files.begin(); i != list_of_files.end(); ++i)
  {
    cout << "Input text file #" << i-list_of_files.begin() << ": " << *i << endl;

    // Check whether this input text file must be selected.
    file.open((inputDirectory+"/"+*i).c_str());
    if (file.is_open())
    {
      // cout << "Great! File opened..." << endl;

    // Skip header.
    if (getline(file,header)) 
    {
      // Read time in first line.
      if (getline(file,first_line))
      {
	memset(&tm_time_in_first_line, 0, sizeof(struct tm));
	strptime(first_line.c_str(),"%c",&tm_time_in_first_line);
	t_time_in_first_line = mktime(&tm_time_in_first_line);
	
	// cout << "Time in first line: " << t_time_in_first_line << " from epoch time" << endl;
      }
      else
      {
	cout << "Error! Cannot read time in first line..." << endl;
	return vector<string>();
      }
      // Read time in last line.
      last_line = getLastLine(file);
      memset(&tm_time_in_last_line, 0, sizeof(struct tm));
      strptime(last_line.c_str(),"%c",&tm_time_in_last_line);
      t_time_in_last_line = mktime(&tm_time_in_last_line);
      
      // cout << "Time in last line: " << t_time_in_last_line << " from epoch time" << endl;   

      // Decide if this input text file must be selected.
      
      if ((t_time_in_first_line <= t_to) && (t_time_in_last_line >= t_from))
      {
	// Select the input text file.
	list_of_selected_files.push_back(*i);
      }

    }
    else
    {
      cout << "Error! Unable to read header..." << endl;
      return vector<string>();
    }
    
    file.close();
    }
    else {
      cout << "Error! Unable to open file." << endl; // To be modified to stop everything if there is a problem.
      return vector<string>();
    }
  }

  // cout << "Selected input text files" << endl;
  for (vector<string>::const_iterator i = list_of_selected_files.begin(); i != list_of_selected_files.end(); ++i)
  {
    // cout << "Selected input text file #" << i-list_of_selected_files.begin() << ": " << *i << endl;
  }

  return list_of_selected_files;
}
