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

#ifndef tools_sg_h2plot
#define tools_sg_h2plot

// Connexion tools/histo to sg/plotter.

// Inheritance :
#include "plottables"

#include "../histo/h1d"
#include "../histo/h2d"
#include "../histo/p1d"
#include "../histo/p2d"

#include "../tokenize"
#include "../num2s"

namespace tools {
namespace sg {

class h1d2plot : public virtual bins1D {
public:
  TOOLS_SCLASS(tools::sg::h1d2plot)
public:
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<h1d2plot>(this,a_class)) {return p;}
    return bins1D::cast(a_class);
  }
public: //plottable
  virtual plottable* copy() const {return new h1d2plot(*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 m_data.title();}
  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;

    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)=="entries") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "Entries";
        a_sinfos += f_lf;
        if(!numas<unsigned int>(m_data.all_entries(),a_sinfos)){}

      } else if((*it)=="mean") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "Mean";
        a_sinfos += f_lf;
        if(!numas<double>(m_data.mean(),a_sinfos)) {}

      } else if((*it)=="rms") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "RMS";
        a_sinfos += f_lf;
        if(!numas<double>(m_data.rms(),a_sinfos)) {}

      } else if((*it)=="underflow") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "UDFLW";
        a_sinfos += f_lf;
        if(!numas<double>(m_data.bin_height(histo::axis_UNDERFLOW_BIN),a_sinfos)){}

      } else if((*it)=="overflow") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "OVFLW";
        a_sinfos += f_lf;
        if(!numas<double>(m_data.bin_height(histo::axis_OVERFLOW_BIN),a_sinfos)){}
      }
    }
  }
public: //bins1D
  virtual void bins_Sw_range(float& a_mn,float& a_mx,bool a_with_entries) const {
    if(a_with_entries && m_data.has_entries_per_bin()) {
      double mn,mx;
      m_data.min_bin_height_with_entries(mn);
      m_data.max_bin_height_with_entries(mx);
      a_mn = float(mn);
      a_mx = float(mx);
    } else {
      a_mn = (float)m_data.min_bin_height();
      a_mx = (float)m_data.max_bin_height();
    }
  }
  virtual unsigned int bins() const {return m_data.axis().bins();}
  virtual float axis_min() const {return (float)m_data.axis().lower_edge();}
  virtual float axis_max() const {return (float)m_data.axis().upper_edge();}
  virtual float bin_lower_edge(int aI) const {return (float)m_data.axis().bin_lower_edge(aI);}
  virtual float bin_upper_edge(int aI) const {return (float)m_data.axis().bin_upper_edge(aI);}

  virtual bool has_entries_per_bin() const {return m_data.has_entries_per_bin();}
  virtual unsigned int bin_entries(int aI) const {return m_data.bin_entries(aI);}

  virtual float bin_Sw(int aI) const {return (float)m_data.bin_height(aI);}

  virtual float bin_error(int aI) const {return (float)m_data.bin_error(aI);}
  virtual bool is_profile() const {return false;}
public:
  h1d2plot(const histo::h1d& a_data):m_data(a_data) {
  }
  virtual ~h1d2plot(){
  }
public:
  h1d2plot(const h1d2plot& a_from)
  :plottable(a_from),bins1D(a_from)
  ,m_data(a_from.m_data)
  ,m_name(a_from.m_name)
  ,m_legend(a_from.m_legend)
  {
  }
  h1d2plot& operator=(const h1d2plot& a_from){
    m_name = a_from.m_name;
    m_legend = a_from.m_legend;
    return *this;
  }
public:
  const histo::h1d& data() const {return m_data;}
protected:
  const histo::h1d& m_data;
  std::string m_name;
  std::string m_legend;
};

class h2d2plot : public virtual bins2D {
public:
  TOOLS_SCLASS(tools::sg::h2d2plot)
public:
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<h2d2plot>(this,a_class)) {return p;}
    return bins2D::cast(a_class);
  }
public: //plottable
  virtual plottable* copy() const {return new h2d2plot(*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 m_data.title();}
  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;
    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\n";
        a_sinfos += m_name;

      } else if((*it)=="entries") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "Entries\n";
        if(!numas<unsigned int>(m_data.all_entries(),a_sinfos)) {}

      } else if((*it)=="mean") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "MeanX\n";
        if(!numas<double>(m_data.mean_x(),a_sinfos)) {}
        a_sinfos += f_lf;
        a_sinfos += "MeanY\n";
        if(!numas<double>(m_data.mean_y(),a_sinfos)) {}

      } else if((*it)=="rms") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "RMS X\n";
        if(!numas<double>(m_data.rms_x(),a_sinfos)) {}
        a_sinfos += f_lf;
        a_sinfos += "RMS Y\n";
        if(!numas<double>(m_data.rms_y(),a_sinfos)) {}

      }
    }
  }
