// ----------------------------------------------------------------------
//
// HepHBookHist1D.cc - implementation of HBook two-dimensional histogram
//
// HepHBookHist1D is the implementation of the HBook two-dimensional
// histogram. It is derived from HepHist1D (the generic interface) and
// HepHBookHist. It is mainly a C++ wrapper around the CERNlib HBook
// Fortran histogramming libraries.
//
// No HepHBookHist1D objects are ever directly
// instantiated by the programmer. When creating new HepHist* objects,
// the manager is in charge of creating the appropriate HepHBook object.
//
// To use generate HBook histograms, HepHBookFileManager must be used:
//
//   int lunit = 10;
//   HepFileManager* m = new HepHBookFileManager("filename.rz", lunit);
//    :
//    :
//   HepHist1D* h(m->hist1D("Title", 100, 0.0, 23.0, 100, 0.0, 23.0));
//   float x, y, weight;
//    :
//   [gather data]
//    :
//   h->accumulate(x, y, weight);
//
//
// Note that the constructor can take an ID number which is used by
// the HBook implementation of HepHist1D. If omitted, the ID number is
// generated automatically (which is recommended). The ID number is
// available through the id() method.
//
// Bob Jacobsen
//   30-May-1997  Walter Brown   Added cloning functions
//   29-May-1997  Jason Luther   Added comments
//   04-Jun-1997  Jason Luther   Rewrote comments
//   04-Aug-1998  Philippe Canal Added weight, sum, sum2, entries
//   25-Feb-1999  J. Marraffino  Added increment operators for histograms
//   21-Feb-2000  Walter Brown   Improved C++ standard compliance
//
// ----------------------------------------------------------------------


#ifndef HEPTRACE_H
#include "HepTuple/HepTrace.h"
#endif

#ifndef HEPHBOOKHIST1D_H
#include "HepTuple/HepHBookHist1D.h"
#endif

#ifndef HEPRAWHIST_H
#include "HepTuple/HepRawHist.h"
#endif

#ifndef HEPHBOOKWRAPPERS_H
#include "HepTuple/HepHBookWrappers.h"
#include "ZMtools/pretendToUse.h"
#endif

USING( std::string )

ZM_BEGIN_NAMESPACE( zmht )	/*  namespace zmht  {  */

// create a 1D histogram with the given title and binning
HepHBookHist1D::HepHBookHist1D(
  HepHBookFileManager * manager
, const string& title
, const int nBins, const float low, const float high
, const int idReq
) :
  HepHist1D( manager, title, nBins, low, high, idReq )
{
  HEP_DEBUG( "HepHBookHist1D::constructor( \"" << title << "\", " << id_ << " )" );
}  //  HepHBookHist1D::HepHBookHist1D()


// Used for dummy construction ...
// the object is then not valid ...
HepHBookHist1D::HepHBookHist1D() : HepHist1D() {
  HEP_DEBUG( "HepHBookHist1D::constructor( )" );
}

void HepHBookHist1D::silenceCompiler() {
  pretendToUse(&(__cf__HEXIST));
  pretendToUse(&(__cf__HSUM));
  pretendToUse(&(__cf__HI));
  pretendToUse(&(__cf__HIE));
  pretendToUse(&(__cf__HIF));
  pretendToUse(&(__cf__HIJ));
  pretendToUse(&(__cf__HIJE));
  pretendToUse(&(__cf__HMIN));
  pretendToUse(&(__cf__HMAX));
  pretendToUse(&(__cf__HRNDM1));
  pretendToUse(&(__cf__HSPFUN));
  pretendToUse(&(__cf__HLNXTF));
  pretendToUse(&(__cf__HSTATI));
  pretendToUse(&(__cf__HX));
  pretendToUse(&(__cf__HXE));
  pretendToUse(&(__cf__HXY));
  pretendToUse(&(__cf__ISCWN));
  pretendToUse(&c2fstrv);
  pretendToUse(&f2cstrv);
  pretendToUse(&vkill_trailing);
  pretendToUse(&num_elem);
}

