# include <ohana.h>
# include <gfitsio.h>
# include <autocode.h>

# ifndef DVO_H
# define DVO_H

/*
  # define ELIXIR 1
  # define PANSTARRS 0
  # define LONEOS 0
*/

/*** named data values (convert all to enums?) ***/

/* DVO table modes */
typedef enum {DVO_MODE_UNDEF, DVO_MODE_RAW, DVO_MODE_MEF, DVO_MODE_SPLIT, DVO_MODE_MYSQL} DVOTableMode;

/* DVO table formats */
typedef enum {DVO_FORMAT_UNDEF, 
      DVO_FORMAT_INTERNAL, 
      DVO_FORMAT_ELIXIR, 
      DVO_FORMAT_LONEOS, 
      DVO_FORMAT_PANSTARRS, 
      DVO_FORMAT_PMTEST, 
      DVO_FORMAT_PANSTARRS_DEV_0,
      DVO_FORMAT_PANSTARRS_DEV_1
} DVOTableFormat;

/* image data modes in RegImage */
typedef enum {T_UNDEF = -1, T_NONE, T_OBJECT, T_DARK, T_BIAS, T_FLAT, T_MASK, T_FRINGE, T_SCATTER, T_MODES, T_FRINGEPTS, T_ANY, N_TYPE} ElixirDetrendTypes;
typedef enum {M_UNDEF = -1, M_NONE, M_MEF, M_SPLIT, M_SINGLE, M_CUBE, M_SLICE, M_MODES, N_MODE} ElixirDetrendModes;

typedef enum {
    PROJ_NONE, // undefined
    PROJ_ZEA, // zenithal
    PROJ_ZPL, // zenithal
    PROJ_ARC, // zenithal
    PROJ_STG, // zenithal
    PROJ_SIN, // zenithal
    PROJ_TAN, // zenithal
    PROJ_DIS, // zenithal (TAN + polyterms)
    PROJ_LIN, // cartesian
    PROJ_PLY, // cartesian
    PROJ_WRP, // cartesian
    PROJ_AIT, // pseudocyl
    PROJ_GLS, // pseudocyl
    PROJ_PAR, // pseudocyl
} OhanaProjection;

typedef enum {
  PROJ_MODE_NONE,
  PROJ_MODE_CARTESIAN,
  PROJ_MODE_ZENITHAL,
  PROJ_MODE_PSEUDOCYL,
} OhanaProjectionMode;

/* RegImage.flag values */
# define IMREG_DIST  0x01 /* image distributed, only imregister-3.0 */

/* catalog values to be loaded */
# define LOAD_AVES 	0x01
# define LOAD_MEAS 	0x02
# define LOAD_MISS 	0x04
# define LOAD_SECF 	0x08 
# define LOAD_MEAS_META 0x10

/* invalid mag value */
# define NO_MAG    0x7fff
# define NO_ERR    0xff

/* photometry code types */
// # define PHOT_PRI 0x01
# define PHOT_SEC 0x02
# define PHOT_DEP 0x03
# define PHOT_REF 0x04
# define PHOT_ALT 0x05  /* never stored, only for look-ups */
# define PHOT_MAG 0x06  /* generic magnitude; never stored */

/* Image.code values.  these are codes to note bad images */
# define ID_IMAGE_NEW   0x0000  /* no nrphot attempted */
# define ID_IMAGE_NOCAL 0x0001  /* used within nrphot to mean "don't apply fit" */
# define ID_IMAGE_POOR  0x0002  /* relphot says image is bad */
# define ID_IMAGE_SKIP  0x0004  /* external information image is bad */
# define ID_IMAGE_FEW   0x0008  /* currently too few measurements for good value */

/* Measure.flags values */
# define ID_MEAS_NOCAL        0x0001
# define ID_MEAS_POOR         0x0002
# define ID_MEAS_SKIP         0x0004
# define ID_MEAS_AREA         0x0008
# define BLEND_IMAGE          0x0100 
# define BLEND_CATALOG        0x0200
# define BLEND_IMAGE_NEIGHBOR 0x1000
# define ID_MEAS_TRAIL        0x2000
# define ID_MEAS_GHOST        0x4000