public: //bins2D
  virtual void bins_Sw_range(float& a_mn,float& a_mx,bool a_with_entries) const {
    if(a_with_entries && m_data.has_entries_per_bin()) {
      double mn,mx;
      m_data.min_bin_height_with_entries(mn);
      m_data.max_bin_height_with_entries(mx);
      a_mn = float(mn);
      a_mx = float(mx);
    } else {
      a_mn = (float)m_data.min_bin_height();
      a_mx = (float)m_data.max_bin_height();
    }
  }
  virtual unsigned int x_bins() const {return m_data.axis_x().bins();}
  virtual unsigned int y_bins() const {return m_data.axis_y().bins();}
  virtual float x_axis_min() const {return (float)m_data.axis_x().lower_edge();}
  virtual float x_axis_max() const {return (float)m_data.axis_x().upper_edge();}
  virtual float y_axis_min() const {return (float)m_data.axis_y().lower_edge();}
  virtual float y_axis_max() const {return (float)m_data.axis_y().upper_edge();}

  virtual float bin_lower_edge_x(int aI) const {return (float)m_data.axis_x().bin_lower_edge(aI);}
  virtual float bin_upper_edge_x(int aI) const {return (float)m_data.axis_x().bin_upper_edge(aI);}
  virtual float bin_lower_edge_y(int aI) const {return (float)m_data.axis_y().bin_lower_edge(aI);}
  virtual float bin_upper_edge_y(int aI) const {return (float)m_data.axis_y().bin_upper_edge(aI);}

  virtual bool has_entries_per_bin() const {return m_data.has_entries_per_bin();}
  virtual unsigned int bin_entries(int aI,int aJ) const {return m_data.bin_entries(aI,aJ);}

  virtual float bin_Sw(int aI,int aJ) const {return (float)m_data.bin_height(aI,aJ);}

  virtual float bin_error(int aI,int aJ) const {return (float)m_data.bin_error(aI,aJ);}
public:
  h2d2plot(const histo::h2d& a_data)
  :m_data(a_data)
  {
  }
  virtual ~h2d2plot(){
  }
public:
  h2d2plot(const h2d2plot& a_from)
  :plottable(a_from),bins2D(a_from)
  ,m_data(a_from.m_data)
  ,m_name(a_from.m_name)
  ,m_legend(a_from.m_legend)
  {
  }
  h2d2plot& operator=(const h2d2plot& a_from){
    m_name = a_from.m_name;
    m_legend = a_from.m_legend;
    return *this;
  }
protected:
  const histo::h2d& m_data;
  std::string m_name;
  std::string m_legend;
};

//NOTE : for the moment, same code as h1d2plot !
class p1d2plot : public virtual bins1D {
public:
  TOOLS_SCLASS(tools::sg::p1d2plot)
public:
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<p1d2plot>(this,a_class)) {return p;}
    return bins1D::cast(a_class);
  }
public:
  virtual plottable* copy() const {return new p1d2plot(*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 m_data.title();}
  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;
    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\n";
        a_sinfos += m_name;

      } else if((*it)=="entries") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "Entries\n";
        if(!numas<unsigned int>(m_data.all_entries(),a_sinfos)) {}
      } else if((*it)=="mean") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "Mean\n";
        if(!numas<double>(m_data.mean(),a_sinfos)) {}
      } else if((*it)=="rms") {
        if(a_sinfos.size()) a_sinfos += f_lf;
        a_sinfos += "RMS\n";
        if(!numas<double>(m_data.rms(),a_sinfos)) {}

      }
    }
  }
public:
  virtual unsigned int bins() const {return m_data.axis().bins();}

  virtual void bins_Sw_range(float& a_mn,float& a_mx,bool a_with_entries) const {
    if(a_with_entries && m_data.has_entries_per_bin()) {
      double mn,mx;
      m_data.min_bin_height_with_entries(mn);
      m_data.max_bin_height_with_entries(mx);
      a_mn = float(mn);
      a_mx = float(mx);
    } else {
      a_mn = (float)m_data.min_bin_height();
      a_mx = (float)m_data.max_bin_height();
    }
  }

  virtual float axis_min() const {return (float)m_data.axis().lower_edge();}
  virtual float axis_max() const {return (float)m_data.axis().upper_edge();}
  virtual float bin_lower_edge(int aI) const {return (float)m_data.axis().bin_lower_edge(aI);}
  virtual float bin_upper_edge(int aI) const {return (float)m_data.axis().bin_upper_edge(aI);}

  virtual bool has_entries_per_bin() const {return m_data.has_entries_per_bin();}
  virtual unsigned int bin_entries(int aI) const {return m_data.bin_entries(aI);}

  virtual float bin_Sw(int aI) const {return (float)m_data.bin_height(aI);}

  virtual float bin_error(int aI) const {return (float)m_data.bin_error(aI);}

  virtual bool is_profile() const {return true;}
public:
  p1d2plot(const histo::p1d& a_data):m_data(a_data){}
  virtual ~p1d2plot(){}
public:
  p1d2plot(const p1d2plot& a_from)
  :plottable(a_from),bins1D(a_from)
  ,m_data(a_from.m_data)
  ,m_name(a_from.m_name)
  ,m_legend(a_from.m_legend)
  {}
  p1d2plot& operator=(const p1d2plot& a_from){
    m_name = a_from.m_name;
    m_legend = a_from.m_legend;
    return *this;
  }
protected:
  const histo::p1d& m_data;
  std::string m_name;
  std::string m_legend;
};

}}

#endif
