/*---------------------------------------------------------------------------*/
// Baseline Wavelet Transform Coder Construction Kit
//
// Geoff Davis
// gdavis@cs.dartmouth.edu
// http://www.cs.dartmouth.edu/~gdavis
//
// Copyright 1996 Geoff Davis 9/11/96
//
// Permission is granted to use this software for research purposes as
// long as this notice stays attached to this software.
//
/*---------------------------------------------------------------------------*/
// quantizer.hh
//
// Routines for quantizing coefficients using various levels of
// precision.  Two basic styles of quantizer are included.  
//
// The UniformQuantizer class is a single-layer, non-embedded
// quantizer. It maps each coefficient to a single symbol which is
// later entropy coded.  The fineness of the quantization is
// controlled by the precision parameter.  The UniformQuantizer class
// codes symbols using a MonoLayer entropy coder.
//
// The LayerQuantizer class is a multi-layer, embedded quantizer.
// It maps each coefficient to a sequence of symbols that correspond
// to an initial coarse quantization and subsequent refinements.  The
// precision parameter controls the number of refinements used.  By
// conditioning the probabilities of refinements on coarser-scale
// quantizations of the same symbol we can achieve the equal or greater
// efficiency than we can with a single layer coder.  Greater
// efficiency is usually possible because the coarse-scale histograms
// are very small (2 or 3 symbols) and adapt quickly.  The
// LayerQuantizer class entropy codes symbols using a MultiLayer
// entropy coder that takes into account the use of multiple symbols
// for each coefficient and conditions the coding appropriately.
// 
// Functions:
// ----------
// setDataEncode    Set data to be encoded.  This must be called
//                  before invoking quantize or getRateDist because
//                  some internals need to be initialized.
// setDataDecode    Set data to be decoded.  This must be called
//                  before invoking dequantize because some
//                  internals need to be initialized.
// getRateDist      Generate a rate/distortion curve for a set of
//                  coefficients.
// quantize         Quantize a set of coefficients, entropy code them,
//                  and write the result using the given encoder
// dequantize       Read a set of coefficients from the given decoder,
//                  decode them and dequantize them.
// writeHeader      Write quantizer parameters using the given encoder.
// readHeader       Set quantizer parameters using a stored header
//                  read using the given decoder.  
/*---------------------------------------------------------------------------*/
#ifndef _QUANTIZER_
#define _QUANTIZER_
#include "entropy.h"
#include "metric.h"
#include "packet.h"

#define CORESUBBANDS   3
#define SUBBHEADERS    3
#define LESSLAYHEADERS 1
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/

class Quantizer {

/*
static const int CORESUBBANDS = 3;
static const int SUBBHEADERS = 3;
static const int LESSLAYHEADERS = 1;
*/

public:
  Quantizer  (ErrorMetric *err);
  virtual ~Quantizer () {};

  virtual void setDataEncode  (Real *data, int nData, int subband) = 0;
  virtual void setDataDecode  (Real *data, int nData, int subband = 0, 
                               int imax = -1, int imin = 1, int imean = -1) = 0;

  virtual void getRateDist  (int precision, Real minStepSize, 
			     Real &rate, Real &dist) = 0; 

  virtual void quantize     (Encoder **encoder, int precision, int subband,
                             PacketEnc **pkt, int modulus) = 0;
  virtual void dequantize   (Decoder **decoder, int precision, int subband,
                             int *missing, PacketDec **pkt, int modulus) = 0;

  virtual void writeHeader (Encoder *encoder, int precision, int subband) = 0;
  virtual void readHeader  (Decoder *decoder, int &precision, int subband) = 0;

  void getStats ();

  int realToInt (Real x, int precision) 
       { return (int)(x * exp (precision * Log2) + 0.5); };
  Real intToReal (int n, int precision)
       { return ((Real)n / exp (precision * Log2)); };
       
  // ----------------------- Added -----------------------------------
  //virtual void setPackTables ();
  virtual int packet (int subband, int position) = 0;
  virtual int getCnt (int layer, int context, int cnt) = 0;
  virtual int getStp (int layer, int context, int cnt) = 0;
  virtual int getPts (int layer, int context, int cnt) = 0;
  virtual void setCnt(int layer, int context, int value) = 0;
  virtual void setStp(int layer, int context, int value) = 0;
  virtual void setPts(int layer, int context, int value) = 0;   
  
  LayerCoder *entropy;

  // ------------------ End of Added ---------------------------------

  ErrorMetric *err;
  Real *data;
  int nData;
  Real max, min, mean, var, sum, sumSq;
  Real initialDist;

};

/*---------------------------------------------------------------------------*/

class UniformQuant : public Quantizer {

/*
static const int CORESUBBANDS = 3;
static const int SUBBHEADERS = 3;
static const int LESSLAYHEADERS = 1;
*/

public:
  UniformQuant  (MonoLayerCoder *entropy, int paramPrecision, 
		 int zeroCenter, int nSt, ErrorMetric *err = NULL); 
  ~UniformQuant () {};

