/* ======================================================================== *\
!
! *
! * This file is part of MARS, the MAGIC Analysis and Reconstruction
! * Software. It is distributed to you in the hope that it can be a useful
! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
! * It is distributed WITHOUT ANY WARRANTY.
! *
! * Permission to use, copy, modify and distribute this software and its
! * documentation for any purpose is hereby granted without fee,
! * provided that the above copyright notice appear in all copies and
! * that both that copyright notice and this permission notice appear
! * in supporting documentation. It is provided "as is" without express
! * or implied warranty.
! *
!
!
!   Author(s): Javier López, 12/2003 <mailto:jlopez@ifae.es>
!              Markus Gaug , 04/2004 <mailto:markus@ifae.es>
!
!   Copyright: MAGIC Software Development, 2000-2004
!
!
\* ======================================================================== */
/////////////////////////////////////////////////////////////////////////////
//
//  bootcampstandardanalysis.C
//
//  Updated version of the macro designed at the Wuerzburg bootcamp and 
//  compatible with the latest changes in Mars for general usage at the
//  Udine bootcamp. 
//
//  Needs as arguments the run number of a pedestal file ("*_P_*.root"), 
//  one of a calibration file ("*_C_*.root") and one of a data file 
//  ("*_D_*.root"). Performs the pedestal calculation, the calibration 
/// constants calculation and the calibration of the data. 
//
//  The TString inpath has to be set correctly.
//
//  The macro searches for the pulser colour which corresponds to the calibration
//  run number. If the run number is smaller than 20000, pulser colour "CT1" 
//  is assumed, otherwise, it searches for the strings "green", "blue", "uv" or 
//  "ct1" in the filenames. If no colour or multiple colours are found, the 
//  execution is aborted.  
//
//////////////////////////////////////////////////////////////////////////////////
const TString inpath = "/mnt/Data/rootdata/CrabNebula/2004_02_10/";
const Int_t dpedrun  = 14607;
const Int_t dcalrun1 = 14608;
const Int_t dcalrun2 = 0;
const Int_t ddatrun1 = 14609;
const Int_t ddatrun2 = 14614;
const Bool_t usedisplay = kTRUE;

void bootcampstandardanalysis(const Int_t prun=dpedrun, // pedestal file
                              const Int_t crun1=dcalrun1, const Int_t crun2=dcalrun2, // calibration file(s)
                              const Int_t drun1=ddatrun1, const Int_t drun2=ddatrun2 // data files(s)
                              )
                              
