#include "VanadiumToolsChoppers.hh"
//////////////////////////////////////////////////////////
VanadiumToolsChoppers::
VanadiumToolsChoppers()
{
    keptECM = NULL;
    CommentHead = "VanadiumTools >>";
}
//////////////////////////////////////////////////////////
VanadiumToolsChoppers::
~VanadiumToolsChoppers()
{
    delete keptECM;
}
//////////////////////////////////////////////////////////
bool VanadiumToolsChoppers::
CheckDataProcessed( ElementContainerMatrix *ecm, std::string process )
{
    HeaderBase *h;
    h=ecm->PutHeaderPointer();

    std::vector<std::string> process_v = h->PutStringVector(UTSUSEMI_KEY_HEAD_DATAPROCESSED);

    bool ret = false;
    for (UInt4 i=0; i<process_v.size(); i++){
        std::string::size_type index = process_v[i].find( process );
        if (index != std::string::npos){
            ret = true;
        }
    }
    return ret;

}
//////////////////////////////////////////////////////////
ElementContainer VanadiumToolsChoppers::
SummationEnergyRegion( ElementContainerMatrix *ecm, double Emin, double Emax )
{
    ElementContainerArray* eca;
    ElementContainer* ec;
    UInt4 num_of_ec;
    std::string type_s,xkey,ykey,ekey;
    std::string::size_type index;
    HeaderBase *h;
    std::vector<double> new_int,new_err;

    ElementContainer *new_ec = new ElementContainer( ecm->PutHeader() );

    UInt4 init_num = (ecm->PutTableSize())*(ecm->PutPointer(0)->PutTableSize());
    std::vector<Int4> PSDID(init_num,0),Masked(init_num,1),Included(init_num,0);
    std::vector<UInt4> PixelID(init_num,0);
    std::vector<double> Intensity(init_num,0.0),Error(init_num,0.0),Erange(2,0.0);

    UInt4 id;
    Double total_sum = 0.0;
    UInt4 num_of_pixel = 0;

    Erange[0] = Emin;
    Erange[1] = Emax;


    for (UInt4 i=0; i<(ecm->PutTableSize()); i++){
        eca = ecm->PutPointer(i);

        type_s = eca->PutHeaderPointer()->PutString(UTSUSEMI_KEY_HEAD_DETTYPE);
        index = type_s.find(UTSUSEMI_KEY_HEAD_DETTYPE_MONITOR);
        if (index == std::string::npos){
            num_of_ec = eca->PutTableSize();
            for (UInt4 j=0; j<num_of_ec; j++){
                ec = eca->PutPointer(j);
                h = ec->PutHeaderPointer();
                //std::vector<Double> result_sum = ec->Sum(Emin,Emax);
                std::pair<Double,Double> result_sum = ec->Sum(Emin,Emax);

                id = h->PutInt4(UTSUSEMI_KEY_HEAD_PIXELID);
                if (id > (PixelID.size()-1)){
                    PixelID.resize( (id+1),0 );
                    PSDID.resize( (id+1),0 );
                    Intensity.resize( (id+1),0.0 );
                    Error.resize( (id+1),0.0 );
                    Masked.resize( (id+1),1 );
                    Included.resize( (id+1),0 );
                }

                PSDID[id]     = h->PutInt4("PSDID");
                PixelID[id]   = h->PutInt4(UTSUSEMI_KEY_HEAD_PIXELID);
                //Intensity[id] = result_sum[0];
                //Error[id]     = result_sum[1];
                Intensity[id] = result_sum.first;
                Error[id]     = result_sum.second;
                Masked[id]    = h->PutInt4(UTSUSEMI_KEY_HEAD_MASKED);
                Included[id]  = 1;

                //total_sum += result_sum[0];
                total_sum += result_sum.first;
                num_of_pixel +=1;
            }
        }
    }

    Int4 last_id = PixelID[ PixelID.size()-1 ];
    PixelID.push_back( last_id );
    h = new_ec->PutHeaderPointer();
    h->Add("MASKEDLIST",Masked);
    h->Add("PSDIDLIST",PSDID);
    h->Add("EnergyRange",Erange);
    h->Add("Included",Included);
    h->Add("AverageCount",(total_sum/double(num_of_pixel)));

    new_ec->Add(UTSUSEMI_KEY_HEAD_PIXELID,PixelID);
    new_ec->Add(UTSUSEMI_KEY_HEAD_TOTALCOUNTS,Intensity);
    new_ec->Add("TotalCountsError",Error);
    new_ec->SetKeys(UTSUSEMI_KEY_HEAD_PIXELID,UTSUSEMI_KEY_HEAD_TOTALCOUNTS,"TotalCountsError");

    return *new_ec;

}
//////////////////////////////////////////////////////////
ElementContainer VanadiumToolsChoppers::
MakeWhiteVanData( ElementContainerMatrix *ecm, double Emin, double Emax, double tof_offset )
{
    if (Emin>Emax){
        double dammy = Emin;
        Emin = Emax;
        Emax = dammy;
    }
    std::vector<double> new_bin;
    new_bin.push_back( Emin );
    new_bin.push_back( Emax );

    //ElementContainerMatrix *new_ecm;
    if (!CheckDataProcessed( ecm, "TOF TO ENERGY CONVERSION" )){
        //new_ecm = new ElementContainerMatrix( *ecm );
        keptECM = new ElementContainerMatrix( *ecm );
        std::cout << "VanadiumTools >> This data has never passed through TOF TO ENERGY CONVERSION." << std::endl;
        TofToEnergyChoppers *tof2energy = new TofToEnergyChoppers();
        //tof2energy->SetTarget(new_ecm);
        tof2energy->SetTarget(keptECM);
        tof2energy->TofToEnergy( tof_offset, new_bin );
        delete tof2energy;
    }else{
        //new_ecm = ecm;
        keptECM = new ElementContainerMatrix( *ecm );
    }

    //ElementContainer van_ec = SummationEnergyRegion( new_ecm, Emin, Emax );
    ElementContainer van_ec = SummationEnergyRegion( keptECM, Emin, Emax );
    HeaderBase *h = van_ec.PutHeaderPointer();
    h->Add("VanadiumType","White");

    return van_ec;

}
//////////////////////////////////////////////////////////
ElementContainer VanadiumToolsChoppers::
MakeWhiteVanData( ElementContainerMatrix *data, double Emin, double Emax )
{
    return MakeWhiteVanData( data, Emin, Emax, 0.0 );
}
//////////////////////////////////////////////////////////
ElementContainer VanadiumToolsChoppers::
MakeMonoVanData( ElementContainerMatrix *ecm, double Ei, double deltaEi, double tof_offset )
{
    double Emin = Ei - deltaEi;
    double Emax = Ei + deltaEi;

    std::vector<double> new_bin;
    new_bin.push_back( Emin );
    new_bin.push_back( Emax );
    //ElementContainerMatrix *new_ecm;
    if (!CheckDataProcessed( ecm, "TOF TO ENERGY TRANSFER CONVERSION" )){
        //new_ecm = new ElementContainerMatrix( &ecm );
        keptECM = new ElementContainerMatrix( *ecm );

        TofToEnergyTransfer *T2ET = new TofToEnergyTransfer();
        //T2ET->SetTarget( new_ecm );
        T2ET->SetTarget( keptECM );
        T2ET->Tof2EnergyTransfer( tof_offset, new_bin );
        delete T2ET;
    }else{
        //new_ecm = &ecm;
        keptECM = new ElementContainerMatrix( *ecm );
    }


    //ElementContainer van_ec = SummationEnergyRegion( new_ecm, Emin, Emax );
    ElementContainer van_ec = SummationEnergyRegion( keptECM, Emin, Emax );
    HeaderBase *h = van_ec.PutHeaderPointer();
    h->Add("VanadiumType","White");

    return van_ec;
}
//////////////////////////////////////////////////////////
ElementContainer VanadiumToolsChoppers::
MakeMonoVanData( ElementContainerMatrix *ecm, double deltaEi )
{
    double Ei = ecm->PutHeaderPointer()->PutDouble(UTSUSEMI_KEY_HEAD_EI);
    return MakeMonoVanData( ecm, Ei, deltaEi, 0.0 );

}

