#ifndef _GImageComponent_H
#define _GImageComponent_H

/* Class which describes a single colour channel of an image in a generalized
 * way allowing for easy and accurate scaling to any size.
 * 
 * Written by:  Chris Studholme
 * Last Update: 10-January-2000
 * Copyright:   GPL (http://www.fsf.org/copyleft/gpl.html)
 */

#include <math.h>

class GImageComponent {
  /*
   * General function is piecewise quasi-linear function with pieces of:
   *   f(x,y) = alpha*x + beta*y + gamma*x*y + omega, x,y e [0,1]
   *   
   * The image coordinate system is (x,y) for x,y e [0,1], where (0,0) is top
   * left.
   *
   * This class is abstract.  Only instanciate a derived class.
   */

 protected:
  int w,h;
  short *tl;
  
  float maxerror;
  double totalerror;
  
 public:
  GImageComponent(int width, int height, float maxerror=0);

  virtual ~GImageComponent() {
    delete[] tl;
  }

  inline double getTotalError() {
    return totalerror;
  }

  int getWidth() {
    return w;
  }

  int getHeight() {
    return h;
  }

  const short* getPointArray() {
    return tl;
  }

  /* x1<x2, y1<y2 */
  int getPixel(float x1, float y1, float x2, float y2);
  int getPixelI(int x1, int y1, int x2, int y2);

  /* must have y1<y2
   */
  void getScanLineHorz(short* pixels, float x1, float y1,
		       float x2, float y2, int npixels);
  /* must have x1<x2
   */
  void getScanLineVert(short* pixels, float x1, float y1,
		       float x2, float y2, int npixels);


  float getMaxValue() {
    int result=tl[0];
    for (int i=1; i<w*h; ++i)
      if (result<tl[i])
	result=tl[i];
    return 128+((float)result)/128;
  }

  float getMinValue() {
    float result=tl[0];
    for (int i=1; i<w*h; ++i)
      if (result>tl[i])
	result=tl[i];
    return 128+((float)result)/128;
  }

  float getMeanValue() {
    float result=0;
    for (int i=0; i<w*h; ++i)
      result += tl[i];
    return 128+((float)result/(w*h))/128;
  }

  void FillHistogram(unsigned int* histogram, int minvalue) {
    for (int i=0; i<w*h; ++i) 
      ++histogram[128+tl[i]/128-minvalue];
  }

  int ReduceGrain(bool extra=false);

protected:
  virtual void TransformCoordinates(float& x, float& y) {
    x-=0.5;
    y-=0.5;
  }

};

class GImageComponent0 : public GImageComponent {
  /*
   * Creates a continuous function to describe a set of observed pixel data.
   * This class is appropriate for images where the pixels completely cover
   * the imaged area (a typical image).
   *
   * This functionality should probably the default behaviour of 
   * GImageComponent when not derived.
   */
   
public:
  GImageComponent0(const unsigned char* imagedata, 
			int width, int height, float maxerror=0);
};

#endif