HepHBookHist1D::~HepHBookHist1D()  {
  HEP_DEBUG( "HepHBookHist1D::destructor( \"" << *title_ << "\", " << id_ << " )" );
}

void HepHBookHist1D::accumulate (
  const float x
, const float weight
)  {

  if ( mayUse() )  {
    _accumulate( x, weight );

    HBookPushd( dir() );
    float temp_y = 0.0;
    HFILL( *id_, x, temp_y, weight );
    HBookPopd();
  }
  else  {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to accumulate() to unmanaged histogram ")
	    +title()+string(".")));
  }
}

float HepHBookHist1D::bin(                     // retrieve value of given bin
  const int binNum
) const  {

  if ( mayUse() )  {
    int numBins = this->nBins();
    float res = 0.0;
    if( binNum >= 0 && binNum <= numBins ) {
      HBookPushd( dir() );
      res = HI( *id_, binNum );
      HBookPopd();
    }
    return res;
  }
  else  {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to bin() to unmanaged histogram ")
	    +title()+string(".")));
    return 0.0;
  }
}

float HepHBookHist1D::binError(                // retrieve error of given bin
  const int binNum
) const  {

  if ( mayUse() )  {
    int numBins = this->nBins();
    float res = 0.0;
    if( binNum >= 0 && binNum <= numBins ) {
      HBookPushd( dir() );
      res = HIE( *id_, binNum );
      HBookPopd();
    }
    return res;
  }
  else  {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to access to unmanaged histogram ")
	    +title()+string(".")));
    return 0.0;
  }
}

void HepHBookHist1D::getContents(             // get values for all in-range bins
  float * data
) const  {

  if ( mayUse() )  {
    HBookPushd( dir() );
    char* type = "HIST";
    HUNPAK( *id_, *data, type, 1 );
    HBookPopd();
  }
  else  {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to access an unmanaged histogram ")
	    +title()+string(".")));
  }
}

void HepHBookHist1D::putContents(             // put values for all in-range bins
  float * data
) const  {

  if ( mayUse() )  {
    HBookPushd( dir() );
    HPAK( *id_, data );
    HBookPopd();
  }
  else  {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to access an unmanaged histogram ")
	    +title()+string(".")));
  }
}

void HepHBookHist1D::getErrors(               // get errors for all in-range bins
  float * data
) const  {

  if ( mayUse() )  {
    HBookPushd( dir() );
    char* type = "HIST";
    HUNPKE( *id_, *data, type, 1 );
    HBookPopd();
  }
  else  {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to access an unmanaged histogram ")
	    +title()+string(".")));
  }
}

void HepHBookHist1D::putErrors(               // put errors for all in-range bins
  float * data
) const  {

  if ( mayUse() )  {
    HBookPushd( dir() );
    HPAKE( *id_, data );
    HBookPopd();
  }
  else  {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to access an unmanaged histogram ")
	    +title()+string(".")));
  }
}

int HepHBookHist1D::entries() const { // number of entries
  if (! mayUse() ) {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to entries() an unmanaged histogram ")
	    +title()+string(".")));    
    return 0;
  }
  // initialize result
  int result = 0;
  // call hbook function
  HBookPushd( dir() );
  HNOENT(*id_, result);
  HBookPopd();
  // return result
  return result;
}

float HepHBookHist1D::weight() const { // sum of all weight
  if (! mayUse() ) {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to weight() an unmanaged histogram ")
	    +title()+string(".")));    
    return 0.0;
  }
  HBookPushd( dir() );
  float result = HSUM(*id_);
  HBookPopd();
  // return result
  return result;  
}