/* some subtle distinctions between the blend flags:
   BLEND_IMAGE: the star on an image is matched with more 
   than one star in the catalog (image has worse seeing than catalog)
   BLEND_CATALOG: the star in the catalog is matched with more 
   than one star on the image (image has better seeing than catalog)
   CALIBRATED: relative photometry has been performed on this measurement
   BLEND_IMAGE_NEIGHBOR: the star on an image is matched with more 
   than one star in the catalog, but not in the same catalog file.
*/

/* Average.code values */
# define ID_STAR_FEW   0x0001 /* used within relphot: skip star */
# define ID_STAR_POOR  0x0002 /* used within relphot: skip star */
# define ID_PROPER     0x0400 /* star with large proper motion */
# define ID_TRANSIENT  0x1000 /* is this mutually exclusive with USNO?  */
# define ID_VARIABLE   0x2000 /* not currently set? */
# define ID_ASTEROID   0x2000 /* identified with an asteroid */
# define ID_BAD_OBJECT 0x4000 /* if all measurements are bad, set this bit */
# define ID_MOVING     0x8000
# define ID_ROCK       0xa000 /* 0x8000 + 0x2000 */
# define ID_GHOST      0xc001 /* 0x8000 + 0x4000 + 0x0001 */
# define ID_TRAIL      0xc002 /* 0x8000 + 0x4000 + 0x0002 */
# define ID_BLEED      0xc003 /* 0x8000 + 0x4000 + 0x0003 */ 
# define ID_COSMIC     0xc004 /* 0x8000 + 0x4000 + 0x0004 */ 

/*** general dvo structures (internal use only / not IO) ***/

/* FITS DB structure */
typedef struct {
  FILE  *f;
  char  *filename;
  int    dbstate;
  int    lockstate;
  double timeout;
  Header header;
  Matrix matrix;
  Header theader;
  FTable ftable;
  VTable vtable;
  int    mode;          /* what data storage mode is used for disk file? */
  int    format;        /* what data format is used for disk file? */
  int    virtual;       /* is table in ftable or vtable? */
  int    swapped;       /* is table in internal byte-order? */
} FITS_DB;

/* the basic HST GSC layout corresponds to a depth of 3 */
# define SKY_DEPTH_HST 3

/* SkyRegion : better implementation than GSCRegion */
typedef struct {
  int Nregions;
  char **filename;
  SkyRegion *regions;
} SkyTable;

typedef struct {
  int Nregions;
  char **filename;
  SkyRegion **regions;
} SkyList;

# if (0)
/* structure for data on a catalog region */
typedef struct {
  char filename[256];
  double DEC[2], RA[2];
} GSCRegion;
# endif

typedef struct {
  int Ncode;					  // number of photcodes
  int Nsecfilt;					  // number of average magnitudes
  int hashcode[0x10000];		  // index from photcode value to sequence
  int hashNsec[0x10000];		  // index from photcode value to Nsec seq
  int codeNsec[0x10000];		  // index from Nsec seq to photcode value
  PhotCode *code;
} PhotCodeData;

/* a catalog contains this data */
typedef struct Catalog {
  char *filename;			/* catalog file */
  FILE *f;  				/* file descriptor */
  Header  header;

  /* data in the catalog file */
  Average *average;
  Measure *measure; 
  Missing *missing; 
  SecFilt *secfilt;
  int Naverage, Nmeasure, Nmissing, Nsecfilt;   /* current number of each component */
  int Nave_disk, Nmeas_disk, Nmiss_disk;        /* number of component on disk */
  int Nmeas_off;			        /* dist seq of first loaded data value */
  /* note the different counting for Nsecfilt */

  /* pointers to split data files */
  struct Catalog *measure_catalog;		/* measure catalog data (split) */
  struct Catalog *missing_catalog;		/* missing catalog data (split) */
  struct Catalog *secfilt_catalog;		/* secfilt catalog data (split) */

  /* extra catalog information */
  int lockmode;
  int catmode;				/* storage mode (raw, mef, split, mysql) */
  int catformat;			/* storage format (elixir, panstarrs, etc) */
  int catflags;				/* choices to be loaded */
  int sorted;				/* is measure table average-sorted? */
  
  /* pointers for data manipulation */
  int *found;
  int *image;
  int *mosaic;
  float *X;
  float *Y;

} Catalog;

