#ifndef __WAVELET_H__
#define __WAVELET_H__

#include "image2d.h"
#include <math.h>
#include <vector>
#include <iostream>

/// a class for wavelet analysis of an image
class wavelet
{
 public:
  ///structure to construct a wavelet tree
  struct wavelettree
  {
    image2d *hl;                ///< data for this level in the tree
    image2d *lh;
    image2d *hh;
    wavelettree *next;         ///< next level
  };

  wavelet();
  ~wavelet();

  /// loads a wavelet tree
  /**
   * @param d pointer to tree
   * data is not copied
   */
  int load( wavelettree *d );

  /// delete any data that may exist
  int del();

  /// do the wavelet transform on the image
  /**
   * @param im the input image
   * @param type the type of wavelet transform to preform 1 -> integer to integer 0 floating point
   */
  int analyze( image2d &im, int type );

  /// returns the high pass sum of all the wavelet levels
  int gethpmap( image2d &im );

  /// return the hp for the level
  int gethplevel( image2d &im, int level );

  /// calculate the gradiant vectors at a level
  int calcgradvector( int level, image2d &im );

  int calcgradmag( int level, image2d &im );

  int numlevels()
  {
    return levelptr.size()-1;
  }

  /// inverse transform the current wavelet data
  /**
   * @param im the output image
   * @param type integer to integer flag
   */
  int istrans( image2d &im, int type );

  /// returns the wavelet tree
  wavelettree *getwlt()
  {
    return data;
  }

  int getwidth()
  {
    return realszy;
  }

  int getheight()
  {
    return realszx;
  }

  int setheight( int x )
  {
    realszx = x;
    return 0;
  }

  int setwidth( int x )
  {
    realszy = x;
    return 0;
  }

 private:

  int del( wavelettree *d );

  /// transform one level of the haar wavelet
  int haartrans( double *in, double *out, int size);
  /// inverse transform for one level haar wavelet
  int ihaartrans( double *in, double *out, int size);

  /// preforms stransform on an image
  int strans( image2d &im );
  /// preforms one level stransform for an image
  /**
   * @param in input image pointer
   * @param ll low low pass data will be written here
   * @param hl high low pass data will be written
   * @param lh low high pass data
   * @param hh high high pass data
   */
  int strans( image2d *in, image2d *ll, image2d *hl,
              image2d *lh, image2d *hh );
  /// transform one level stransform integer to integer
  /**
   * s transform first half of output buffer will be 
   * low pass second half high pass
   *
   * @param in input data
   * @param out output buffer pointer
   * @param size size of the input buffer
   */
  int strans( double *in, double *out,
              int size);

  /// transform one level inverse s tranform on image
  /**
   * @param ll low low pass data will be written here
   * @param hl high low pass data will be written
   * @param lh low high pass data
   * @param hh high high pass data
   * @param out output image
   */
  int istrans(image2d *ll, image2d *hl,
              image2d *lh, image2d *hh,
              image2d *out );

  /// transform one level iverse stransform integer to integer
  /**
   * inverse s transform
   *
   * @param l input lowpass data
   * @param h input high pass data
   * @param out output buffer pointer 2*size of input buffer
   * @param size size of the input buffer
   */
  int istrans( double *l, double *h,
               double *out, int size);

  int istrans( double *in, double *out, int h, int w);
  
  wavelettree *data;

  int realszx;   ///< the size of the image before padding
  int realszy;   ///< size of image before padding

  int iti; ///< integer to integer transform flag

  /// pointer to each level in the wavelet decomposition
  std::vector< wavelettree* > levelptr; 
};

#endif