  void setDataEncode (Real *newData, int newNData, int subband);
  void setDataDecode (Real *newData, int newNData, int subband = 0, 
                      int imax = -1, int imin = 1, int imean = -1);
  void getRateDist  (int precision, Real minStepSize, 
                     Real &rate, Real &dist);

  void quantize     (Encoder **encoder, int precision, int subband, 
                     PacketEnc **pkt, int modulus);
  void dequantize   (Decoder **decoder, int precision, int subband,
                      int *missing, PacketDec **pkt, int modulus);

  void writeHeader (Encoder *encoder, int precision, int subband);
  void readHeader  (Decoder *decoder, int &precision, int subband);

  void setParams (int paramPrecision, Real max, Real min, Real mean);
  
  // ----------------------- Added -----------------------------------
  void setPackTables ();
  void setPackTables2 ();
  int packet (int subband, int position);
  int getCnt(int layer, int context, int cnt) { return 0; };
  int getStp(int layer, int context, int cnt) { return 0; };
  int getPts(int layer, int context, int cnt) { return 0; };
  void setCnt(int layer, int context, int value) { };
  void setStp(int layer, int context, int value) { };
  void setPts(int layer, int context, int value) { };
  
  // -------------------- End of added -------------------------------

  int nStages;
  int imin, imax, imean;
  Real qmin, qmax, qmean;
  MonoLayerCoder *entropy;
  int paramPrecision, zeroCenter;
  
// ----------------------- Added -----------------------------------
//private:
  //static int **subLL, ***sub5, ***sub4, ***sub3, ***sub2, ***sub1;
  int subLL[16][16], sub5[3][16][16], sub4[3][32][32], sub3[3][64][64], 
  sub2[3][128][128], sub1[3][256][256];
// ------------------ End of Added ---------------------------------

};

/*---------------------------------------------------------------------------*/

class LayerQuant : public Quantizer {

// CORESUBBANDS = # of (low frequency) subbands with all layers in header
// SUBBHEADERS = total # of subbands with at leadt some layers written
// in the header
// LESSLAYHEADERS = # of least signif. layers in (SUBBHEADERS-CORESUBBANDS) 
// subband whose histograms are not written in the header

/*
static const int CORESUBBANDS = 13;
static const int SUBBHEADERS = 13;   
static const int LESSLAYHEADERS = 0;
*/

public:
  LayerQuant  (MultiLayerCoder *entropy, int paramPrecision, 
	       int signedSym, int nLayers, int nSt, ErrorMetric *err = NULL);
  ~LayerQuant ();

  void setDataEncode  (Real *data, int nData, int subband);
  void setDataDecode  (Real *data, int nData, int subband = 0, int imax = -1,
		       int imin = 1, int imean = -1);

  void getRateDist  (int precision, Real minStepSize, 
		     Real &rate, Real &dist); 

  void quantize     (Encoder **encoder, int precision, int subband, 
                     PacketEnc **pkt, int modulus);
  void dequantize   (Decoder **decoder, int precision, int subband, 
                     int *missing, PacketDec **pkt, int modulus);

  void writeHeader (Encoder *encoder, int precision, int subband);
  void readHeader  (Decoder *decoder, int &precision, int subband);

  void quantizeLayer   (Encoder **encoder, int precision, int subband,
                        PacketEnc **pkt, int modulus);
  void dequantizeLayer (Decoder **decoder, int &precision, 
                        int subband, int *missing, PacketDec **pkt, int modulus);
  void resetLayer      ();

  void setParams (int paramPrecision, Real max, Real min, Real mean);
  
  // ----------------------- Added -----------------------------------
  void setPackTables ();
  void setPackTables2 ();
  int packet (int subband, int position);
  void qLayer (Encoder *encoder);
  
  int getCnt(int layer, int context, int cnt);
  int getStp(int layer, int context, int cnt);
  int getPts(int layer, int context, int cnt);
  void setCnt(int layer, int context, int value);
  void setStp(int layer, int context, int value);
  void setPts(int layer, int context, int value);
  // ------------------ End of Added ---------------------------------

  MultiLayerCoder *entropy;
  int paramPrecision, signedSym, nLayers;
  int imin, imax, imean;
  Real qmin, qmax, qmean;

  int currentLayer, *context;
  Real *layerRate, *layerDist, *residual;
  Real threshold;
  int nStages;
  
  //-----
  int *newCoeff;
  //-----
  
// ----------------------- Added -----------------------------------
//private:
  //static int **subLL, ***sub5, ***sub4, ***sub3, ***sub2, ***sub1;
  // MODIFY TO TAKE INTO ACCOUNT IMAGE SIZE AND NUMBER STAGES OF DWT
  int subLL[32][32], sub5[3][32][32], sub4[3][64][64], sub3[3][128][128], 
  sub2[3][256][256], sub1[3][256][256];
// ------------------ End of Added ---------------------------------
  
};

/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
#endif
/*---------------------------------------------------------------------------*/