/*** prototypes ***/

/* in gfits_db.c */
int   gfits_db_init                PROTO((FITS_DB *db));
int   gfits_db_create              PROTO((FITS_DB *db));
int   gfits_db_lock                PROTO((FITS_DB *db, char *filename));
int   gfits_db_load                PROTO((FITS_DB *db));
int   gfits_db_load_segment        PROTO((FITS_DB *db, int start, int Nrows));
int   gfits_db_save                PROTO((FITS_DB *db));
int   gfits_db_update              PROTO((FITS_DB *db));
int   gfits_db_close               PROTO((FITS_DB *db));
int   gfits_db_free                PROTO((FITS_DB *db));

/* in coords.c, using libautocode/def/coords.d */
int  XY_to_LM (double *L, double *M, double x,  double y,   Coords *coords);
int  LM_to_XY (double *x,  double *y,   double L, double M, Coords *coords);
int  RD_to_LM (double *L, double *M, double ra,  double dec,   Coords *coords);
int  LM_to_RD (double *ra, double *dec,   double L, double M, Coords *coords);
int  XY_to_RD (double *ra, double *dec, double x,  double y,   Coords *coords);
int  RD_to_XY (double *x,  double *y,   double ra, double dec, Coords *coords);
int  fXY_to_RD (float *ra, float *dec, double x,  double y,   Coords *coords);
int  fRD_to_XY (float *x,  float *y,   double ra, double dec, Coords *coords);
int  GetCoords (Coords *coords, Header *header);
int  PutCoords (Coords *coords, Header *header);
void RegisterMosaic (Coords *coords);
void coords_precess (double *ra, double *dec, double in_epoch, double out_epoch);
OhanaProjection GetProjection (char *ctype);
int SetProjection (char *ctype, OhanaProjection proj);
OhanaProjectionMode GetProjectionMode (OhanaProjection proj);

char *libdvo_version ();

int GetRegisteredMosaic ();
int FindMosaicForImage (Image *images, int Nimages, int entry);
int FindMosaicForImage_TableSearch (Image *images, int Nimages, int entry);
int FindMosaicForImage_MatchSearch (Image *images, int Nimages, int entry);
int BuildChipMatch (Image *images, int Nimages);
void SetImageCorners (double *X, double *Y, Image *image);

short int putMi (double value);
double getMi (short int value);
void returnMcal (Image *image, double *c);
void assignMcal (Image *image, double *c, int order);
double applyMcal (Image *image, double x, double y);
double findscatter (double *X, double *Y, double *M, double *dM, int N, double *c, int order);

PhotCode *GetPhotcodebyName (char *name);
PhotCode *GetPhotcodeEquivbyName (char *name);
PhotCode *GetPhotcodebyCode (int code);
PhotCode *GetPhotcodebyNsec (int Nsec);
PhotCode *GetPhotcodeEquivbyCode (int code);
char     *GetPhotcodeNamebyCode (int code);

float PhotInst (Measure *measure);
float PhotCat (Measure *measure);
float PhotSys (Measure *measure, Average *average, SecFilt *secfilt);
float PhotRel (Measure *measure, Average *average, SecFilt *secfilt);
float PhotCal (Measure *thisone, Average *average, SecFilt *secfilt, Measure *measure, PhotCode *code);
float PhotAve (PhotCode *code, Average *average, SecFilt *secfilt);
float PhotRef (PhotCode *code, Average *average, SecFilt *secfilt, Measure *measure);
float PhotXm (PhotCode *code, Average *average, SecFilt *secfilt);
float PhotdM (PhotCode *code, Average *average, SecFilt *secfilt);