float HepHBookHist1D::weight2() const { // retrieve sum of weight^2
  if (! mayUse() ) {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to weight2() an unmanaged histogram ")
	    +title()+string(".")));    
    return 0.0;
  }
  float sum = 0;
  float weight;
  int numBins = this->nBins();
  HBookPushd( dir() );
  for (int i=1;i<numBins+1;i++) {
    weight = HI( *id_, i);
    sum += weight * weight;
  }
  HBookPopd();
  return sum;
}

float HepHBookHist1D::sum() const { // retrieve weighted sum
  if (! mayUse() ) {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to sum() an unmanaged histogram ")
	    +title()+string(".")));    
    return 0.0;
  }
  float sum = 0;
  float low = min();
  int numBins = this->nBins();
  float delta = (max()-low)/numBins;
  HBookPushd( dir() );
  for (int i=1;i<numBins+1;i++)
    sum += (low + delta * (i-0.5)) * HI( *id_, i );
  HBookPopd();
  return sum;
}

float HepHBookHist1D::sum2() const { // retrieve weighted sum of square (X^2)
  if (! mayUse() ) {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to sum() an unmanaged histogram ")
	    +title()+string(".")));    
    return 0.0;
  }
  float sum = 0;
  float low = min();
  int numBins = this->nBins();
  float delta = (max()-low)/numBins;
  HBookPushd( dir() );
  for (int i=1;i<numBins+1;i++) {
    float val = (low + delta * (i-0.5));
    sum += val * val * HI( *id_, i );
  }
  HBookPopd();
  return sum;
}

void HepHBookHist1D::getStatistics(		// get histogram-wide statistics
      int & numEntries
 ,  float & sumW
 ,  float & sumW2
 , double & sumWX
 , double & sumWX2
) const  {

  if ( mayUse() )  {
    HBookPushd( dir() );
    numEntries = entries();
    sumW = weight();
    sumW2 = weight2();
    sumWX = (double)sum();
    sumWX2 = (double)sum2();
    HBookPopd();
  }
  else  {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to access an unmanaged histogram ")
	    +title()+string(".")));
  }
}

void HepHBookHist1D::getOverflows(		// get over/under-flow count
   float * numOver
 , float * numUnder
) const  {

  if ( mayUse() )  {
    HBookPushd( dir() );
    int numBins = this->nBins();
    *numUnder = HI( *id_, 0 );
    *numOver = HI( *id_, numBins+1 );
    HBookPopd();
  }
  else  {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to access an unmanaged histogram ")
	    +title()+string(".")));
  }
}

void HepHBookHist1D::setXTitle( const std::string& label )
{  // Dummy function since there is no implementation in HBook for this.
}

void HepHBookHist1D::setYTitle( const std::string& label )
{  // Dummy function since there is no implementation in HBook for this.
}

void HepHBookHist1D::setZTitle( const std::string& label )
{  // Dummy function since there is no implementation in HBook for this.
}

HepRawHist HepHBookHist1D::importHist1D( const HepHist1D & h ) {

// Gather up all the data we need from h

  int numBins = h.nBins();
  float minX = h.min();
  float maxX = h.max();
  float * contents  = new float[numBins];
  float * errors    = new float[numBins];

  float nunder;
  float nover;
  h.getOverflows( &nover, &nunder );

  h.getContents( contents );
  h.getErrors( errors );
  
  int numEntries;
  float sumW;   
  float sumW2; 
  double sumWX;
  double sumWX2;
  h.getStatistics( numEntries, sumW, sumW2, sumWX, sumWX2 );

// Manufacture a temporary histogram with all the characteristics of h, in the
// same HBook directory as h, but in the same implementation as the result.
// Note that this thing is unmanaged so we need to talk with it directly.

// Find an unused id

  int id;
  HBookPushd( dir() );
  for( id = 1000; HEXIST(id) != 0; ++id) { }

// Book a HBook 1D histogram to park stuff

  char* title = "Temporary hist1D for importHist1D";
  HBOOK1( id, title, numBins, h.min(), h.max(), 0.0 );

// Instantiate a HepRawHist object to pass back to say where the
// Raw Histogram lives and what it's called

  HepRawHist temp( id );

// Set up to move histogram data.

// Move the bin contents and bin errors

  HPAK( id, contents );
  HPAKE( id, errors );
  delete [] contents;
  delete [] errors;

// Then underflows and overflows

  if ( nover > 0 ) {
    float tempx = maxX+1.0;
    float tempy = 0.0;
    HFILL( id, tempx, tempy, nover );
  }
  if( nunder > 0 ) {
    float tempx = minX-1.0;
    float tempy = 0.0;
    HFILL( id, tempx, tempy, nunder );
  }

// Now set the overall statistics

  PUTSTAT( temp.hid, numEntries, sumW, sumW2, sumWX, sumWX2 );

// Since we're in control here, let's postpone the Pop and save some time

//HBookPopd();
  return temp;
}

