//
// A1526Timer.cpp                
//
// Michael Tytgat, michael.tytgat@cern.ch
//
#include <A1526Timer.h>

using namespace std;

A1526TimerWindow::A1526TimerWindow( A1526Control *parent, 
				    unsigned short j, unsigned short i) 
{
  myA1526Control = parent;
  myenviro = parent->getEnviro();
  //  oconsole = mainparent->getOConsole();
  slot = j; 
  channel = i;
  running = false;

  future = new QFuture<void>;
  futurewatcher = new QFutureWatcher<void>;
  connect(futurewatcher, SIGNAL(finished()), this, SLOT(next()));

  /*
  fstream readfile("measurements.dat");
  string line;
  if ( !readfile.is_open() ) {
    print("No measurements.dat file found\n");
  } else {
    while ( !readfile.eof() ) {
      getline(readfile,line);
      if ( line.size() > 0 ) 
	measurements << line.c_str();
    }
    readfile.close();
  }
  */
}

/****************************************
 * To handle the messages of this class *
 ****************************************/
void A1526TimerWindow::printc(const char* format, ...)
{
  //*oconsole << 
  QString premessage, message;
  premessage.sprintf("A1526Timer:\t");
  //emit consolewrite(message);
  va_list args;
  va_start(args, format);
  //*oconsole << 
  message.vsprintf(format, args);
  va_end(args);

  emit consolewrite(premessage+message);
  //oconsole->flush();
}

void A1526TimerWindow::print(const char* format, ...)
{
  va_list args;
  va_start(args, format);
  printf("A1526Timer:\t");
  vprintf(format, args);
  //  printf("\n");
  va_end(args);
}

//-------------------------------------------------------------------------
// Configure and start timer
void A1526TimerWindow::start( QString measurementtype_ ) {

  if (running) {
    printc("Stopping measurements for ch %i-%i\n", slot, channel);
    stop();
    return;
  }
  
  bool ok = true;
  //  filename = QInputDialog::getText(this, tr("Load program"), 
  //				   tr("File name:"), 
  //				   QLineEdit::Normal, 
  //				   "DarkCurrent1.txt", &ok);
  if ( measurementtype_.isEmpty() )
    measurementtype = QInputDialog::getItem(this, tr("Load Measurement"), 
					    tr("Measurement Config:"), 
					    myA1526Control->getMeasurements(), 
					    0, true, &ok);
  else
    measurementtype = measurementtype_;
  
  if (ok && !measurementtype.isEmpty()) {
    fstream readfile;
    QByteArray ba = 
      ("/home/daq/RPClab/config/"+measurementtype+".txt").toLatin1();
    readfile.open(ba.data());
    if ( !readfile.is_open() ) {
      printc("Could not open %s description file\n", measurementtype.data());
      return;
    }
    
    string dummy;
    int duration, on;
    unsigned long voltage;
    float current;
    int Events;
    bool veffon;
    A1526TimerEvents.clear();

    getline(readfile, dummy);
    getline(readfile, dummy);
    readfile >> Events;
    for ( int i = 0; i < Events; ++i ) { 
      //      while ( !readfile.eof() ) {
      readfile >> duration >> on >> voltage >> veffon >> current;
      A1526TimerEvents.push_back( new A1526TimerEvent( duration, 
						       on==1? true : false, 
						       voltage, current )); 
    }
    readfile.close();
    
    // only start if non-zero events are present
    printc("Executing %i measurement steps for ch %i-%i\n", 
    	   A1526TimerEvents.size(), slot, channel); 
    
    if ( A1526TimerEvents.size() ) {

      time(&startTime);       // Get time0
      struct tm * now = localtime(&startTime);
      int month = now->tm_mon;
      int day = now->tm_mday;
      int hour = now->tm_hour;
      int minut = now->tm_min;

      sprintf(timetag, "%s_%02i_%02i_%02i_%02i", 
	      measurementtype.toAscii().data(), month+1, day, hour, minut);
      myA1526Control->setGraphFilenameTag(slot, channel, timetag);
      myA1526Control->changeVvalmode(slot, channel, veffon);
      myA1526Control->setReadOnly(slot, channel, true);
      myA1526Control->resetGraphs(slot, channel);
      myA1526Control->setEnableGraph(slot, channel, true);
      
      // start the measurement
      currentstep = -1;
      running = true;
      next();
    }
  }
}

//-------------------------------------------------------------------------
void A1526TimerWindow::stop() {

  for ( unsigned short i = 0; i < A1526TimerEvents.size(); ++i ) {
    delete A1526TimerEvents.at(i);
  }
  //A1526TimerEvents.erase( A1526TimerEvents.begin(), A1526TimerEvents.end() );
  A1526TimerEvents.clear();
  
  // switch channel off
  myA1526Control->changeVvalmode(slot, channel, false);  
  myA1526Control->changeVval( slot, channel, 0. );
  myA1526Control->setEnableGraph(slot, channel, false);
  myA1526Control->setParameter(slot, channel, "Pw", false );
  myA1526Control->setReadOnly(slot, channel, false);

  running = false;

}

