// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.

#ifndef tools_sg_fit2plot
#define tools_sg_fit2plot

#include "plottables"

#include "../words"
#include "../num2s"

#ifdef TOOLS_MEM
#include "../mem"
#endif

namespace tools {
namespace sg {

class fit2plot : public virtual plottable {
  static const std::string& s_empty() {
    static const std::string s_v("");
    return s_v;
  }
public:
  static const std::string& s_class() {
    static const std::string s_v(s_tools_sg_fit2plot());
    return s_v;
  }
public:
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<fit2plot>(this,a_class)) {return p;}
    return plottable::cast(a_class);
  }
public: //plottable
  virtual plottable* copy() const {return new fit2plot(*this);}
  virtual bool is_valid() const {return true;}
  virtual const std::string& name() const {return m_name;}
  virtual void set_name(const std::string& a_s) {m_name = a_s;}
  virtual const std::string& title() const {return s_empty();}
  virtual const std::string& legend() const {return m_legend;}
  virtual void set_legend(const std::string& a_s) {m_legend = a_s;}

  virtual void infos(const std::string& a_opts,std::string& a_sinfos) const {
    a_sinfos.clear();
    std::string f_lf("\n");
    std::vector<std::string> ws;
    words(a_opts," ",false,ws);
    std::vector<std::string>::const_iterator it;
  
    bool show_fit_ndf = false;
   {for(it=ws.begin();it!=ws.end();++it) {
      if((*it)=="fit_ndf") {show_fit_ndf = true;break;}
    }}
    bool show_fit_errors = false;
   {for(it=ws.begin();it!=ws.end();++it) {
      if((*it)=="fit_errors") {show_fit_errors = true;break;}
    }}

    for(it=ws.begin();it!=ws.end();++it) {
      if(((*it)=="name") && m_name.size()) {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "Name";
        a_sinfos += f_lf;
        a_sinfos += m_name;
  
      } else if((*it)=="fit_quality") {
        if(show_fit_ndf) {
          if(a_sinfos.size()) a_sinfos += f_lf;
          a_sinfos += "[h]^2! / ndf";
          a_sinfos += f_lf; 
          if(!numas<double>(m_output[0],a_sinfos)){}
          a_sinfos += " / "; 
          if(!numas<double>(m_output[1],a_sinfos)){}
        } else { //show chi2 only.
          if(a_sinfos.size()) a_sinfos += f_lf;
          a_sinfos += "[h]^2!";
          a_sinfos += f_lf;
          if(!numas<double>(m_output[0],a_sinfos)){}
        }

      } else if((*it)=="fit_parameters") {
        size_t nparam = m_names.size();
        for(size_t iparam=0;iparam<nparam;iparam++) {
          if(show_fit_errors) {
            if(a_sinfos.size()) a_sinfos += f_lf;
            a_sinfos += m_names[iparam];
            a_sinfos += f_lf;
            if(!numas<double>(m_output[2+4*iparam+0],a_sinfos)){} //value
            a_sinfos += " +&_ ";
            if(!numas<double>(m_output[2+4*iparam+1],a_sinfos)){} //error
          } else {
            if(a_sinfos.size()) a_sinfos += f_lf;
            a_sinfos += m_names[iparam];
            a_sinfos += f_lf;
            if(!numas<double>(m_output[2+4*iparam+0],a_sinfos)){}
          }
        }
      }
    }
  }
public:
  fit2plot(const std::vector<std::string>& a_names,
           const std::vector<double>& a_output)
  :m_names(a_names)
  ,m_output(a_output)
  {
#ifdef TOOLS_MEM
    mem::increment(s_class().c_str());
#endif
    size_t nparam = (m_output.size()-2)/4;
    if(m_names.size()!=nparam) {
      //should issue a warning.
      m_names.clear();
      m_output.clear();
    }
  }
  virtual ~fit2plot(){
#ifdef TOOLS_MEM
    mem::decrement(s_class().c_str());
#endif
  }
public:
  fit2plot(const fit2plot& a_from)
  : plottable(a_from)
  ,m_names(a_from.m_names)
  ,m_output(a_from.m_output)
  ,m_name(a_from.m_name)
  ,m_legend(a_from.m_legend)
  {
#ifdef TOOLS_MEM
    mem::increment(s_class().c_str());
#endif
  }  
  fit2plot& operator=(const fit2plot& a_from){
    m_names = a_from.m_names;
    m_output = a_from.m_output;
    m_name = a_from.m_name;
    m_legend = a_from.m_legend;
    return *this;
  }
protected:
  std::vector<std::string> m_names;
  std::vector<double> m_output;
  std::string m_name;
  std::string m_legend;
};

}}

#endif