void HepHBookHist1D::addHist1D( const HepRawHist & temp ) {

// If we got here, the temporary histogram object referred to by temp is
// known to be valid. On the other hand, it's worth being careful. 

// Since we postponed the Pop in importHist1D, we shouldn't Push here

//HBookPushd( dir() );
  char* operation = "+";
  if( temp.hid != 0 ) HOPERA( *id_, operation, temp.hid, *id_, 1.0, 1.0 );

// Postpone the Pop again

//HBookPopd ();
}

void HepHBookHist1D::subtractHist1D( const HepRawHist & temp ) {

// If we got here, the temporary histogram object referred to by temp is
// known to be valid. On the other hand, it's worth being careful. 

// Since we postponed the Pop in importHist1D, we shouldn't Push here

//HBookPushd( dir() );
  char* operation = "-";
  if( temp.hid != 0 ) HOPERA( *id_, operation, temp.hid, *id_, 1.0, 1.0 );

// Postpone the Pop again

//HBookPopd ();
}

void HepHBookHist1D::multiplyHist1D( const HepRawHist & temp ) {

// If we got here, the temporary histogram object referred to by temp is
// known to be valid. On the other hand, it's worth being careful. 

// Since we postponed the Pop in importHist1D, we shouldn't Push here

//HBookPushd( dir() );
  char* operation = "*";
  if( temp.hid != 0 ) HOPERA( *id_, operation, temp.hid, *id_, 1.0, 1.0 );

// Postpone the Pop again

//HBookPopd ();
}

void HepHBookHist1D::divideHist1D( const HepRawHist & temp ) {

// If we got here, the temporary histogram object referred to by temp is
// known to be valid. On the other hand, it's worth being careful. 

// Since we postponed the Pop in importHist1D, we shouldn't Push here

//HBookPushd( dir() );
  char* operation = "/";
  if( temp.hid != 0 ) HOPERA( *id_, operation, temp.hid, *id_, 1.0, 1.0 );

// Postpone the Pop again

//HBookPopd ();
}

void HepHBookHist1D::removeImportedHist1D( const HepRawHist & temp ) {

// If we got here, the temporary histogram object referred to by temp is
// known to be valid. On the other hand, it's worth being careful. If we
// pass a zero to HDELET, it will happily (and silently) eat everything!

// Since we postponed the Pop in importHist1D, we shouldn't Push here

//HBookPushd( dir() );
  if( temp.hid != 0 ) HDELET( temp.hid );

// Now, we're really done. Finally, do the Pop we've been postponing.

  HBookPopd ();
}

void HepHBookHist1D::reset()  {

  if ( mayUse() )  {
    HBookPushd( dir() );
    char* chopt = " ";
    HRESET ( *id_, chopt );
    HBookPopd();
  }
  else  {
    ZMthrow(ZMxHepUnmanagedItem(
	    string("attempt to reset() to unmanaged histogram ")
	    +title()+string(".")));
  }
}


ZM_END_NAMESPACE( zmht )	/*  }  // namespace zmht  */