//-------------------------------------------------------------------------
void A1526TimerWindow::runevent(int step) {

  //  printc("Running step %i for ch %i-%i in thread %i\n", step, slot,
  //	 channel, thread()->currentThread()); 
  //  if ( myA1526Control->getStatus(slot, channel) 
  //   != A1526TimerEvents[step]->getOn() ) 
  //myA1526Control->changeOnOff(slot, channel);
  myA1526Control->setParameter(slot, channel, "Pw", 
			       A1526TimerEvents[step]->getOn() );
  myA1526Control->changeIset(slot, channel, 
			     A1526TimerEvents[step]->getCurrent());
  myA1526Control->changeVval(slot, channel, 
			     A1526TimerEvents[step]->getVoltage()); 
  sleep(1); // give it a bit of time to update
  
  // check if channel stopped ramping
  while ( myA1526Control->getStatusval(slot, channel) != 1 ) {
    //cout << "waiting for channel to switch to on" << endl;
    sleep(5);
  }

  sleep(120); // some additional 2min waiting time to let things stabilise

  // initial conditions
  myenviro->ResetMinMax(); // keep track of p0 min/max during measurement
  float Tenv0 = myenviro->getTenv();
  float Penv0 = myenviro->getPenv();
  float Henv0 = myenviro->getHenv();
  float Tgas0 = myenviro->getTgas();
  float Hgas0 = myenviro->getHgas();
  float Imon0 = myA1526Control->getParameter(slot, channel, "IMon");

  // start the measurement
  myA1526Control->setEnableImonGraphs2(slot, channel, true);
  sleep(A1526TimerEvents[step]->getTime()*60); // time specified in min
  myA1526Control->setEnableImonGraphs2(slot, channel, false);

  // final conditions
  float Penv_min = myenviro->getPenvMin();
  float Penv_max = myenviro->getPenvMax();

  float Tenv1 = myenviro->getTenv();
  float Penv1 = myenviro->getPenv();
  float Henv1 = myenviro->getHenv();
  float Tgas1 = myenviro->getTgas();
  float Hgas1 = myenviro->getHgas();
  float Imon1 = myA1526Control->getParameter(slot, channel, "IMon");
  
  // compute average environmental conditions during measurement
  float mTenv = .5 * ( Tenv0 + Tenv1 );
  float mPenv = .5 * ( Penv0 + Penv1 );
  float mHenv = .5 * ( Henv0 + Henv1 );
  float mTgas = .5 * ( Tgas0 + Tgas1 );
  float mHgas = .5 * ( Hgas0 + Hgas1 );
  printc("Measured Imon values for ch %i-%i : %f +- %f\n", slot, channel, 
	 myA1526Control->getImonMean(slot, channel),
	 myA1526Control->getImonRMS(slot, channel));

  // add data to output file
  // GAP SERIAL NUMBER,HV_1010,HV_app,I_mon,
  // Env_T[degC],Env_P[mbar],Env_RH[%],Gas_T[degC],Gas_RH[%]
  ofstream outputfile;
  QString filename = "measurements/"
    + myA1526Control->getRPCCodeString(slot, channel) 
    + "_" + myA1526Control->getGraphFilenameTag(slot, channel)
    + ".csv";
  outputfile.open( filename.toAscii().data(), ios::out | ios::app );

  if ( measurementtype == "DarkCurrent1" ) {
    outputfile 
      << (myA1526Control->getRPCCodeString(slot, channel)).toAscii().data() 
      << ","
      << myA1526Control->getVeff(A1526TimerEvents[step]->getVoltage()) << ","
      << A1526TimerEvents[step]->getVoltage() << ","
      << myA1526Control->getImonMean(slot, channel) << ","
      << mTenv << ","
      << mPenv << ","
      << mHenv << ","
      << mTgas << ","
      << mHgas 
      << endl;
  } else if ( measurementtype == "DarkCurrent2" ) {
    outputfile
      << (myA1526Control->getRPCCodeString(slot, channel)).toAscii().data() 
      << ","
      << A1526TimerEvents[step]->getVoltage() << ","
      << Imon0 << ","
      << Imon1 << ","
      << Penv0 << ","
      << Penv1 << ","
      << myA1526Control->getImonMin(slot, channel) << ","
      << myA1526Control->getImonMax(slot, channel) << ","
      << Penv_min << ","
      << Penv_max << ","
      << "1"        // this is the accept/reject field to be modified by user
      << ",,,,,,,"  // lots of empty fields for the DB interface
      << endl;
  }
  
  outputfile.close();
}

//-------------------------------------------------------------------------
void A1526TimerWindow::next() {
  
  if ( ++currentstep < A1526TimerEvents.size() ) {  
    printc("Starting measurement step %i for ch. %i-%i\n", currentstep,
	   slot, channel);
    *future = QtConcurrent::run(this, 
				&A1526TimerWindow::runevent, currentstep);  
    futurewatcher->setFuture(*future);
  } else {
    printc("Measurements done for ch. %i-%i\n", slot, channel);
    stop();
  }
}

