// 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__

#include <pthread.h>

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

#include "smooth.h"

typedef struct {
  char* dest;
  char** sjv;
  int ww;
  int hh;
  int dd;
  int bz;
  int mm;
} t_reorder_arg;

class FVContour;

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 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 reorderThread(t_reorder_arg*, char*, void* (void*), int*);

  int nhdu();
  void updateClip(FrScale*);

 protected:
  pthread_t* thread_;
  t_smooth_arg* targ_;

 public:
  Context();
  ~Context();

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

  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();

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

  int isMosaic() {return mosaicCount_>1 ? 1 : 0;}
  int isCube() {return nhdu()>1 ? 1 : 0;}

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

  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_;}

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

  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 updateBin(Base*);
  void updateBlock();
  void updateBinFileNames();
  void updateClip();
  void updateContours();
  void updateContours(const Matrix&);
  void updateSlice(int, int);
};

#endif