float PhotColorForCode (Average *average, SecFilt *secfilt, Measure *measure, PhotCode *code);
int PhotColor (Average *average, SecFilt *secfilt, Measure *measure, int c1, int c2, double *color);

PhotCodeData *GetPhotcodeTable ();

int LoadPhotcodes (char *catdir_file, char *master_file);
int LoadPhotcodesText (char *filename);
int LoadPhotcodesFITS (char *filename);
int SavePhotcodesText (char *filename);
int SavePhotcodesFITS (char *filename);

void PrintPhotcodeNamebyCode (FILE *f, char *format, int code);

int GetPhotcodeCodebyName (char *name);
int GetPhotcodeEquivCodebyName (char *name);
int GetPhotcodeEquivCodebyCode (int code);
int GetPhotcodeNsec (int code);
int GetPhotcodeNsecfilt ();
void SetZeroPoint (double ZP);
int *GetPhotcodeEquivList (int code, int *nlist);
void ParseColorTerms (char *terms, float *X, int *N);

int get_image_type (char *name);
char *get_type_name (int type);
int get_image_mode (char *name);
char *get_mode_name (int mode);

/* these functions refer to the DVO structures defined in the includes above
 *  they are being replaced with autocode entries (drop when totally autocoded)
 */

int   Fread (void *ptr, int size, int nitems, FILE *f, char *type);
int   Fwrite (void *ptr, int size, int nitems, FILE *f, char *type);
int   ByteSwap (char *ptr, int size, int nitems, char *type);
int   ConvertStruct (char *buffer, int size, int Nbytes, char *type);

/** dvo_catalog APIs */
void dvo_catalog_init (Catalog *catalog, int complete);
void dvo_catalog_create (SkyRegion *region, Catalog *catalog);
void dvo_catalog_free (Catalog *catalog);
int dvo_catalog_check (Catalog *catalog, int Nsecfilt, int extend);
int dvo_catalog_lock (Catalog *catalog, int lockmode);
int dvo_catalog_unlock (Catalog *catalog);
int dvo_catalog_load (Catalog *catalog, int VERBOSE);
int dvo_catalog_open (Catalog *catalog, SkyRegion *region, int VERBOSE, char *iomode);
int dvo_catalog_save (Catalog *catalog, char VERBOSE);
int dvo_catalog_update (Catalog *catalog, char VERBOSE);
int dvo_catalog_catformat (char *catformat);
int dvo_catalog_catmode (char *catmode);
void dvo_catalog_test (Catalog *catalog, int halt);

/* catmode-specific APIs */
int dvo_catalog_load_raw (Catalog *catalog, int VERBOSE);
int dvo_catalog_save_raw (Catalog *catalog, char VERBOSE);
int dvo_catalog_load_mef (Catalog *catalog, int VERBOSE);
int dvo_catalog_save_mef (Catalog *catalog, char VERBOSE);
int dvo_catalog_load_split (Catalog *catalog, int VERBOSE);
int dvo_catalog_save_split (Catalog *catalog, char VERBOSE);
int dvo_catalog_update_split (Catalog *catalog, char VERBOSE);

/*** conversion functions / I/O conversions ***/
Average *ReadRawAverage (FILE *f, int Naverage, int format, SecFilt **primary);
Measure *ReadRawMeasure (FILE *f, int Nmeasure, int format);
SecFilt *ReadRawSecFilt (FILE *f, int Nsecfilt, int format);
int WriteRawAverage (FILE *f, Average *average, int Naverage, int format, SecFilt *primary);
int WriteRawMeasure (FILE *f, Measure *measure, int Nmeasure, int format);
int WriteRawSecFilt (FILE *f, SecFilt *secfilt, int Nsecfilt, int format);

Average *FtableToAverage (FTable *ftable, int *Naverage, int *format, SecFilt **primary);
Measure *FtableToMeasure (FTable *ftable, int *Nmeasure, int *format);
SecFilt *FtableToSecFilt (FTable *ftable, int *Nsecfilt, int *format);
int FtableToImage (FTable *ftable, Header *theader, int *format);

