/*
 * (C) Copyright 1996-2016 ECMWF.
 * 
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. 
 * In applying this licence, ECMWF does not waive the privileges and immunities 
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

/*! \file EquidistantTableMode.cc
    \brief Implementation of the Template class EquidistantTableMode.
    
    Magics Team - ECMWF 2005
    
    Started: Tue 17-May-2005
    
    Changes:
    
*/



#include "EquidistantTableMode.h"

using namespace magics;

EquidistantTableMode::EquidistantTableMode()
{
	return;
}


EquidistantTableMode::~EquidistantTableMode() 
{
}

/*!
 Class information are given to the output-stream.
*/		
void EquidistantTableMode::print(ostream& out)  const
{
	out << "EquidistantTableMode[";
	//EquidistantTableModeAttributes::print(out);
	LookupTableModeAttributes::print(out);
	out << "]";
}

void EquidistantTableMode::operator()(Image& im, Raster& rd)
{
     int 	i;		 // auxiliary variables
     long	acum;		 // accumulated population
     long	pop;		 // total population
     long       cutv;            // outlayer population

     // Check outlayer value

     if ( outlayer_ < 0. || outlayer_ > 0.5 )
     {
	  MagLog::error() << "Invalid outlayer value. Range between 0. and 0.5. Default value used (0.0)." << endl;
	  outlayer_ = 0.;
     }

     // Check image range of values
     int imin = (int)rd.min();
     int imax = (int)rd.max();

     if (imax > ETM_MLEN || imin < 0 )
     {
	  MagLog::error() << "EquidistantTableMode: Invalid range of image values (" << imin << "," << imax << ")\n"
	               << "  Current implementation accepts values between 0 to " << ETM_MLEN << endl;
	  return;
     }

     // Initialize lookuptable
     ColourTable& table = im.getColourTable();
     int nlevels = table.size();

     // Reserve memory for the histogram and lut
     imax++; //index imax is needed
     vector<long> hist(imax,0L);
     vector<short> lut(imax);

     // Compute histogram (Maybe we do not need to use all values -> one every 10???)
     for (vector<double>::const_iterator val = rd.begin(); val != rd.end(); ++val)
     {
	     // Remove this test later
	     if(*val < imin || *val > imax-1)
		     MagLog::error() << "EquidistantTableMode: ERROR in histogram!!!" << endl;

	     hist[(int)*val]++;
     }

#if 0
//test: remove later
long aa=0L;
for(i = 0; i < imax; i++) 
{
     aa += hist[i];
     MagLog::dev()<< i << " " << hist[i] << endl;
}
MagLog::dev()<< "EquidistantTableMode: test aa =" << aa << endl;
#endif

     // Remove outlayers and compute minmax indexes
     // Level imin is left out because it is the background
     int minOut = imin;
     int maxOut = imax-1;
     pop  = (long)rd.getRows() * (long)rd.getColumns();
     cutv = (long) ((double)pop * outlayer_ + 1.);
     acum = 0L;

     for (i = imin+1; i < imax; i++)
     {
	  acum += hist[i];
	  if ( acum >= cutv )
	  {
	       minOut = i;
	       break;
	  }
     }
     acum = 0L;
     for (i = imax-1; i > imin; i--)
     {
	  acum += hist[i];
	  if ( acum >= cutv )
	  {
	       maxOut = i;
	       break;
	  }
     }

     // Create accumulate histogram
     pop = hist[minOut];
     for( i = minOut+1; i <= maxOut; i++)
     {
	  pop += hist[i];
	  hist[i] = hist[i-1] + hist[i];
     }

     // Create lut
     for( i = 0; i < imax; i++)
     {
	  if ( i < minOut ) 
	       lut[i] = 0;
	  else if (i >= maxOut)
	       lut[i] = nlevels-1;
	  else
		  lut[i] = (short)( (double)hist[i] * (double)(nlevels-1) / (double)pop );
     }

#if 0
//test: remove later
MagLog::dev()<< "Accumulated histogram" << endl;
for(i = 0; i < imax; i++) 
	MagLog::dev()<< i << " " << hist[i] << " " << lut[i] << endl;
#endif

     // Create output image
//vector<long> hist1(nlevels+1,0L); //test
//long iii=0L;
     for (vector<double>::const_iterator val = rd.begin(); val != rd.end(); ++val)
     {
	     im.push_back(lut[(int)*val]);
//	     short ii = lut[(int)*val];
//error	     table[ii].value(*val);
//	     im.push_back(ii);
//iii++;
//hist1[ii]++;
     }

//MagLog::dev()<< "EquidistantTableMode::operator()" << endl;
//for( i = 0; i < nlevels+1; i++)
//     MagLog::dev()<< i << " " << hist1[i] << endl;
//MagLog::dev()<< "total=" << iii<< endl;

     return;
}
