#include "CreateLambVector.hh"
//////////////////////////////////////////////////////////
CreateLambVector::
CreateLambVector()
{
    Initialize();
}

//////////////////////////////////////////////////////////
CreateLambVector::
CreateLambVector(ElementContainerMatrix *ecm, Double L1_in)
{
    Initialize();
    SetTarget(ecm);
    SetL1( L1_in );
}

//////////////////////////////////////////////////////////
CreateLambVector::
~CreateLambVector()
{
    delete UU;
}

//////////////////////////////////////////////////////////
void CreateLambVector::
Initialize(){
    _MessageTag = "CreateLambVector::";
    L1 = 0.0;
    UU = new UtsusemiUnitConverter();
}
//////////////////////////////////////////////////////////
void CreateLambVector::
SetL1( Double L1_in ){
    L1 = L1_in;
}
//////////////////////////////////////////////////////////
std::vector<Double> CreateLambVector::
CalcLambFromTof( HeaderBase* head_ec, std::vector<Double> tof, bool isHist ){
    std::vector<Double> ret;

    if ( L1==0.0 ){
        if (head_ec->CheckKey("L1")==0){
            std::string msg = _MessageTag+"CalcLambFromTof >> L1 is not defined";
            std::cout << msg << std::endl;
            return ret;
        }else{
            L1 = head_ec->PutDouble("L1");             // If L1 depends on pixel posi, use this option
        }
    }

    std::vector<Double> pv = head_ec->PutDoubleVector("PixelPosition");
    Double L2 = sqrt( pv[0]*pv[0] + pv[1]*pv[1] + pv[2]*pv[2] );

    if (isHist){
        ret.resize( tof.size() );
        for (UInt4 i=0; i<tof.size(); i++)
            ret[i] = UU->TLtoLambda( tof[i], (L1+L2)/1000.0 ); // tof [micro-sec] / L [m]
    }else{
        ret.resize( tof.size()-1 );
        for (UInt4 i=0; i<(tof.size()-1); i++)
            ret[i] = UU->TLtoLambda( ((tof[i]+tof[i+1])/2.0), (L1+L2)/1000.0 );  // tof [micro-sec] / L [m]
    }

    return ret;
}
//////////////////////////////////////////////////////////
std::vector<Double> CreateLambVector::
CalcLambFromEnergy( HeaderBase* head_ec, std::vector<Double> energy, bool isHist ){
    std::vector<Double> ret;

    if (isHist){
        ret.resize( energy.size() );
        for (UInt4 i=0; i<energy.size(); i++)
            ret[i] = (UU->VtoLambda())*(UU->EtoV(energy[i]));
    }else{
        ret.resize( energy.size()-1 );
        for (UInt4 i=0; i<(energy.size()-1); i++)
            ret[i] = (UU->VtoLambda())*(UU->EtoV((energy[i]+energy[i+1])/2.0));
    }

    return ret;
}
//////////////////////////////////////////////////////////
std::vector<Double> CreateLambVector::
CalcLambFromQ( HeaderBase* head_ec, std::vector<Double> moment, bool isHist ){
    std::vector<Double> ret;

    if (isHist){
        ret.resize( moment.size() );

        for (UInt4 i=0; i<moment.size(); i++){
            Double vv = moment[i]/(UU->Vmm_msToK()); // [mm/micro-sec]
            ret[i] = (UU->VtoLambda())*vv/1000.0;
        }

    }else{
        ret.resize( moment.size()-1 );

        for (UInt4 i=0; i<(moment.size()-1); i++){
            Double vv = ((moment[i]+moment[i+1])/2.0)/(UU->Vmm_msToK()); // [mm/micro-sec]
            ret[i] = (UU->VtoLambda())*vv/1000.0;
        }
    }
    return ret;
}

//////////////////////////////////////////////////////////
bool CreateLambVector::
Execute(){
    CalcSphericalAngles( -1.0, -1.0, -1.0 );

    ElementContainerMatrix *ecm = Put();
    HeaderBase* h_ecm = ecm->PutHeaderPointer();

    if ( (L1==0.0)&&(h_ecm->CheckKey("L1")==1) ){ // Input L1 unit must be mm
        L1 = h_ecm->PutDouble("L1");
        //std::cout << " Header has L1 " << L1 <<  std::endl;
    }else{
        std::cout << _MessageTag+" Header has No L1 " << std::endl;
    }

    bool ret = false;

    for (UInt4 i=0; i<ecm->PutSize(); i++){
        ElementContainerArray* eca = ecm->PutPointer(i);
        for (UInt4 j=0; j<eca->PutSize(); j++){
            std::vector<Double> Lamb_v;
            std::vector<Double> Lambda_v;
            ElementContainer* ec = eca->PutPointer(j);
            std::string xkey= ec->PutXKey();
            if (xkey.find("TOF")!=std::string::npos){
                Lamb_v = CalcLambFromTof( ec->PutHeaderPointer(), ec->PutX(), false );
                Lambda_v = CalcLambFromTof( ec->PutHeaderPointer(), ec->PutX(), true );
            }
            if (xkey=="d"){
                Lamb_v = CalcLambFromTof( ec->PutHeaderPointer(), ec->Put("TOF"), false );
                Lambda_v = CalcLambFromTof( ec->PutHeaderPointer(), ec->Put("TOF"), true );
            }
            if (xkey.find("Energy")!=std::string::npos){
                Lamb_v = CalcLambFromEnergy( ec->PutHeaderPointer(), ec->PutX(), false );
                Lambda_v = CalcLambFromEnergy( ec->PutHeaderPointer(), ec->PutX(), true );
            }
            if (xkey.find("MomentumTransfer")!=std::string::npos){
                Lamb_v = CalcLambFromQ( ec->PutHeaderPointer(), ec->PutX(), false );
                Lambda_v = CalcLambFromQ( ec->PutHeaderPointer(), ec->PutX(), true );
            }
            if (xkey.find("Lambda")!=std::string::npos){
                std::vector<Double> xx = ec->PutX();
                Lamb_v.resize(xx.size()-1) ;
                for (UInt4 k=0; k<(xx.size()-1); k++)
                    Lamb_v[k] = (xx[k]+xx[k+1])/2.0;
            }
            ec->Add( "Lamb", Lamb_v, "Ang" );
            if (Lambda_v.empty()){
            }else
                ec->Add( "Lambda", Lambda_v, "Ang" );

        }
    }

    std::vector<std::string> process = h_ecm->PutStringVector("DATAPROCESSED");
    process.push_back("CreateLambVector");
    h_ecm->OverWrite("DATAPROCESSED",process);

    return true;
}

//////////////////////////////////////////////////////////
void CreateLambVector::
CalcSphericalAngles(double dx, double dy, double dz){
    ElementContainerMatrix *ecm = Put();
    HeaderBase* h = ecm->PutHeaderPointer();
    std::vector<std::string> process = h->PutStringVector("DATAPROCESSED");

    for (std::vector<std::string>::iterator it=process.begin(); it!=process.end(); ++it)
        if ((*it).find("Phi Calculation")!=std::string::npos) return;

    UtsusemiReductionCommon URC( ecm );
    URC.CalcPhi(dx,dy,dz);

    return;
}