int AverageToFtable (FTable *ftable, Average *average, int Naverage, int format, SecFilt *primary);
int MeasureToFtable (FTable *ftable, Measure *measure, int Nmeasure, int format);
int SecFiltToFtable (FTable *ftable, SecFilt *secfilt, int Nsecfilt, int format);
int ImageToFtable (FTable *ftable, Header *theader, int format);
int ImageToVtable (VTable *vtable, Header *theader, int format);

Image 		       *ImageElixirToInternal (ImageElixir *in, int Nvalues);
Image 		       *ImageLoneosToInternal (ImageLoneos *in, int Nvalues);
Image 		       *ImagePanstarrsToInternal (ImagePanstarrs *in, int Nvalues);
Image 		       *ImagePanstarrs_DEV_0_ToInternal (ImagePanstarrs_DEV_0 *in, int Nvalues);
Image 		       *ImagePanstarrs_DEV_1_ToInternal (ImagePanstarrs_DEV_1 *in, int Nvalues);

ImageElixir 	       *ImageInternalToElixir (Image *in, int Nvalues);
ImageLoneos 	       *ImageInternalToLoneos (Image *in, int Nvalues);
ImagePanstarrs         *ImageInternalToPanstarrs (Image *in, int Nvalues);
ImagePanstarrs_DEV_0   *ImageInternalToPanstarrs_DEV_0 (Image *in, int Nvalues);
ImagePanstarrs_DEV_1   *ImageInternalToPanstarrs_DEV_1 (Image *in, int Nvalues);

Average                *AverageLoneosToInternal (AverageLoneos *in, int Nvalues, SecFilt **primary);
Average 	       *AverageElixirToInternal (AverageElixir *in, int Nvalues, SecFilt **primary);
Average 	       *AveragePanstarrsToInternal (AveragePanstarrs *in, int Nvalues);
Average 	       *AveragePanstarrs_DEV_0_ToInternal (AveragePanstarrs_DEV_0 *in, int Nvalues);
Average 	       *AveragePanstarrs_DEV_1_ToInternal (AveragePanstarrs_DEV_1 *in, int Nvalues);

AverageLoneos 	       *AverageInternalToLoneos (Average *in, int Nvalues, SecFilt *primary);
AverageElixir 	       *AverageInternalToElixir (Average *in, int Nvalues, SecFilt *primary);
AveragePanstarrs       *AverageInternalToPanstarrs (Average *in, int Nvalues);
AveragePanstarrs_DEV_0 *AverageInternalToPanstarrs_DEV_0 (Average *in, int Nvalues);
AveragePanstarrs_DEV_1 *AverageInternalToPanstarrs_DEV_1 (Average *in, int Nvalues);

Measure                *MeasureLoneosToInternal (MeasureLoneos *in, int Nvalues);
Measure 	       *MeasureElixirToInternal (MeasureElixir *in, int Nvalues);
Measure 	       *MeasurePanstarrsToInternal (MeasurePanstarrs *in, int Nvalues);
Measure 	       *MeasurePanstarrs_DEV_0_ToInternal (MeasurePanstarrs_DEV_0 *in, int Nvalues);
Measure 	       *MeasurePanstarrs_DEV_1_ToInternal (MeasurePanstarrs_DEV_1 *in, int Nvalues);

MeasureLoneos 	       *MeasureInternalToLoneos (Measure *in, int Nvalues);
MeasureElixir 	       *MeasureInternalToElixir (Measure *in, int Nvalues);
MeasurePanstarrs       *MeasureInternalToPanstarrs (Measure *in, int Nvalues);
MeasurePanstarrs_DEV_0 *MeasureInternalToPanstarrs_DEV_0 (Measure *in, int Nvalues);
MeasurePanstarrs_DEV_1 *MeasureInternalToPanstarrs_DEV_1 (Measure *in, int Nvalues);