{

  MRunIter pruns;
  MRunIter cruns;
  MRunIter druns;

  pruns.AddRun(prun,inpath);

  if (crun2==0)
    cruns.AddRun(crun1,inpath);
  else
    cruns.AddRuns(crun1,crun2,inpath);

  MCalibrationCam::PulserColor_t color;

  if (crun1 < 20000)
    color = MCalibrationCam::kCT1;
  else
    color = FindColor((MDirIter*)&cruns);

  if (color == MCalibrationCam::kNONE)
    {
      TTimer timer("gSystem->ProcessEvents();", 50, kFALSE);
      
      while (1)
        {
          timer.TurnOn();
          TString input = Getline("Could not find the correct colour: Type 'q' to exit, "
                                  "green, blue, uv or ct1 to go on: ");
          timer.TurnOff();
          
          if (input=="q\n")
            return ;
          
          if (input=="green")
            color = MCalibrationCam::kGREEN;
          if (input=="blue")
            color = MCalibrationCam::kBLUE;
          if (input=="uv")
            color = MCalibrationCam::kUV;
          if (input=="ct1")
            color = MCalibrationCam::kCT1;
        }
    }
  
  if (drun2==0)
    druns.AddRun(drun1,inpath);
  else
    druns.AddRuns(drun1,drun2,inpath);
  
  //
  // Now setup the tasks and tasklist for the pedestals:
  // ---------------------------------------------------
  //
  MBadPixelsCam     badcam;
  MGeomCamMagic     geomcam;
  MGeomApply        geomapl;
  //
  // If you want to exclude pixels from the beginning, read 
  // an ascii-file with the corr. pixel numbers (see MBadPixelsCam)
  //
  //  badcam.AsciiRead("badpixels.dat");
  
  /************************************/
  /* FIRST LOOP: PEDESTAL COMPUTATION */
  /************************************/

  MJPedestal pedloop;
  pedloop.SetInput(&pruns);
  if (usedisplay)
    {
      MStatusDisplay *display = new MStatusDisplay;
      display->SetUpdateTime(3000);
      display->Resize(850,700);
      pedloop.SetDisplay(display);
    }
  pedloop.SetBadPixels(badcam);

  if (!pedloop.Process())
    return;

  /****************************************/
  /* SECOND LOOP: CALIBRATION COMPUTATION */
  /****************************************/

  //
  // Now setup the new tasks for the calibration:
  // ---------------------------------------------------
  //
  MCalibrationQECam qecam;
  MJCalibration     calloop;
  calloop.SetColor(color);
  calloop.SetInput(&cruns);
  //
  // Use as signal extractor MExtractSignal:
  //
  calloop.SetExtractorLevel(1);
  //
  // Set the corr. cams:
  //
  calloop.SetQECam(qecam);
  calloop.SetBadPixels(pedloop.GetBadPixels());
  //
  // The next two commands are for the display:
  //
  if (usedisplay)
      calloop.SetDisplay(display);
  
  //
  // Apply rel. time calibration:
  //
  calloop.SetRelTimeCalibration();
  //
  // Use as arrival time extractor MArrivalTimeCalc2:
  //
  calloop.SetArrivalTimeLevel(2);
  
  //
  // Do the event-loop:
  //
  if (!calloop.Process(pedloop.GetPedestalCam()))
    return;
  

  /*************************************/
  /* THIRD LOOP: PEDESTAL CALIBRATION  */
  /*************************************/

  //
  // Create a empty Parameter List and an empty Task List
  //
  MParList  plist3;
  MTaskList tlist3;
  plist3.AddToList(&tlist3);
  
  //
  // Now setup the tasks and tasklist to calculate the pedestal rms in number of photons
  // -----------------------------------------------------------------------------------
  //
  
  MCerPhotEvt    nphot;
  MPedPhotCam    nphotrms;
  
  plist3.AddToList(&geomcam);

  //
  // Retrieve the cameras from the previous runs:
  //
  plist3.AddToList(&pedloop.GetPedestalCam());
  plist3.AddToList(&calloop.GetCalibrationCam());
  plist3.AddToList(&calloop.GetQECam());
  plist3.AddToList(&calloop.GetRelTimeCam());
  plist3.AddToList(&calloop.GetBadPixels());
  plist3.AddToList(&nphot);
  plist3.AddToList(&nphotrms);
  
  //tasks
  MReadMarsFile read3("Events");
  read3.DisableAutoScheme();
  static_cast<MRead&>(read3).AddFiles(pruns);  

  MExtractSignal   extsig;
  MCalibrate       photcalc;
  photcalc.SetCalibrationMode(MCalibrate::kFfactor);
  //    MPedPhotCalc  photrmscalc;  //It doesn't exist yet
  
  tlist3.AddToList(&read3);
  tlist3.AddToList(&geomapl);
  tlist3.AddToList(&extsig);
  tlist3.AddToList(&photcalc);
  //    tlist3.AddToList(&photrmscalc);
  
  //
  // Create and setup the eventloop
  //
  MEvtLoop evtloop3;
  evtloop3.SetParList(&plist3);
  
  //
  // Execute first analysis
  //
  if (!evtloop3.Eventloop())
    return;
  
  tlist3.PrintStatistics();
  
  /*************************************/
  /* FOURTH LOOP: DATA CALIBRATION     */
  /*************************************/

  //
  // Create a empty Parameter List and an empty Task List
  //
  MParList  plist4;
  MTaskList tlist4;
  plist4.AddToList(&tlist4);
  
  //
  // Now setup the tasks and tasklist to analize the data
  // -----------------------------------------------------
  //
  
  plist4.AddToList(&geomcam);
  //
  // Retrieve the cameras from the previous runs:
  //
  plist4.AddToList(&pedloop.GetPedestalCam());
  plist4.AddToList(&calloop.GetCalibrationCam());
  plist4.AddToList(&calloop.GetQECam());
  plist4.AddToList(&calloop.GetRelTimeCam());
  plist4.AddToList(&calloop.GetBadPixels());
  plist4.AddToList(&nphot);
  plist4.AddToList(&nphotrms);

  MArrivalTime times;
  plist4.AddToList(&times);
  
  //tasks
  MReadMarsFile read4("Events");
  read4.DisableAutoScheme();
  static_cast<MRead&>(read4).AddFiles(druns);  
  
  MArrivalTimeCalc2   timecalc;
  MCalibrateRelTimes  timecal;

  tlist4.AddToList(&read4);
  tlist4.AddToList(&geomapl);
  tlist4.AddToList(&extsig);
  tlist4.AddToList(&timecalc);
  tlist4.AddToList(&photcalc);
  tlist4.AddToList(&timecal);
  
  //
  // Create and setup the eventloop
  //
  MEvtLoop evtloop4;
  evtloop4.SetParList(&plist4);

  if (!evtloop4.PreProcess())

    return;
  
  TCanvas *c1 = new TCanvas;
  MHCamera disp1(geomcam);
  disp1.SetPrettyPalette();
  //disp1.SetInvDeepBlueSeaPalette()
  disp1.Draw();
  gPad->SetLogy();
  gPad->cd(1);
  
  /*
  TCanvas *c2 = new TCanvas;
  MHCamera disp2(geomcam);
  disp2.SetPrettyPalette();
  //disp2.SetInvDeepBlueSeaPalette()
  disp2.Draw();
  gPad->SetLogy();
  gPad->cd(1);
  */
  while (tlist4.Process())
    {
      disp1.SetCamContent(nphot);
      
      gPad->Modified();
      gPad->Update();

      /*    
      disp2.SetCamContent(times);
      
      gPad->Modified();
      gPad->Update();
      */

      // Remove the comments if you want to go through the file
      // event-by-event:
      if (!HandleInput())
	break;
    }

  evtloop4.PostProcess();
  
}

