/*
 * Implementation of class Histogram
 *
 * $Date$
 * $Revision$
 *
 */

#include "WTools/Histogram.hh"
#ifdef _WIN32_WCE
#undef DELETE
#endif
#include <stdexcept>
#include <cmath>
#include <cassert>
#ifndef _WIN32_WCE
#include <iostream>
#include <iomanip>
#else
#include "WImage/miscdefs.h"
#endif

#if !(defined __WATCOMC__ && __WATCOMC__ < 1230)
using namespace std;
#endif


Histogram::Histogram (Image &img, double dlt)
{
  if (fabs (dlt) < COEFF_EPSILON)
    {
      throw invalid_argument ("Histogram: delta must not be zero.");
    }
  
  this->m_image = &img;
  m_data = NULL;
  this->m_dlt = dlt;
  this->m_values = NULL;

  m_ii = NULL;
  update ();
}

Histogram::Histogram (ImageInformation &ii, double dlt)
{
  if (fabs (dlt) < COEFF_EPSILON)
    {
      throw invalid_argument ("Histogram: delta must not be zero.");
    }
  
  this->m_image = NULL;
  this->m_data = &ii;
  this->m_dlt = dlt;
  this->m_values = NULL;

  m_ii = NULL;
  update ();
}

Histogram::~Histogram (void)
{
  DELETE (m_ii);
  DELETE (m_values);
}

void
Histogram::update (void)
{
  DELETENOTNULL (m_ii);

  if (m_image != NULL)
    {
      m_ii = NEW (ImageInformation (*m_image));
    }
  else
    {
      m_ii = m_data->clone ();
    }
  
  m_ii->ssort ();

  coeff max = m_ii->smax ();
  coeff min = m_ii->smin ();
  int negsize = (int)floor ((fabs (min) + 0.5 * m_dlt) / m_dlt);
  int possize = (int)floor ((fabs (max) + 0.5 * m_dlt) / m_dlt);
  m_nvals = negsize + possize + 1;

  DELETENOTNULL (m_values);
  
  m_values = NEW (struct hist [m_nvals]);

  coeff cur = negsize * m_dlt;
  if (min < 0)
    {
      cur *= -1;
    }
  for (int i = 0; i < m_nvals; i++)
    {
      m_values[i].lower = cur;
      cur += m_dlt;
      m_values[i].upper = cur;
      m_values[i].number = 0;
    }

  CoeffInformation grey;
  int histidx = 0;
  for (int i = 0; i < m_ii->size (); i++)
    {
      grey = m_ii->at (i);
      for (; grey.val () >= m_values[histidx].upper && histidx < m_nvals; histidx++)
        {
        }
      m_values[histidx].number++;
    }
}

int 
Histogram::at (int pos, coeff &lower)
{
  if (pos < 0 || pos >= m_nvals)
    {
      throw invalid_argument ("at: index `pos' out of bounds.");
    }
  lower = m_values[pos].lower;
  return m_values[pos].number;
}

int 
Histogram::at (coeff value)
{
  int i;
  for (i = 0; value >= m_values[i].upper && i < m_nvals; i++)
    {
    }
  return m_values[i].number;
}

#ifndef _WIN32_WCE
void
Histogram::print (void)
{
  cout.setf (ios::fixed, ios::floatfield);
  cout << "# " << m_nvals << " values" << endl;
  for (int i = 0; i < m_nvals; i++)
    {
      cout << std::setprecision (4) 
           << m_values[i].lower << ' ' << m_values[i].number << endl;
    }
  cout.setf (FMT0, ios::floatfield);
  
}
#endif

void 
Histogram::add (coeff value, int number)
{
  int i;
  for (i = 0; value >= m_values[i].upper && i < m_nvals; i++)
    {
    }
  if (m_values[i].number + number < 0)
    {
      throw invalid_argument ("add: number would get negative.");
    }
  m_values[i].number += number;
}

