#include "AdvModelSpecularMul.hh"
#include "AdvModelSpecular.hh"

AdvModelSpecularMul::AdvModelSpecularMul(AdvModelSpecular* m, enum mode i) {
  model = m;
  imode = i;
  this->set("AdvModelSpecularMultidata", "specular_m", m->getNumberOfParam());
}


#ifdef USE_POINTER
/** evaluate the value of the function */
Double AdvModelSpecularMul::eval(const Double x, const Double *p) {
  std::cout << "NOT IMPLEMENTED" << std::endl;
  return 0.0;
}
#ifdef HAVE_DIFFERENTIAL_MEMBER
/** evaluate the value of the 1st derivative function */
Double AdvModelSpecularMul::der1st(const Double x, const Double *p) {
  std::cout << "NOT IMPLEMENTED" << std::endl;
  return 0.0;
}
/** evaluate the value of the 2nd derivative function */
Double AdvModelSpecularMul::der2nd(const Double x, const Double *p) {
  std::cout << "NOT IMPLEMENTED" << std::endl;
  return 0.0;
}
/** evaluate the gradient of the function for parameters */
Double *AdvModelSpecularMul::gradient(const Double x, const Double *p){
  std::cout << "NOT IMPLEMENTED" << std::endl;
  return NULL;
}
#endif //HAVE_DIFFERENTIAL_MEMBER
#endif //USE_POINTER

#ifdef USE_VECTOR
/** evaluate the value of the function */
Double AdvModelSpecularMul::eval(const Double x, const std::vector<Double> &p){
  int flag; //, flag2;

  if ( p.size() == p_save.size() ) {
    int n = p.size();
    flag = 1;
    for (int i = 0; i<n; ++i) {
      if (p[i] != p_save[i]) {
        flag = 0;
        p_save[i] = p[i];
      }
    }
  } else {
      flag = 0;
      p_save = p;
  }

  //flag2 = 0;

  if (flag == 1) {  //  parameter is not modified
    int n = x_save.size();
    for (int i = 0; i<n; ++i) {
      if (x_save[i] == x) {
        return r_save[i][imode];
      }
    }
  } else {
    x_save.clear();
    r_save.clear();
  }

  model->SetFitParam(p);
  std::vector<Double> out = model->ReflectAt(x, 3);

  std::vector<Double> ref(7);

  ref[UnPol2UnPol]   = ( out[0] + out[1] + 2.0*out[2] ) * 0.5;
  ref[UpPol2UpPol]   = out[0];
  ref[UpPol2DownPol] = out[2];
  ref[UpPol2UnPol]   = out[0] + out[2];
  ref[DownPol2DownPol] = out[1];
  ref[DownPol2UpPol] = out[2];
  ref[DownPol2UnPol] = out[1] + out[2];

  if (x_save.size() != r_save.size() ) std::cout << "ERROR: x_save.size != r_save.sizse" << std::endl;

  x_save.push_back(x);
  r_save.push_back(ref);

  return ref[imode];
}

#ifdef HAVE_DIFFERENTIAL_MEMBER
/** evaluate the value of the 1st derivative function */
Double AdvModelSpecularMul::der1st(const Double x, const std::vector<Double> &p){
  std::cout << "NOT SUPPORT ANALYTICAL GRADIENT" << std::endl;
  return 0.0;
}
/** evaluate the value of the 2nd derivative function */
Double AdvModelSpecularMul::der2nd(const Double x, const std::vector<Double> &p){
  std::cout << "NOT SUPPORT ANALYTICAL GRADIENT" << std::endl;
  return 0.0;
}
/** evaluate the gradient of the function for parameters */
std::vector<Double> AdvModelSpecularMul::gradient(const Double x, const std::vector<Double> &p){
  std::cout << "NOT SUPPORT ANALYTICAL GRADIENT" << std::endl;
  std::vector<Double> v;
  v.clear();
  return v;
}
#endif //HAVE_DIFFERENTIAL_MEMBER
#endif //USE_VECTOR
