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

#ifndef __context_h__
#define __context_h__

#ifndef __WIN32
#include <pthread.h>
#endif

#include "base.h"
#include "coord.h"
#include "frscale.h"
#include "list.h"
#include "fitsmask.h"
#include "fitsimage.h"
#include "head.h"

class FVContour;

class FitsZBound { 
 public:
  int zmin;
  int zmax;

 public:
  FitsZBound() {zmin= zmax=0;}
  FitsZBound(int z0, int z1) {zmin=z0; zmax=z1;}
  FitsZBound(const FitsZBound &bb) {zmin=bb.zmin; zmax=bb.zmax;}
  void set(int z0, int z1) {zmin=z0; zmax=z1;}
};
ostream& operator<<(ostream&, const FitsZBound&);

class Context {
 public:
  enum SmoothFunction {BOXCAR, TOPHAT, GAUSSIAN};

  FitsImage* bfits_;
  FitsImage* fits;
  FitsImage* cfits;

  List <FitsMask> mask;

  FVContour* contour;
  List<Contour> auxcontours;

  FrScale frScale;

 private:
  Base* parent_;

  int shareWCS_;

  int manageAxes_;
  int axesOrder_;

  int baxis_[FTY_MAXAXES]; // the first two are ignored
  int* naxis_; // the first two are ignored
  int slice_[FTY_MAXAXES]; // the first two are ignored

  int mosaicCount_;
  Base::MosaicType mosaicType;
  Coord::CoordSystem mosaicSystem;

  FitsHist::Function binFunction_;
  Vector binFactor_;
  int binBufferSize_;
  int binDepth_;

  Vector blockFactor_;

  int doSmooth_;
  SmoothFunction smoothFunction_;
  int smoothRadius_;

  void reorderAxis(char*, char**, int, int, int, size_t);
#ifndef __WIN32
  void reorderThread(void*, char*, void* (void*), int*);
#endif

  FitsZBound iparams; // image bbox
  FitsZBound cparams; // crop bbox

 private:
  void binFinish();
  int blockMask();
  int nhdu();
  void loadFinishMask();
  void loadFinishMosaic(FitsImage*);
  int loadFinishMosaicMask();
  int processMosaicKeywords(FitsImage*);
  void updateClip(FrScale*);

 protected:
#ifndef __WIN32
  pthread_t* thread_;
#endif

 public:
  Context();
  ~Context();

  int shareWCS() {return shareWCS_;}

  void analysis();
  int axesOrder() {return axesOrder_;}

  Matrix bin(const Vector&);
  Matrix binCenter();
  Matrix binCursor();

  int block();
  void bltHist(char*, char*, int);

  int calcSlice();
  void clearContour();
  void contourAuxHead() {auxcontours.head();}
  void contourAuxNext() {auxcontours.next();}

  void deleteFits(FitsImage*);

  int fitsCount();

  Vector getClip(FrScale::ClipMode, float);
  Vector getClip();
  FitsZBound* getDataParams(FrScale::ScanMode);   // return bbox in IMAGE
  Vector getMinMax();

  int hasContour() {return contour ? 1 : 0;}
  int hasContourAux() {return auxcontours.current() ? 1 : 0;}
  double* histequ() {return frScale.histequ(fits);}

  Coord::Orientation IRAFOrientation(Coord::Orientation oo) 
    {return parent_->IRAFOrientation(oo);}
  int isMosaic() {return mosaicCount_>1 ? 1 : 0;}
  int isCube() {return nhdu()>1 ? 1 : 0;}

  int load(Base::MemType, const char*, FitsImage*, Base::LayerType);
  int loadExtCube(Base::MemType, const char*, FitsImage*);
  int loadSlice(Base::MemType, const char*, FitsImage*);
  int loadMosaic(Base::MemType, const char*, FitsImage*, 
		 Base::LayerType, Base::MosaicType, Coord::CoordSystem);
  int loadMosaicImage(Base::MemType, const char*, FitsImage*, 
		      Base::LayerType, Base::MosaicType, Coord::CoordSystem);
  int loadMosaicWFPC2(Base::MemType, const char*, FitsImage*);
  void loadInit(int, Base::MosaicType, Coord::CoordSystem);
  int loadFinish();

  int naxis(int ii) {return naxis_[ii];}
  int naxes();

  void parent(Base* pp) {parent_ = pp;}

  void reorderAxes();
  void reorderWCSi(FitsHead*, char*, int, char);
  void reorderWCSij(FitsHead*, char*, int, char);

  void setContour(FVContour*);
  int slice(int ii) {return slice_[ii];}

  void setAxesOrder(int);
  void setBinFunction(FitsHist::Function f) {binFunction_ = f;}
  void setBinFactor(const Vector&);
  void setBinToFactor(const Vector&);
  void setBinBufferSize(int s) {binBufferSize_ = s;}
  void setBinDepth(int d) {binDepth_ = d < 1 ? 1 : d;}
  FitsHist::Function binFunction() {return binFunction_;}
  Vector binFactor() {return binFactor_;}
  int binBufferSize() {return binBufferSize_;}
  int binDepth() {return binDepth_;}

  Vector setBlockFactor(const Vector&);
  Vector setBlockToFactor(const Vector&);
  const Vector& blockFactor() {return blockFactor_;}

  void setCrop3dParams();
  void setCrop3dParams(int,int);
  void setCrop3dParams(double, double);

  void setSmooth(int ss) {doSmooth_ =ss;}
  void setSmooth(int ss, SmoothFunction ff, int rr)
  {doSmooth_=ss; smoothFunction_=ff; smoothRadius_=rr;}
  int hasSmooth() {return doSmooth_;}
  SmoothFunction smoothFunction() {return smoothFunction_;}
  int smoothRadius() {return smoothRadius_;}

  void unload();
  void updateBinFileNames();
  void updateClip();
  void updateContours();
  void updateContours(const Matrix&);
  void updateContoursScale();
  void updateSlice(int, int);
};

#endif
