// Copyright (C) 1999-2014
// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
// For conditions of distribution and use, see copyright notice in "copyright"

#ifndef __fitsdata_h__
#define __fitsdata_h__

#include "base.h"
#include "file.h"

class ColorScale;
class FitsFile;

class FitsBound { 
 public:
  int xmin;
  int xmax;
  int ymin;
  int ymax;
  int zmin;
  int zmax;

  FitsBound(int x0, int y0, int x1, int y1)
    {xmin=x0; xmax=x1; ymin=y0; ymax=y1; zmin=0; zmax=0;}
  FitsBound(int x0, int y0, int x1, int y1, int z0, int z1)
    {xmin=x0; xmax=x1; ymin=y0; ymax=y1; zmin=z0; zmax=z1;}
  FitsBound() {reset();}
  void reset() {xmin= xmax= ymin= ymax= zmin= zmax=0;}
};
ostream& operator<<(ostream&, const FitsBound&);

class FitsData {
protected:
  Base* parent;

  long width;
  long height;
  char buf[32];

  int byteswap;

  double bscale;
  double bzero;
  int hasScaling;

  int hasBlank;
  int blank;

  double high;         // bscale applied
  double low;          // bscale applied

  float zHigh;         // bscale applied
  float zLow;          // bscale applied
  double aLow;	       // bscale applied		    
  double aHigh;	       // bscale applied		    
  double uLow;	       // bscale applied		    
  double uHigh;	       // bscale applied		    

  int scanValid;
  int incr_;

  float zContrast;
  int zSample;
  int zLine;
  int zscaleValid;

  int autoCutValid;
  float autoCutPer;

  FrScale::ClipMode clipMode;
  FrScale::MinMaxMode mmMode;
  FrScale::ScanMode scanMode;

  double datamin;      // bscale applied
  double datamax;      // bscale applied
  int hasdatamin;

  double irafmin;      // bscale applied
  double irafmax;      // bscale applied
  int hasirafmin;

  // zscale constants

  enum PixelType {GOOD_PIXEL, BAD_PIXEL, REJECT_PIXEL};

  int zSubSample(float*, float*, int, int);
  int zFitLine(float*, int, float*, float*, float, int, int);
  void zFlattenData (float*, float*, float*, int npix, float, float dz);
  int zComputeSigma (float*, short*, int npix, float*, float*);
  int zRejectPixels (float*, float*, float*, short*, int, double*, 
		     double*, double*, double*, float, int);

 protected:
  void autoCut(FitsBound*);
  int getIncr();

public:
  FitsData(FitsFile*, Base*);
  virtual ~FitsData();

  virtual const char* getValue(const Vector&) =0;
  virtual float getValueFloat(const Vector&) =0;
  virtual double getValueDouble(const Vector&) =0;
  virtual int getValueMask(const Vector&) =0;
  virtual int getValueMask(double,double) =0;

  virtual float getValueFloat(long) =0;
  virtual double getValueDouble(long) =0;
  virtual int getValueMask(long) =0;

  virtual const char* getMin() =0;
  virtual const char* getMax() =0;
  virtual double getMinDouble() =0;
  virtual double getMaxDouble() =0;

  const char* getLow();
  const char* getHigh();
  double getLowDouble() {return low;}
  double getHighDouble() {return high;}

  void setClip(double l, double h) {low = l; high = h;}

  virtual void updateClip(FrScale*, FitsBound*) =0;
  int hasDATAMIN() {return hasdatamin;}
  int hasIRAFMIN() {return hasirafmin;}

  virtual void bin(double*,int,double,double,FitsBound*) =0;
};

template<class T>
class FitsDatam : public FitsData {
 private:
  T* data;
  T min;               // bscale not applied
  T max;               // bscale not applied

  void updateMinMax(FitsBound*);
  void scan(FitsBound*);
  void output(ostringstream&, T);
  void zscale(FitsBound*);
  int zSampleImage(float**,FitsBound*);

 public:
  FitsDatam(FitsFile*, Base*);

  T swap(T*);

  const char* getValue(const Vector&);

  float getValueFloat(const Vector&);
  double getValueDouble(const Vector&);
  int getValueMask(const Vector&);
  int getValueMask(double, double);

  float getValueFloat(long i);
  double getValueDouble(long i);
  int getValueMask(long i);

  const char* getMin();
  const char* getMax();

  double getMinDouble();
  double getMaxDouble();

  void updateClip(FrScale*, FitsBound*);
  void bin(double*, int, double, double, FitsBound*);
};

#endif
