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

# ifndef DVO_H
# define DVO_H

/* 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_DEV_0,
	      DVO_FORMAT_PANSTARRS_DEV_1,
	      DVO_FORMAT_PS1_DEV_1,
	      DVO_FORMAT_PS1_DEV_2
} 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 {DVO_CAT_OPEN_FAIL, DVO_CAT_OPEN_OK, DVO_CAT_OPEN_EMPTY} DVOCatalogOpenModes;

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;

// these are used as NAN for types of int values
typedef enum {
    NAN_S_CHAR  = 0x7f,
    NAN_U_CHAR  = 0xff,   // was NO_ERR
    NAN_S_SHORT = 0x7fff, // was NO_MAG
    NAN_U_SHORT = 0xffff, 
    NAN_S_INT   = 0x7fffffff,
    NAN_U_INT   = 0xffffffff,
} DVO_INT_NAN;

# ifndef NAN
# ifndef BYTE_SWAP
#  define __nan_bytes           { 0x7f, 0xc0, 0, 0 }
# else
#  define __nan_bytes           { 0, 0, 0xc0, 0x7f }
# endif
static union { unsigned char __c[4]; float __d; } __nan_union
    __attribute_used__ = { __nan_bytes };
# define NAN    (__nan_union.__d)
# endif

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

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

/* 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 */
// XXX replace the # defines with typedef enum
# define ID_MEAS_NOCAL        0x0001  /* detection ignored for this analysis (photcode, time range) -- internal only */
# define ID_MEAS_POOR_PHOTOM  0x0002  /* detection is photometry outlier					     */	  
# define ID_MEAS_SKIP_PHOTOM  0x0004  /* detection was ignored for photometry measurement			     */	  
# define ID_MEAS_AREA         0x0008  /* detection near image edge						     */
# define ID_MEAS_POOR_ASTROM  0x0010  /* detection is astrometry outlier					     */	  
# define ID_MEAS_SKIP_ASTROM  0x0020  /* detection was ignored for astrometry measurement			     */	  
# define ID_MEAS_UNDEF_1      0x0040  /* unused									     */
# define ID_MEAS_UNDEF_2      0x0080  /* unused									     */
# define ID_MEAS_BLEND_MEAS   0x0100  /* detection is within radius of multiple objects				     */
# define ID_MEAS_BLEND_OBJ    0x0200  /* multiple detections within radius of object				     */
# define ID_MEAS_UNDEF_3      0x0400  /* unused									     */
# define ID_MEAS_UNDEF_4      0x0800  /* unused									     */
# define ID_MEAS_BLEND_MEAS_X 0x1000  /* detection is within radius of multiple objects across catalogs		     */
# define ID_MEAS_ARTIFACT     0x2000  /* detection is thought to be non-astronomical				     */
# define ID_MEAS_UNDEF_5      0x4000  /* unused									     */
# define ID_MEAS_UNDEF_6      0x8000  /* unused									     */

// XXX we used these names previously in markstar: replace with ID_MEAS_ARTIFACT
// # 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;
  int ownElements; 				  /* does this list own filename, regions? */
  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 Nsecfilt;  /* number of secfilt entries for each average entry */
  int Naverage,   Nmeasure,   Nmissing,   Nsecf_mem;  /* current number of each component in memory */
  int Naves_disk, Nmeas_disk, Nmiss_disk, Nsecf_disk; /* current number of each component on disk */
  int Naves_off,  Nmeas_off,  Nmiss_off,  Nsecf_off;  /* index of first loaded data value */

  /* note the different counting for Nsecfilt:
     number of secfilt rows on disk is: Nave_disk * Nsecfilt
     number of secfilt rows in mem  is: Naverage * Nsecfilt
     *** that is just silly, and bad: convert to using Nsec_mem, Nsec_disk, Nsec_off.
     *** unless we always require the secfilt and average entries to be loaded sychronously.
   */

  /* 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) */

  unsigned int objID;
  unsigned int catID;

  /* 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 isRegisteredMosaic ();
int GetRegisteredMosaic ();
int GetMosaicCoords (Coords *coords);
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);
double GetZeroPoint ();
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);
void dvo_catalog_free_data (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_save_complete (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);
int dvo_catalog_save_split_complete (Catalog *catalog, char VERBOSE);

int dvo_catalog_load_segment (Catalog *catalog, int VERBOSE, int start, int Nrows);
int dvo_catalog_load_segment_split (Catalog *catalog, int VERBOSE, int start, int Nrows);

/*** 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);

# include "loneos_defs.h"
# include "elixir_defs.h"
# include "panstarrs_dev_0_defs.h"
# include "panstarrs_dev_1_defs.h"
# include "ps1_dev_1_defs.h"
# include "ps1_dev_2_defs.h"

/*** 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        SkyTableFree            PROTO((SkyTable *table));
int        SkyListSetFilenames     PROTO((SkyList *list, char *path, char *ext));
int        SkyTableSetFilenames    PROTO((SkyTable *sky, char *path, char *ext));

/* dvo-specific sorting functions */
void sortave (Average *ave, int N);
void sort_image_subset (Image *image, int *subset, int N);
void sort_coords_index (double *X, double *Y, int *S, int N);
void sort_stars_ra (Stars *stars, int N);
void sort_regions (SkyRegion *region, int N);

# endif