//////////////////////////////////////////////////////////
void VanadiumToolsChoppers::
CorrectWhiteVan( ElementContainerMatrix *data, ElementContainer wvdata )
{
    HeaderBase *h = wvdata.PutHeaderPointer();
    std::vector<double> Erange    = h->PutDoubleVector("EnergyRange");
    std::vector<double>  PixelID  = wvdata.PutX();
    std::vector<double> Intensity = wvdata.PutY();
    std::vector<double> Error     = wvdata.PutE();

    std::vector<Int4> PSDID       = h->PutInt4Vector("PSDIDLIST");
    std::vector<Int4> Masked      = h->PutInt4Vector("MASKEDLIST");
    std::vector<Int4> Included    = h->PutInt4Vector("Included");

    ElementContainer *ec;
    ElementContainerArray *eca;
    HeaderBase *hec;
    double pid,cnt,err;
    //double av_cnt;
    std::vector<double> xx,yy,ee;
    std::string xtitle,ytitle,etitle;
    for (UInt4 i=0; i<data->PutTableSize(); i++){
        eca = data->PutPointer(i);
        std::cout << "Correct White Van psd=" << i << std::endl;
        for (UInt4 j=0; j<eca->PutTableSize(); j++){
            ec = eca->PutPointer(j);
            hec = ec->PutHeaderPointer();
            pid = hec->PutInt4(UTSUSEMI_KEY_HEAD_PIXELID);
            if ((pid>PixelID.size()) || (Included[pid]==0)){
                std::cout << "There is no White Vanadium information about PixelID=" << pid << std::endl;
                throw "EXCEPTION: given data does not match with vanadium data.";
            }

            //av_cnt = h->PutDouble("AverageCount");
            //cnt = Intensity[pid]/av_cnt;
            //err = Error[pid]/av_cnt;
            cnt = Intensity[pid];
            err = Error[pid];
            yy = ec->PutY();
            ee = ec->PutE();
            xtitle = ec->PutXKey();
            ytitle = ec->PutYKey();
            etitle = ec->PutEKey();
            for (UInt4 k=0; k<yy.size(); k++){
                ee[k]=sqrt( pow( (ee[k]/cnt),2.0 )+pow( (yy[k]/cnt/cnt),2.0)*pow( err, 2.0) );
                yy[k]=yy[k]/cnt;
            }
            ec->Replace(ytitle,yy);
            ec->Replace(etitle,ee);
            ec->SetKeys(xtitle,ytitle,etitle);

        }
    }
    std::cout << "finish Correct White Van" << std::endl;
    //return data;

}
//////////////////////////////////////////////////////////
ElementContainerMatrix VanadiumToolsChoppers::
CorrectMonVan( ElementContainerMatrix data, ElementContainer mvdata )
{

    return data;
}
//////////////////////////////////////////////////////////
ElementContainerMatrix VanadiumToolsChoppers::
CorrectAllVan( ElementContainerMatrix data, ElementContainer wvdata, ElementContainer mvdata, ElementContainer wmvdata )
{
    // White Vanadium for measurement of sample
    HeaderBase *wv_h = wvdata.PutHeaderPointer();
    std::vector<double> wv_PixelID   = wvdata.PutX();
    std::vector<double> wv_Intensity = wvdata.PutY();
    std::vector<double> wv_Error     = wvdata.PutE();

    std::vector<Int4> wv_PSDID       = wv_h->PutInt4Vector("PSDIDLIST");
    std::vector<Int4> wv_Masked      = wv_h->PutInt4Vector("MASKEDLIST");
    std::vector<Int4> wv_Included    = wv_h->PutInt4Vector("Included");

    // White Vanadium for measurement of Monochro Vanadium
    HeaderBase *wmv_h = wmvdata.PutHeaderPointer();
    std::vector<double> wmv_PixelID   = wmvdata.PutX();
    std::vector<double> wmv_Intensity = wmvdata.PutY();
    std::vector<double> wmv_Error     = wmvdata.PutE();

    std::vector<Int4> wmv_PSDID       = wmv_h->PutInt4Vector("PSDIDLIST");
    std::vector<Int4> wmv_Masked      = wmv_h->PutInt4Vector("MASKEDLIST");
    std::vector<Int4> wmv_Included    = wmv_h->PutInt4Vector("Included");

    // Monochro Vanadium
    HeaderBase *mv_h = mvdata.PutHeaderPointer();
    std::vector<double> mv_PixelID   = mvdata.PutX();
    std::vector<double> mv_Intensity = mvdata.PutY();
    std::vector<double> mv_Error     = mvdata.PutE();

    std::vector<Int4> mv_PSDID       = mv_h->PutInt4Vector("PSDIDLIST");
    std::vector<Int4> mv_Masked      = mv_h->PutInt4Vector("MASKEDLIST");
    std::vector<Int4> mv_Included    = mv_h->PutInt4Vector("Included");

    // Check size of van data
    if (wmv_PixelID.size()!=mv_PixelID.size()){
        std::cout << "White Vanadium for MonoVan and MonoVan are not match." << std::endl;
        throw "EXCEPTION: ";
    }
    if (wv_PixelID.size()!=mv_PixelID.size()){
        std::cout << "White Vanadium for sample and MonoVan are not match." << std::endl;
        throw "EXCEPTION: ";
    }
    for (UInt4 i=0; i< mv_Included.size(); i++){
        if ( (mv_Included[i]!=wmv_Included[i]) || (mv_Included[i]!=wv_Included[i]) ){
            std::cout << "Vanadium types are different." << std::endl;
            throw "EXCEPTION: ";
        }
    }

    // Correction
    ElementContainer *ec;
    ElementContainerArray *eca;
    HeaderBase *hec;
    double pid;
    double mv_cnt,mv_err,wv_cnt,wv_err,wmv_cnt,wmv_err;
    std::vector<double> xx,yy,ee;
    std::string xtitle,ytitle,etitle;
    for (UInt4 i=0; i<data.PutTableSize(); i++){
        eca = data.PutPointer(i);
        for (UInt4 j=0; j<eca->PutTableSize(); i++){
            ec = eca->PutPointer(j);
            hec = ec->PutHeaderPointer();
            pid = hec->PutInt4(UTSUSEMI_KEY_HEAD_PIXELID);
            if ((pid>mv_PixelID.size()) || (mv_Included[pid]==0)){
                throw "EXCEPTION: given data does not match with vanadium data.";
            }

            mv_cnt = mv_Intensity[pid];
            mv_err = mv_Error[pid];
            wv_cnt = wv_Intensity[pid];
            wv_err = wv_Error[pid];
            wmv_cnt = wmv_Intensity[pid];
            wmv_err = wmv_Error[pid];

            yy = ec->PutX();
            ee = ec->PutE();
            xtitle = ec->PutXKey();
            ytitle = ec->PutYKey();
            etitle = ec->PutEKey();

            for (UInt4 k=0; k<yy.size(); k++){
                ee[k]=sqrt( pow( (wmv_cnt/mv_cnt/wv_cnt*ee[k]),2.0 )+pow( (yy[k]/mv_cnt/wv_cnt*wmv_err),2.0) + pow( (yy[k]*wmv_cnt/wv_cnt*(1.0/mv_cnt/mv_cnt)*mv_err),2.0 ) + pow( (yy[k]*wmv_cnt/mv_cnt*(1.0/wv_cnt/wv_cnt)*wv_err),2.0 ) );
                yy[k]=(yy[k]/wv_cnt)/(mv_cnt/wmv_cnt);
            }
            ec->Replace(ytitle,yy);
            ec->Replace(etitle,ee);
            ec->SetKeys(xtitle,ytitle,etitle);

        }
    }
    std::cout << "finish CorrectWhiteVan" << std::endl;
    return data;
}


