#ifndef HISTERR_SEEN
#define HISTERR_SEEN

#include "objfio.h"
#include <iostream>
#include <stdio.h>
#include "tvector.h"

namespace SOPHYA {

//  Forward class declaration for Fits handler
template <class T>  class FitsHandler;


//! 1 dimensions histograms with errors given by user
class HistoErr : public AnyDataObj {
  friend class ObjFileIO<HistoErr>;
  friend class FitsHandler<HistoErr>;
public:

  //! Create or destroy
  HistoErr(void);
  HistoErr(r_8 xmin,r_8 xmax,int_4 nx);
  HistoErr(const HistoErr& H);
  virtual ~HistoErr(void);

  //! Updating or Setting
  void ReCenterBin(void);
  void ReCenterBinW(void);
  void Zero(void);

  //! Getting Info
  int_4 NBins(void) {return nx_;}
  r_8 XMin(void) {return xmin_;}
  r_8 XMax(void) {return xmax_;}
  r_8 BinWidth(void) {return dx_;}

  //! Retourne le contenu du bin
  inline r_8 operator()(int_4 i) const
    {
    if(i<0 || i>=nx_) return 0.;
    return data_(i);
    }
  inline r_8& operator()(int_4 i)
    {
    return data_(i);
    }

  //! Retourne le nombre l'erreur au carre dans le bin
  inline r_8 Error2(int_4 i) const
    {
    if(i<0 || i>=nx_) return 0.;
    return err2_(i);
    }
  inline r_8 Error(int_4 i) const
    {
    if(i<0 || i>=nx_) return 0.;
    if(err2_(i)>0.) return sqrt(err2_(i)); else return 0.;
    }

  //! Retourne le nombre d'entree dans le bin
  inline r_8 NEntBin(int_4 i) const
    {
    if(i<0 || i>=nx_) return 0.;
    return ndata_(i);
    }

  //! Retourne l'abscisse et l'ordonnee du coin inferieur du bin i.
  inline r_8 BinLowEdge(int_4 i) const {return xmin_ + i*dx_;}
  //! Retourne l'abscisse et l'ordonnee du centre du bin i.
  inline r_8 BinCenter(int_4 i) const  {return xmin_ + (i+0.5)*dx_;}
  //! Retourne l'abscisse et l'ordonnee du coin superieur du bin i.
  inline r_8 BinHighEdge(int_4 i) const {return xmin_ + (i+1)*dx_;}
  //! Retourne les numeros du bin contenant l'abscisse et l'ordonnee x,y.
  inline int_4 FindBin(r_8 x) const {return (int_4)floor((x-xmin_)/dx_);}

  //! Addition du contenu de l'histo pour abscisse x poids w et l'erreur e
  inline void Add(r_8 x, r_8 w, r_8 e)
    {
    int_4 i = FindBin(x);
    if(i<0 || i>=nx_) return;
    data_(i) += w; ndata_(i) += 1.; err2_(i) += e*e;
    }
  inline void Add(r_8 x, r_8 w) {Add(x,w,w);}

  //! Addition du contenu de l'histo pour le bin i poids w et l'erreur e
  inline void AddBin(int_4 i, r_8 w, r_8 e)
    {
    if(i<0 || i>=nx_) return;
    data_(i) += w; ndata_(i) += 1.; err2_(i) += e*e;
    }
  inline void AddBin(int_4 i, r_8 w) {AddBin(i,w,w);}

  //! remplissage contenu de l'histo pour le bin i poids w et l'erreur e
  inline void SetBin(int_4 i, r_8 w, r_8 e, r_8 nb)
    {
    if(i<0 || i>=nx_) return;
    data_(i)  = w;
    err2_(i)  = e*e;
    ndata_(i) = nb;
    }
  //! remplissage de la valeur pour le bin i
  inline void SetBin(int_4 i, r_8 w)
    {
    if(i<0 || i>=nx_) return;
    data_(i)  = w;
    }
  //! remplissage de l'erreur carree pour le bin i
  void SetErr2(int_4 i, r_8 e2)
    {
    if(i<0 || i>=nx_) return;
    err2_(i) = e2;
    }
  //! remplissage nombre d'entrees pour le bin i
  void SetNentB(int_4 i, r_8 nb)
    {
    if(i<0 || i>=nx_) return;
    ndata_(i) = nb;
    }

  //! Compute the mean histogram
  void ToMean(void);
  void FromMean(void);
  int_4 NMean(void) {return mMean;}
  void SetMean(int_4 nmean) {mMean = nmean;}

  //! Replace the errors by the variance
  void ToVariance(void);
  void FromVariance(void);

  //! Fill an histogram with an histogram
  void FillFrHErr(HistoErr& hfrom);

  //! Recuperation des matrices elementaires
  void GetData(TVector<r_8>& data) {data = data_;}
  void GetError2(TVector<r_8>& err2) {err2 = err2_;}
  void GetNData(TVector<r_8>& ndata) {ndata = ndata_;}

  //! Recuperation d'information
  double Sum(void);
  double Sum2(void);
  double SumN(void);

  // Operators
  HistoErr& operator = (const HistoErr& h);
  HistoErr& operator *= (r_8 b);

  // Print
  void Show(ostream& os) const;
  void Show() const { Show(cout); }

  // Write ASCII
  int WriteASCII(string fname);
  int ReadASCII(string fname);

protected:
  void CreateOrResize(r_8 xmin,r_8 xmax,int_4 nx);

  r_4 xmin_,xmax_,dx_;
  int_4 nx_;
  TVector<r_8> data_;
  TVector<r_8> err2_;
  TVector<r_8> ndata_;
  int_4 mMean;  //!< Nombre d'appels a ToMean/Variance(+1) ou FromMean/Variance(-1)
};

/*! Prints histogram information on stream \b s (h.Show(s)) */
inline ostream& operator << (ostream& s, HistoErr const & h)
  {  h.Show(s);  return(s);  }

/*! \ingroup HiStats \fn operator<<(POuttPersist&,HistoErr)
  \brief Persistance management */
inline POutPersist& operator << (POutPersist& os, HistoErr & obj)
{ ObjFileIO<HistoErr> fio(&obj);  fio.Write(os);  return(os); }
/*! \ingroup HiStats \fn operator<<(POuttPersist&,HistoErr)
  \brief Persistance management */
inline PInPersist& operator >> (PInPersist& is, HistoErr & obj)
{ ObjFileIO<HistoErr> fio(&obj); is.SkipToNextObject(); fio.Read(is); return(is); }

} // Fin du namespace

#endif // HISTERR_SEEN