Bool_t HandleInput()
{
    TTimer timer("gSystem->ProcessEvents();", 50, kFALSE);

    while (1)
    {
        //
        // While reading the input process gui events asynchronously
        //
        timer.TurnOn();
        TString input = Getline("Type 'q' to exit, <return> to go on: ");
        timer.TurnOff();

        if (input=="q\n")
            return kFALSE;

        if (input=="\n")
            return kTRUE;
    };

    return kFALSE;
}

MCalibrationCam::PulserColor_t FindColor(MDirIter* run) 
{
  
  MCalibrationCam::PulserColor_t col = MCalibrationCam::kNONE;

  TString filenames;

  while (!(filenames=run->Next()).IsNull())
    {

      filenames.ToLower();

      if (filenames.Contains("green"))
        if (col == MCalibrationCam::kNONE)
          {
            cout << "Found colour: Green  in " << filenames << endl;
            col = MCalibrationCam::kGREEN;
          }
        else if (col != MCalibrationCam::kGREEN)
          {
            cout << "Different colour found in " << filenames << "... abort" << endl;
            return MCalibrationCam::kNONE;
          }

      if (filenames.Contains("blue"))
        if (col == MCalibrationCam::kNONE)
          {
            cout << "Found colour: Blue  in " << filenames << endl;
            col = MCalibrationCam::kBLUE;
          }
        else if (col != MCalibrationCam::kBLUE)
          {
            cout << "Different colour found in " << filenames << "... abort" << endl;
            return MCalibrationCam::kNONE;
          }

      if (filenames.Contains("uv"))
        if (col == MCalibrationCam::kNONE)
          {
            cout << "Found colour: Uv  in " << filenames << endl;
            col = MCalibrationCam::kUV;
          }
        else if (col != MCalibrationCam::kUV)
          {
            cout << "Different colour found in " << filenames << "... abort" << endl;
            return MCalibrationCam::kNONE;
          }

      if (filenames.Contains("ct1"))
        if (col == MCalibrationCam::kNONE)
          {
            cout << "Found colour: Ct1  in " << filenames << endl;
            col = MCalibrationCam::kCT1;
          }
        else if (col != MCalibrationCam::kCT1)
          {
            cout << "Different colour found in " << filenames << "... abort" << endl;
            return MCalibrationCam::kNONE;
          }
      
    }
  

      
  if (col == MCalibrationCam::kNONE)
    cout <<  "No colour found in filenames of runs: " << ((MRunIter*)run)->GetRunsAsString() 
         << "... abort" << endl;
  
  return col;      
}
