// COCOA class implementation file
// Id:  Measurement.C
// CAT: Model
// ---------------------------------------------------------------------------
// History: v1.0 
// Authors:
//   Pedro Arce

#include "MeasurementCOPS.h"
#include "LightRay.h"
#include "Model.h"
#include "Fit.h"
#include "ALIVRMLMgr.h"

#include <iostream.h>
#include <iomanip.h>

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@@ calculate the simulated value propagating the light ray through the OptO that take part in the Measurement
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void MeasurementCOPS::calculateSimulatedValue( ALIbool firstTime ) 
{
 
  if( Utils::debug >= 3) cout << endl << "@@@@ Start calculation simulated value of Measurement " << this->name() << endl;

  //---------- Create light ray
  LightRay lightray;

  //---------- Define types of OptO that may take part in the Measurement
  int isec = 0;  //security variable to check OptOList().size()

  //---------- Loop list of OptO that take part in measurement
  vector<OpticalObject*>::const_iterator vocite =  OptOList().begin();
  if( Utils::debug >= 5) cout  << "OptOList size" <<OptOList().size() << endl;

  //----- Check that first object is 'Xlaser' 
  if( (*vocite)->type() != "Xlaser" ) { 
    cerr << "!!ERROR MeasurementCOPS: first Optical object should be 'Xlaser'" << endl;
    DumpBadOrderOptOs();
    exit(1);
  }     

  //---------- Check that last object is a COPS Sensor (that makes measuremnt and kill the lightray)
  if( ( *(OptOList().end() -1) )->type() != "COPS" ) { 
    cerr << "!!ERROR MeasurementCOPS: last Optical object should be 'COPS'" << endl;
    DumpBadOrderOptOs();
    exit(1);
  }     


  while( (*vocite) !=  *(OptOList().end()) ) {
    if( Utils::debug >= 2) cout << endl << "@@@@ LR:OBJECT " << (*vocite)->name() << endl;  
    isec ++;

    //---------- Get the behaviour of the object w.r.t the measurement (if it reflects the light, let it traverse it, ...)
    ALIstring behav = getMeasuringBehaviour(vocite);

    if( &lightray ) {
      (*vocite)->participateInMeasurement( lightray, *this, behav );

      if( Fit::getFirstTime() ) {
	if(Model::GlobalOptions()["writeVRML"] > 1) {
	  ALIVRMLMgr::getInstance().addLightPoint( lightray.point() );
	  //	  cout << "ALIVRMLMg  addLightPoint " << lightray.point() << (*vocite)->name() << endl;
	}
      }

    } else {
      cerr << "!! Last object is not Sensor 2D in measurement " << name() << endl;
      DumpBadOrderOptOs();
      exit(1);
    }

    vocite++;
    if ( isec > OptOList().size() ) {
      cerr << "ERROR DE PROGRAMACION EN GetSimulatedValue" << endl;
      exit(5);
    }
  }

 
  if(Utils::debug >= 9) cout << "end calculateSimulatedValue" <<endl;
  
}



//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@@ You input 8 numbers after 'TILMETER':
//@@  
//@@ set the conversion factor from mV to mrad and the pedestal 
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void MeasurementCOPS::setConversionFactor( vector<ALIstring> wordlist ) 
{
  //--------- Set it to 0 
  ALIuint ii;
  for( ii = 0; ii < dim(); ii++) {
    theDisplace[ii] = 0.; 
  }

  //--------- Check that the format is OK
  if(wordlist.size() == 1) return; 
  if( wordlist.size() != 3 
      || !Utils::IsNumber(wordlist[1]) || !Utils::IsNumber(wordlist[2])
      || !Utils::IsNumber(wordlist[3]) || !Utils::IsNumber(wordlist[4]) ) {
    cerr << "!! SensorCOPS Measurement setConversionFactor: WRONG FORMAT "<<  endl 
	 << "It should be: SENSOR2D displace_U displace_D displace_L displace_R " << endl 
	 << "It is: ";
    ostream_iterator<ALIstring> outs(cout," ");
    copy(wordlist.begin(), wordlist.end(), outs);
    cout << endl;
    exit(1);
  }

  for( ii = 0; ii < dim(); ii++) {
    theDisplace[ii] = atof(wordlist[ii+1].c_str())* valueDimensionFactor();
  }

}



void MeasurementCOPS::correctValueAndSigma()
{
   //---------- Make  displacement
  ALIuint ii;
  for( ii = 0; ii < dim(); ii++) { 
    ALIdouble val = value()[ii];
    val += theDisplace[ii];
    if(Utils::debug >= 9) cout << "MeasurementCOPS::correctValueAndSigma: old value X " << value()[ii] << " new " << val << " +- " << endl;
    setValue( ii, val );
  }

}

