#include "MessageService/MsgService.h"
#include "MCReweight/Zbeam.h"

#include "ZbeamWeight.h"
#include "Parsers.h"
#include "FitBeam.h"
#include "FitData.h"
#include "FitPar.h"
#include "GenericFactory.h"

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>

REGISTER_OBJECT(SkzpWeight,ZbeamWeight)

using namespace boost;
using namespace Parsers;
CVSID("");


ZbeamWeight::ZbeamWeight()
  :fName("ZbeamWeight"),
   fDataFile(""),
   fConfig("DetXs")
{
  
  fZbeam=new Zbeam();
  
}

ZbeamWeight::~ZbeamWeight()
{
  // delete fZbeam;
  fZbeam=0;
}

Bool_t ZbeamWeight::SetProperty(std::string prop) 
{
  
  string property=prop.substr(0,prop.find("="));
  string val=prop.substr(prop.find("=")+1);

  if(property=="Parameters") {
    vector<std::string> params;

    parse_val(val,params);
    std::vector<std::string>::iterator iter=params.begin();
    std::vector<std::string>::iterator iter_end=params.end();
    for( ; iter!=iter_end ; ++iter) {
      //cout<<*iter<<endl;
      std::vector<string> vals;
      split(vals, *iter, is_any_of("() "), token_compress_on);
           
      FitPar par(vals);
      fParameters.push_back(par);
    }
  }
  else {
    MSG("ZbeamWeight",Msg::kWarning)<<"Cannot set property "<<property
				    <<" for ZbeamWeight function "<<fName<<endl;
    return false;
  } 
   
  return true;
  
}


double ZbeamWeight::GetWeight(FitData &data)
{
  
  double weight=1.;
  Zbeam::ZbeamData_t zdata;
  zdata.ntype    = data.NuType();
  zdata.true_enu = data.TrueEnergy();
  zdata.detector = Detector::kNear;
  zdata.beam     = BeamType::FromZarko(FitBeam::AsZbeamCode(data.Beam()));
  
  weight *= fZbeam->GetWeight(zdata,BeamSys::kHorn1Offset   ,fPars[0]);
  weight *= fZbeam->GetWeight(zdata,BeamSys::kBaffleScraping,fPars[1]);
  weight *= fZbeam->GetWeight(zdata,BeamSys::kPOT           ,fPars[2]);
  weight *= fZbeam->GetWeight(zdata,BeamSys::kHornIMiscal   ,fPars[3]);
  weight *= fZbeam->GetWeight(zdata,BeamSys::kHornIDist     ,fPars[4]);

  //target z
  if (data.Beam() == FitBeam::kNuMuLE010z170i || 
      data.Beam() == FitBeam::kAntiNuMuLE010z170i ||
      data.Beam() == FitBeam::kNuMuLE010z185i || 
      data.Beam() == FitBeam::kAntiNuMuLE010z185i ||
      data.Beam() == FitBeam::kNuMuLE010z200i || 
      data.Beam() == FitBeam::kAntiNuMuLE010z200i) {
    
    weight *= fZbeam->GetWeight(zdata,BeamSys::kTargetZ ,fPars[5]);

  } else if (data.Beam() == FitBeam::kNuMuLE100z200i || 
	     data.Beam() == FitBeam::kAntiNuMuLE100z200i) {

    weight *= fZbeam->GetWeight(zdata,BeamSys::kTargetZ ,fPars[6]);

  } else if (data.Beam() == FitBeam::kNuMuLE150z200i ||
	     data.Beam() == FitBeam::kAntiNuMuLE150z200i) {

    weight *= fZbeam->GetWeight(zdata,BeamSys::kTargetZ ,fPars[7]);

  } else if (data.Beam() == FitBeam::kNuMuLE250z200i ||
	     data.Beam() == FitBeam::kAntiNuMuLE250z200i) {

    weight *= fZbeam->GetWeight(zdata,BeamSys::kTargetZ ,fPars[8]);

  } else if (data.Beam() == FitBeam::kNuMuLE010z185iN ||
	     data.Beam() == FitBeam::kAntiNuMuLE010z185iN) {

    weight *= fZbeam->GetWeight(zdata,BeamSys::kTargetZ ,fPars[9]);

  } else if (data.Beam() == FitBeam::kNuMuLE250z200iN ||
	     data.Beam() == FitBeam::kAntiNuMuLE250z200iN) {
    
    weight *= fZbeam->GetWeight(zdata,BeamSys::kTargetZ ,fPars[10]);

  }

  if (data.Beam() == FitBeam::kNuMuLE250z200i ||
      data.Beam() == FitBeam::kNuMuLE100z200i)
    weight *= fZbeam->GetWeight(zdata,BeamSys::kBeamWidth,0.);

  MSG("ZbeamWeight",Msg::kVerbose)
    <<"Beam Weight="<<weight<<endl;
  return weight;
}


bool ZbeamWeight::Init() 
{
  fZbeam->SetReweightConfig(fConfig);
  return true;
}