//////////////////////////////////////////////////////////
ElementContainerMatrix VanadiumToolsChoppers::
MakeVanECM( ElementContainer van_ec )
{
    if (keptECM == NULL){
        std::cout << CommentHead << "No ElementContainerMatrix as template." << std::endl;
        throw "Exception";
    }

    ElementContainerMatrix new_ecm;
    new_ecm.InputHeader( keptECM->PutHeader() );
    HeaderBase *h;
    UInt4 id;

    h = van_ec.PutHeaderPointer();
    std::vector<double> Erange    = h->PutDoubleVector("EnergyRange");
    std::vector<double>  PixelID   = van_ec.PutX();
    std::vector<double> Intensity = van_ec.PutY();
    std::vector<double> Error     = van_ec.PutE();

    std::vector<Int4> PSDID       = h->PutInt4Vector("PSDIDLIST");
    std::vector<Int4> Masked      = h->PutInt4Vector("MASKEDLIST");
    std::vector<Int4> Included    = h->PutInt4Vector("Included");

    ElementContainerArray *eca;
    ElementContainer *ec;
    std::vector<double> yy,ee;

    for (UInt4 i=0; i< (keptECM->PutTableSize()); i++){
        eca = keptECM->PutPointer(i);
        ElementContainerArray *new_eca = new ElementContainerArray( eca->PutHeader() );
        for (UInt4 j=0; j<(eca->PutTableSize()); j++){
            ec = eca->PutPointer(j);

            h = ec->PutHeaderPointer();
            id = h->PutInt4(UTSUSEMI_KEY_HEAD_PIXELID);

            if ((id > (PixelID.size()+1)) || ( Included[id]==0 ) ){
                std::cout << CommentHead << " This Vanadium container is not match for loaded ElementContainerMatrix " << std::endl;
                throw "Exceptions";
            }

            yy.clear();
            ee.clear();
            yy.push_back(Intensity[id]);
            ee.push_back(Error[id]);
            ElementContainer *new_ec = new ElementContainer( ec->PutHeader() );
            new_ec -> Add(UTSUSEMI_KEY_ENERGY,Erange,"meV");
            new_ec -> Add(UTSUSEMI_KEY_INTENSITY,yy,"arb.unit");
            new_ec -> Add(UTSUSEMI_KEY_ERROR,ee,"arb.unit");
            new_ec -> SetKeys(UTSUSEMI_KEY_ENERGY,UTSUSEMI_KEY_INTENSITY,UTSUSEMI_KEY_ERROR);
            h = new_ec->PutHeaderPointer();
            if (h->CheckKey(UTSUSEMI_KEY_HEAD_TOTALCOUNTS)==0){
                h->Add(UTSUSEMI_KEY_HEAD_TOTALCOUNTS,Intensity[id]);
            }else{
                h->OverWrite(UTSUSEMI_KEY_HEAD_TOTALCOUNTS,Intensity[id]);
            }
            if (h->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==0){
                h->Add(UTSUSEMI_KEY_HEAD_MASKED,Masked[id]);
            }else{
                h->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,Masked[id]);
            }

            new_eca->Add(*new_ec);
        }

        new_ecm.Add(*new_eca);
    }

    return new_ecm;
}
//////////////////////////////////////////////////////////
ElementContainerMatrix VanadiumToolsChoppers::
MakeVanECM( ElementContainer ec, ElementContainerMatrix ecm )
{
    keptECM = new ElementContainerMatrix( ecm );
    return MakeVanECM( ec );
}