SecFilt 	       *SecFiltLoneosToInternal (SecFiltLoneos *in, int Nvalues);
SecFilt 	       *SecFiltElixirToInternal (SecFiltElixir *in, int Nvalues);
SecFilt 	       *SecFiltPanstarrsToInternal (SecFiltPanstarrs *in, int Nvalues);
SecFilt 	       *SecFiltPanstarrs_DEV_0_ToInternal (SecFiltPanstarrs_DEV_0 *in, int Nvalues);
SecFilt 	       *SecFiltPanstarrs_DEV_1_ToInternal (SecFiltPanstarrs_DEV_1 *in, int Nvalues);

SecFiltLoneos 	       *SecFiltInternalToLoneos (SecFilt *in, int Nvalues);
SecFiltElixir 	       *SecFiltInternalToElixir (SecFilt *in, int Nvalues);
SecFiltPanstarrs       *SecFiltInternalToPanstarrs (SecFilt *in, int Nvalues);
SecFiltPanstarrs_DEV_0 *SecFiltInternalToPanstarrs_DEV_0 (SecFilt *in, int Nvalues);
SecFiltPanstarrs_DEV_1 *SecFiltInternalToPanstarrs_DEV_1 (SecFilt *in, int Nvalues);

/*** DVO image db I/O Functions ***/
int dvo_image_lock (FITS_DB *db, char *filename, double timeout, int lockstate);
int dvo_image_unlock (FITS_DB *db);
int dvo_image_load (FITS_DB *db, int VERBOSE, int FORCE_READ);
int dvo_image_save (FITS_DB *db, int VERBOSE);
int dvo_image_update (FITS_DB *db, int VERBOSE);
int dvo_image_load_raw (FITS_DB *db, int VERBOSE, int FORCE_READ);
int dvo_image_update_raw (FITS_DB *db, int VERBOSE);
int dvo_image_save_raw (FITS_DB *db, int VERBOSE);
int dvo_image_addrows (FITS_DB *db, Image *new, int Nnew);
void dvo_image_create (FITS_DB *db, double ZeroPoint);

/* skyregion APIs */
int        SkyTableSave        	   PROTO((SkyTable *table, char *filename));
SkyTable  *SkyTableLoad        	   PROTO((char *filename, int VERBOSE));
SkyTable  *SkyTableFromGSC     	   PROTO((char *filename, int depth, int VERBOSE));
SkyTable  *SkyTableLoadOptimal 	   PROTO((char *catdir, char *SKYFILE, char *GSCFILE, int depth, int VERBOSE));
int        SkyTableSetDepth    	   PROTO((SkyTable *sky, int depth));
SkyList   *SkyRegionByPoint    	   PROTO((SkyTable *table, int depth, double ra, double dec));
SkyList   *SkyListByPoint      	   PROTO((SkyTable *table, double ra, double dec));
SkyList   *SkyListByRadius     	   PROTO((SkyTable *table, int depth, double RA, double DEC, double radius));
SkyList   *SkyListByPatch      	   PROTO((SkyTable *table, int depth, SkyRegion *patch));
SkyList   *SkyListByName      	   PROTO((SkyTable *table, char *name));
SkyList   *SkyListByImage      	   PROTO((SkyTable *table, int depth, Image *image));
SkyList   *SkyListByBounds     	   PROTO((SkyTable *table, int depth, double Rmin, double Rmax, double Dmin, double Dmax));
SkyList   *SkyListChildrenByBounds PROTO((SkyTable *table, int No, int depth, double Rmin, double Rmax, double Dmin, double Dmax));
int        SkyListMerge     	   PROTO((SkyList **outlist, SkyList *newlist));
int        SkyListFree             PROTO((SkyList *list, int ELEMENTS));
int        SkyTableFree            PROTO((SkyTable *table));
int        SkyListSetFilenames     PROTO((SkyList *list, char *path, char *ext));
int        SkyTableSetFilenames    PROTO((SkyTable *sky, char *path, char *ext));

# endif
