#include <string>
#include <iostream>
#include <iomanip>

#include "JDB/JDB.hh"
#include "JDB/JSelector.hh"
#include "JDB/JSelectorSupportkit.hh"
#include "JDB/JDetectorIntegration_t.hh"
#include "JDB/JPBSSequence.hh"
#include "JDB/JProductRouter.hh"
#include "JDB/JDBToolkit.hh"

#include "JLang/JLangToolkit.hh"

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


/**
 * \file
 *
 * Example program to build detector from database.
 * \author mdejong
 */
int main(int argc, char **argv)
{
  using namespace std;
  using namespace JPP;

  JServer   server;
  string    usr;
  string    pwd;
  string    cookie;
  string    inputFile;
  string    detid;
  JPBS_t    pbs;
  JUPI_t    upi;
  int       debug;

  try {

    JParser<> zap("Example program to build detector from database.");
    
    zap['s'] = make_field(server)     = getServernames();
    zap['u'] = make_field(usr)        = "";
    zap['!'] = make_field(pwd)        = "";
    zap['C'] = make_field(cookie)     = "";
    zap['f'] = make_field(inputFile, "output of JPrintDB -q \"integration\" -c \";\" -W1")  = "";
    zap['D'] = make_field(detid);
    zap['P'] = make_field(pbs)        = JPBS_t();
    zap['U'] = make_field(upi)        = JUPI_t();
    zap['d'] = make_field(debug)      = 1;

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


  JDetectorIntegration_t detector;

  if (inputFile != "") {

    detector.load(inputFile.c_str());

  } else {

    DEBUG("Reading database table " << getTable<JDetectorIntegration_t>() << endl); 

    try {

      JDB::reset(usr, pwd, cookie);

      detid = getDetector<string>(detid);

      ResultSet& rs  = getResultSet(getTable<JDetectorIntegration_t>());

      if (! (rs >> detector)) {
	THROW(JDatabaseException, "Error reading " << getTable<JDetectorIntegration_t>());
      }
    }
    catch(const exception& error) {
      FATAL(error.what() << endl);
    }
  }
  
  if (is_integer(detid)) {
    FATAL("Detector identifier must be object identifier." << endl);
  }
  
  detector.configure(detid);


  if        (pbs != JPBS_t()) {

    const JProductRouter router(detector, getPBSSequences(pbs));

    JDetectorIntegration_t::range_type range = detector.find(pbs);

    for (JDetectorIntegration_t::range_const_iterator i = range.first; i != range.second; ++i) {

      const JUPI_t upi = detector[i->second].content.getUPI();

      cout << LEFT(32) << upi << right << ' ' << router.getLocation(upi) << endl;
    }

  } else if (upi != JUPI_t()) {

    const JProductRouter router(detector, getPBSSequences(upi.getPBS()));

    detector.print(cout, upi);

    const JLocation_t location = router.getLocation(upi);

    if (location.is_valid()) {
      cout << location << endl;
    }
    
  } else {

    cout << "Enter UPI." << endl;

    for ( ; ; ) {

      JUPI_t upi;

      cout << "> " << flush;
      cin  >> upi;

      const JProductRouter router(detector, getPBSSequences(upi.getPBS()));

      detector.print(cout, upi);

      const JLocation_t location = router.getLocation(upi);

      if (location.is_valid()) {
	cout << location << endl;
      }
    }
  }
}