#include "DetectorEffiCorrection.hh"
//////////////////////////////////////////////////////////
DetectorEffiCorrection::
DetectorEffiCorrection()
{
    Initialize();
}
//////////////////////////////////////////////////////////
DetectorEffiCorrection::
DetectorEffiCorrection( ElementContainerMatrix *ecm ){
    Initialize();
    SetTarget(ecm);
}
//////////////////////////////////////////////////////////
DetectorEffiCorrection::
DetectorEffiCorrection( ElementContainerMatrix *ecm, std::string filepath ){
    Initialize();
    SetTarget(ecm);
    LoadEffiData( filepath );
}
//////////////////////////////////////////////////////////
DetectorEffiCorrection::
~DetectorEffiCorrection()
{
    delete _FCD;
}
//////////////////////////////////////////////////////////
void DetectorEffiCorrection::
Initialize()
{
    //_FCD = new FtlCalcDetectorEffi();
    _FCD = new SASCalcDetectorEffi();
    _EffiDataFilePath = "";
    _MessageTag = "DetectorEffiCorrection::";
}
//////////////////////////////////////////////////////////
void DetectorEffiCorrection::
LoadEffiData( std::string filepath ){
    _FCD->loadData( filepath );
    _EffiDataFilePath = filepath;
}
//////////////////////////////////////////////////////////
Double DetectorEffiCorrection::
CalcSecAtPixel( std::vector<Double> *det_unit_vec, std::vector<Double> *pixel_ori_vec ){
    if (det_unit_vec->size()!=3) return 0;
    Double dx = (*det_unit_vec)[0];
    Double dy = (*det_unit_vec)[1];
    Double dz = (*det_unit_vec)[2];
    Double px = (*pixel_ori_vec)[0];
    Double py = (*pixel_ori_vec)[1];
    Double pz = (*pixel_ori_vec)[2];
    Double pl = sqrt(px*px+py*py+pz*pz);
    px = px/pl;
    py = py/pl;
    pz = pz/pl;

    Double ax = dy*pz - dz*py;
    Double ay = dz*px - dx*pz;
    Double az = dx*py - dy*px;

    return 1.0/( sqrt( ax*ax + ay*ay + az*az ) );

}
//////////////////////////////////////////////////////////
void DetectorEffiCorrection::
Execute(){
    if (_EffiDataFilePath==""){
        std::cout << _MessageTag+"Execute : No load efficiency data file" << std::endl;
        return;
    }

    ElementContainerMatrix *ecm = Put();
    HeaderBase* h_ecm = ecm->PutHeaderPointer();
    std::vector<std::string> process = h_ecm->PutStringVector("DATAPROCESSED");

    for (UInt4 i=0; i<ecm->PutSize(); i++){
        ElementContainerArray* eca = ecm->PutPointer(i);
        std::vector<Double> det_posi_info = eca->PutHeaderPointer()->PutDoubleVector("DETPOSINFO");
        std::vector<Double> det_unit_v(3,0.0);
        Double LL = sqrt( det_posi_info[3]*det_posi_info[3] + det_posi_info[4]*det_posi_info[4] + det_posi_info[5]*det_posi_info[5] );
        det_unit_v[0] = det_posi_info[3]/LL;
        det_unit_v[1] = det_posi_info[4]/LL;
        det_unit_v[2] = det_posi_info[5]/LL;

        for (UInt4 j=0; j<eca->PutSize(); j++){
            ElementContainer* ec = eca->PutPointer(j);
            std::vector<Double> p_vect = ec->PutHeaderPointer()->PutDoubleVector("PixelPosition");
            std::vector<Double> lambda = ec->Put("Lamb");
            std::vector<Double> intens = ec->PutY();
            std::vector<Double> errors = ec->PutE();
            std::string Xkey = ec->PutXKey();
            std::string Ikey = ec->PutYKey();
            std::string Ekey = ec->PutEKey();

            for (UInt4 k=0; k<lambda.size(); k++){
                Double sec_v = fabs( CalcSecAtPixel( &det_unit_v, &p_vect ) );
                //std::cout << "##### sec_v=" << sec_v << std::endl;
                if (sec_v!=0){
                    Double effi_v = _FCD->PutApproximateVal( lambda[k], sec_v );
                    intens[k] = intens[k]/effi_v;
                    errors[k] = errors[k]/effi_v;
                }else{
                    break;
                }
            }

            ec->Replace( Ikey, intens );
            ec->Replace( Ekey, errors );
            ec->SetKeys( Xkey, Ikey, Ekey );
        }
    }

    std::string pp = "DetectorEffiCorrection with "+_EffiDataFilePath;
    process.push_back( pp );
    h_ecm->OverWrite("DATAPROCESSED",process);

}
//////////////////////////////////////////////////////////
void DetectorEffiCorrection::
N2MonEffiCorrection( ElementContainer* ec, double p_N2, double thickness, double thick_Al ){
    std::vector<Double> lambda = ec->Put("Lamb");
    std::vector<Double> intens = ec->PutY();
    std::vector<Double> errors = ec->PutE();
    std::string Xkey = ec->PutXKey();
    std::string Ikey = ec->PutYKey();
    std::string Ekey = ec->PutEKey();

    thickness = thickness/10.0;  // [mm]->[cm]
    thick_Al = thick_Al/10.0;    // [mm]->[cm]
    for (UInt4 i=0; i<lambda.size(); i++){
        double nn1 = 1-exp(-1.0*(5.034E-5)*p_N2*lambda[i]*thickness);
        double nn2 = exp( (-1.0*(1.11E-2))*lambda[i]-(9.77E-2)*thick_Al );

        intens[i] = intens[i]/(nn1*nn2);
        errors[i] = errors[i]/(nn1*nn2);
        //std::cout << "#lambda, n(lambda)=" << lambda[i] << "," << nn1*nn2 << std::endl;
    }
    ec->Replace( Ikey, intens );
    ec->Replace( Ekey, errors );
    ec->SetKeys( Xkey, Ikey, Ekey );

}