/*!
//////////////////////////////////////////////////////////
ElementContainer VanadiumToolsChoppers::
EncodeVanContainer( ElementContainerMatrix ecm )
{
    if (!CheckDataProcessed( &ecm, "VanadiumData" )){
        throw "ERROR: This data has never passed through MakeWhiteVan or MakeMonoVan functions";
    }

    ElementContainer *new_ec = new ElementContainer( ecm.PutHeader() );
    std::vector<Int4> PSDID,Masked;
    std::vector<double> PixelID,Intensity,Error,Erange;

    ElementContainerArray *eca;
    HeaderBase *h;
    std::string::size_type index;
    std::string type_s;

    for (UInt4 i=0; i<(ecm.PutTableSize()); i++){
        eca = ecm.PutPointer(i);

        type_s = eca->PutHeaderPointer()->PutString(UTSUSEMI_KEY_HEAD_DETTYPE);
        index = type_s.find(UTSUSEMI_KEY_HEAD_DETTYPE_MONITOR);
        if (index == std::string::npos){
            for (UInt4 j=0;j<(eca->PutTableSize());j++){
                if (Erange.size()==0){
                    std::vector<double> temp = eca->PutPointer(j)->PutX();
                    for (UInt4 k=0;k<temp.size();k++){
                        Erange.push_back( temp[k] );
                    }
                }
                h = eca->PutPointer(j)->PutHeaderPointer();
                PSDID.push_back( h->PutInt4("PSDID") );
                PixelID.push_back( h->PutInt4(UTSUSEMI_KEY_HEAD_PIXELID) );
                Intensity.push_back( h->PutDouble(UTSUSEMI_KEY_HEAD_TOTALCOUNTS) );
                Error.push_back( h->PutDouble("TotalCountsError") );
                Masked.push_back( h->PutInt4(UTSUSEMI_KEY_HEAD_MASKED) );
            }
        }
    }
    PixelID.push_back( 0 );
    h = new_ec->PutHeaderPointer();
    h->Add("MASKEDLIST",Masked);
    h->Add("PSDIDLIST",PSDID);
    h->Add("EnergyRange",Erange);

    new_ec->Add(UTSUSEMI_KEY_HEAD_PIXELID,PixelID);
    new_ec->Add(UTSUSEMI_KEY_HEAD_TOTALCOUNTS,Intensity);
    new_ec->Add("TotalCountsError",Error);
    new_ec->SetKeys(UTSUSEMI_KEY_HEAD_PIXELID,UTSUSEMI_KEY_HEAD_TOTALCOUNTS,"TotalCountsError");

    return *new_ec;

}

//////////////////////////////////////////////////////////
ElementContainerMatrix VanadiumToolsChoppers::
DecodeVanContainer( ElementContainer ec )
{
    ElementContainerMatrix *new_ecm = new ElementContainerMatrix( ec.PutHeader() );
    HeaderBase *h = ec.PutHeaderPointer();

    std::vector<Int4> Masked = h->PutInt4Vector("MASKEDLIST");
    std::vector<double> Erange = h->PutDoubleVector("EnergyRange");
    std::vector<Int4> PsdId = h->PutInt4Vector("PSDIDLIST");
    std::vector<double> PixelId = ec.Put(UTSUSEMI_KEY_HEAD_PIXELID);
    std::vector<double> Intensity = ec.Put(UTSUSEMI_KEY_HEAD_TOTALCOUNTS);
    std::vector<double> Error = ec.Put("TotalCountsError");

    Int4 pre_psdId=PsdId[0];
    std::vector<double> yy,ee;
    ElementContainerArray *eca = new ElementContainerArray();

    for (UInt4 i=0; i<Masked.size(); i++){
        if (PsdId[i]!=pre_psdId){
            new_ecm -> Add(*eca);
            delete eca;
            ElementContainerArray *eca = new ElementContainerArray();
            pre_psdId = PsdId[i];
        }

        ElementContainer *ec = new ElementContainer();
        yy.clear();
        ee.clear();
        yy.push_back( Intensity[i] );
        ee.push_back( Error[i] );

        ec->Add(UTSUSEMI_KEY_ENERGY,Erange);
        ec->Add(UTSUSEMI_KEY_INTENSITY,yy);
        ec->Add(UTSUSEMI_KEY_ERROR,ee);
        ec->SetKeys(UTSUSEMI_KEY_ENERGY,UTSUSEMI_KEY_INTENSITY,UTSUSEMI_KEY_ERROR);
        ec->AddToHeader("PSDID",PsdId[i]);
        ec->AddToHeader(UTSUSEMI_KEY_HEAD_PIXELID,PixelId[i]);

        eca->Add(*ec);
        delete ec;
    }
    new_ecm -> Add(*eca);

    return *new_ecm;

}
*/
