#include <string>
#include <iostream>
#include <sstream>
#include <map>

#include "km3net-dataformat/offline/Head.hh"
#include "km3net-dataformat/offline/Evt.hh"

#include "JDAQ/JDAQTimesliceIO.hh"
#include "JDAQ/JDAQEventIO.hh"
#include "JDAQ/JDAQSummarysliceIO.hh"

#include "JTrigger/JTriggerParameters.hh"

#include "JSupport/JSingleFileScanner.hh"
#include "JSupport/JFileRecorder.hh"
#include "JSupport/JMonteCarloFileSupportkit.hh"
#include "JSupport/JTriggerParametersSupportkit.hh"
#include "JSupport/JSupport.hh"
#include "JSupport/JMeta.hh"

#include "JLang/JObjectMultiplexer.hh"

#include "JDB/JDB.hh"
#include "JDB/JDBToolkit.hh"
#include "JDB/JSelector.hh"
#include "JDB/JSelectorSupportkit.hh"
#include "JDB/JDetectors.hh"
#include "JDB/JRuns.hh"
#include "JDB/JAllParams.hh"
#include "JDB/JRunsetupParams.hh"

#include "Jeep/JParser.hh"
#include "Jeep/JMessage.hh"


/**
 * \file
 * Auxiliary program to check trigger parameters in a given ROOT files against the values from the database.
 * \author lnauta
 */
int main(const int argc, const char * const argv[])
{
  using namespace std;
  using namespace JPP;
  using namespace KM3NETDAQ;

  JSingleFileScanner<JDAQTypes_t> inputFile;
  JFileRecorder     <JAllTypes_t> outputFile;
  JServer  server;
  string   usr;
  string   pwd;
  string   cookie;
  int      debug;

  try {

    JParser<> zap("Auxiliary program to check trigger parameters in a given ROOT files against the values from the database.");

    zap['f'] = make_field(inputFile);
    zap['s'] = make_field(server)     = getServernames();
    zap['u'] = make_field(usr)        = "";
    zap['!'] = make_field(pwd)        = "";
    zap['C'] = make_field(cookie)     = "";
    zap['o'] = make_field(outputFile) = "";
    zap['d'] = make_field(debug)      = 1;

    zap(argc, argv);
  }
  catch(const exception& error) {
    FATAL(error.what() << endl);
  }


  const double Dmax_m = 9999.0;

  JTriggerParameters parametersA;
  JTriggerParameters parametersB;


  try {
    parametersA = getTriggerParameters(inputFile);
  }
  catch(const JException& error) {
    ERROR("No trigger parameters from input." << endl);
  }

  parametersA.set(Dmax_m);

  DEBUG(parametersA);


  int detector_id = 0;
  int run_number  = 0;

  JObjectMultiplexer<JDAQTypes_t, JDAQHeader> in(inputFile);

  if (in.hasNext()) {

    detector_id = in.next()->getDetectorID();
    run_number  = in.next()->getRunNumber();

  } else {

    FATAL("File does not contain a valid run number." << endl);
  }  


  try {
    JDB::reset(usr, pwd, cookie);
  }
  catch(const exception& error) {
    FATAL(error.what() << endl);
  }


  string rs_oid;

  try {

    JRuns buffer;

    ResultSet& rs = getResultSet(getTable<JRuns>(), getSelector<JRuns>(detector_id, run_number));

    if (rs >> buffer) {
      rs_oid = buffer.RUNSETUPID;
    }

    rs.Close();
  }
  catch(const exception& error) {
    FATAL(error.what() << endl);
  }


  map<string, string> zmap;

  try {

    JAllParams buffer;

    ResultSet& rs = getResultSet(getTable<JAllParams>(), getSelector<JAllParams>("DATAACQUISITION"));

    while (rs >> buffer) {

      string::size_type pos = buffer.NAME.find(PREFIX_DATAFILTER);

      if (pos != string::npos) {

        pos = buffer.NAME.find('=', pos + PREFIX_DATAFILTER.length());

        zmap[buffer.OID] = buffer.NAME.erase(0, pos + 1);
      }
    }

    rs.Close();
  }
  catch(const exception& error) {
    FATAL(error.what() << endl);
  }


  stringstream data;    

  try {

    JRunsetupParams buffer;

    ResultSet& rs = getResultSet(getTable<JRunsetupParams>(), getSelector<JRunsetupParams>(getDetector(detector_id), rs_oid));

    while (rs >> buffer) {

      map<string, string>::const_iterator i = zmap.find(buffer.PAR_OID);

      if (i != zmap.end()) {
	data << i->second << "=" << buffer.VALUE << ";\n";
      }
    }

    rs.Close();
  }
  catch(const exception& error) {
    FATAL(error.what() << endl);
  }


  data >> parametersB;

  parametersB.set(Dmax_m);  
  parametersB.actionAtFileRead();

  DEBUG(parametersB);


  if (outputFile.getFilename() != "") {

    DEBUG("Write to " << outputFile << "... " << flush);

    outputFile.open();

    outputFile.put(parametersB);
    
    JSingleFileScanner<JRemove<JAllTypes_t, JTriggerParameters>::typelist> io(inputFile);

    io >> outputFile;

    outputFile.close();

    DEBUG("OK" << endl);
  }


  const bool is_equal = (parametersA == parametersB);

  if (is_equal)
    NOTICE(GREEN << "The parameters for run " << run_number << " are equivalent."     << RESET << endl);
  else
    ERROR (RED   << "The parameters for run " << run_number << " are NOT equivalent." << RESET << endl);

  return (is_equal ? 0 : 1);
}