# include <ohana.h>
# include <dvo.h>
# include <signal.h>
# include <sys/time.h>
# include <time.h>
# include <zlib.h>

/* solaris requires both of these instead of ip.h:
   # include <sys/socket.h>
   # include <netinet/in.h>
*/

/* linux is happy with this, not solaris */
# include <netinet/ip.h>
# include <netdb.h>
# include <arpa/inet.h>
# include <glob.h>

/* used in find_matches, find_matches_refstars */
# define IN_REGION(R,D) ( \
((D) >= region[0].Dmin) && ((D) < region[0].Dmax) && \
((R) >= region[0].Rmin)  && ((R) < region[0].Rmax))

/* grab named photcode */
# define NAMED_PHOTCODE(CODE,NAME) \
  CODE = GetPhotcodeCodebyName (NAME); \
  if (!CODE) { \
    fprintf (stderr, "ERROR:  photcode %s not found in photcode table\n", NAME); \
    exit (0); }

typedef struct {
  int Nstars;
  Stars *stars;
  int Nimages;
  Image *images;
  Coords *mosaic;
  SkyRegion *patch;
  AddstarClientOptions *options;
  char *refcat;
} DVO_DATA;

typedef struct {
  char *exthead;
  char *extdata;
  char *exttype;
  int extnum_head;
  int extnum_data;
} HeaderSet;

typedef struct sockaddr_in SockAddress;

enum {M_IMAGE, M_REFLIST, M_REFCAT, M_FAKEIMAGE, M_RESORT};
enum {NONE, SIMPLE_CMP, SIMPLE_CMF, SIMPLE_MEF, MOSAIC_CMP, MOSAIC_CMF, MOSAIC_MEF, MOSAIC_PHU, SDSS_OBJ};
/* note: MEF implies CMF */

/* globals which define database info / data sources (KEEP) */
char   ImageCat[256];
char   GSCFILE[256];
char   CATDIR[256];
char   CATMODE[16];    /* raw, mef, split, mysql */
char   CATFORMAT[16];  /* internal, elixir, loneos, panstarrs */
char   TWO_MASS_DIR_AS[256];
char   TWO_MASS_DIR_DR2[256];
char   GSCDIR[256];
char   USNO_A_DIR[256];
char   USNO_B_DIR[256];
char   TYCHO_DIR[256];
char   SubpixDatafile[256];
char   PASSWORD[80];
char   HOSTNAME[80];
int    NVALID, *VALID_IP;
char   SKY_TABLE[256];
int    SKY_DEPTH;  /** XXX EAM : depth of catalog tables, fix usage */
char   CameraLayout[256];
SkyTable *ServerSky;
char  *PMM_CCD_TABLE;

/* used to select entries from header (gstars or parse_time) (KEEP) */
char   DateKeyword[64];
char   DateMode[64];
char   UTKeyword[64];
char   MJDKeyword[64];
char   JDKeyword[64];
char   ExptimeKeyword[64];
char   AirmassKeyword[64];
char   CCDNumKeyword[64];
char   STKeyword[64];
char   ExtnameKeyword[64];

/* these globals modify the behavior of gstars (KEEP) */
double 	SNLIMIT;
int    	ACCEPT_ASTROM;  // accept even bad astrometry solutions (NASTRO == 0)
int    	ACCEPT_MOTION;  // accept reference proper motion measurements
int    	ACCEPT_TIME;    // accept time stamp (or 0)
int    	NO_STARS;       // ignore the stars
int    	TEXTMODE;       // force input file to be loaded as RAW
int     SUBPIX;         // apply a subpix correction
char   *DUMP;           // dump out intermediate results
int    	XOVERSCAN;      // used to modify stored image dimensions 
int    	YOVERSCAN;      // used to modify stored image dimensions 
int    	XMIN;           // used to filter loaded star list 
int    	XMAX;           // used to filter loaded star list 
int    	YMIN;           // used to filter loaded star list 
int    	YMAX;           // used to filter loaded star list 
double 	Latitude;       // carried into image structure from config
double 	Longitude;      // carried into image structure from config
double  FAKE_RA;        // boresite coords for fake images
double  FAKE_DEC;       // boresite coords for fake images
double  FAKE_THETA;     // boresite angle for fake images

// carries the mosaic into gstars

/* these globals are used separately by both client and server (KEEP) */
double CAL_INSTMAG_MAX;
double CAL_INSTMAG_MIN;
int    VERBOSE;
int    PLOT;
double MAX_CERROR;

/* modify server behavior (make this an addstar cleanup mode?) */
int    FORCE_READ;

// XXX this should be replaced with 
// 1) an airmass accuracy option
// 2) an alternative CATFORMAT with the sky element correctly defined.

/* these depend on HOW we implement the client/server interaction for CAT/REF modes */
time_t    TIMEREF;    // used by MODE REF
SkyRegion UserPatch;  // used by MODE CAT
char     *SELECT_2MASS_QUALITY;  // used only by get2mass_as

/*** addstar prototypes ***/

void       AddToCalibration       PROTO((Average *average, SecFilt *secfilt, Measure *measure, Measure *new, int *next, int Nstar));
AddstarClientOptions ConfigInit   PROTO((int *argc, char **argv));
void       FindCalibration        PROTO((Image *image));
FILE      *GetDB                  PROTO((int *state));
void       InitCalibration        PROTO(());
void       SaveCalibration        PROTO((float Mo, float dMo, float Mr, float dMr, float Mi, int N));
void       SetProtect             PROTO((int mode));
int        SetSignals             PROTO(());
int        Shutdown               PROTO((char *message, ...); ) 
void       TrapSignal             PROTO((int sig));
float      airmass                PROTO((float secz_image, double ra, double dec, double st, double latitude));
void       SetAirmassQuality      PROTO((int quality));
SkyTable  *SkyTableFromTychoIndex PROTO((char *filename, int VERBOSE));
AddstarClientOptions args         PROTO((int argc, char **argv, AddstarClientOptions options));
void       check_permissions      PROTO((char *basefile));
int        dump_rawstars          PROTO((Stars *stars, int Nstars));
int        edge_check             PROTO((double *x1, double *y1, double *x2, double *y2));
Image     *fakeimage              PROTO((char *rootname, int *Nimage, int photcode));
int        find_matches           PROTO((SkyRegion *region, Stars *stars, int Nstars, Catalog *catalog, AddstarClientOptions options));
int        find_matches_closest   PROTO((SkyRegion *region, Stars *stars, int Nstars, Catalog *catalog, AddstarClientOptions options));
int        find_matches_refstars  PROTO((SkyRegion *region, Stars **stars, int Nstars, Catalog *catalog, AddstarClientOptions options));
Stars    **find_subset            PROTO((SkyRegion *region, Stars *stars, int Nstars, int *NSTARS));
int        gcatalog               PROTO((Catalog *catalog));
Stars     *get2mass               PROTO((SkyRegion *patch, int photcode, int mode, int *NSTARS));
double     get_subpix             PROTO((double x, double y));
Stars     *getgsc                 PROTO((SkyRegion *patch, int *NSTARS));
Stars     *gettycho               PROTO((SkyRegion *catstats, int photcode, int *Nstars));
Stars     *getusno                PROTO((SkyRegion *catstats, int photcode, int *Nstars));
Stars     *getusnob               PROTO((SkyRegion *catstats, int photcode, int *Nstars));
Image     *gimages                PROTO((FITS_DB *db, Image *image, Coords *mosaic, int *Npimage));
Stars     *grefcat                PROTO((char *Refcat, SkyRegion *catstats, int photcode, int *nstars));
Stars     *grefstars              PROTO((char *file, int photcode, int *Nstars));

Stars     *LoadStars              PROTO((char *file, int *Nstars, Image **images, int *Nimages, AddstarClientOptions *options));
Header   **LoadHeaders            PROTO((FILE *f, int *mode, int *Nheader));
HeaderSet *MatchHeaders           PROTO((int **extsize, int *nimage, int mode, Header **headers, int Nheaders));
int        LoadData               PROTO((FILE *f, char *file, Image **images, int *nvalid, Stars **stars, int *Nstars, Header **headers, int *extsize, HeaderSet *headerSets, int NheaderSets));

int        in_image               PROTO((double r, double d, Image *image));
int        load_pt_catalog        PROTO((Catalog *catalog, SkyRegion *region));  /*** choose new name ***/
void       load_subpix            PROTO(());
void       lock_image_db          PROTO((FITS_DB *db, char *filename));
int        main                   PROTO((int argc, char **argv));
void       make_backup            PROTO((char *filename));
int        match_refstars         PROTO((Stars *stars, int Nstars));
void       mkcatalog              PROTO((SkyRegion *region, Catalog *catalog));
double     opening_angle          PROTO((double x1, double y1, double x2, double y2, double x3, double y3));
int        parse_time             PROTO((Header *header));
Stars     *rd_gsc                 PROTO((char *filename, int *nstars));
int        replace_match          PROTO((Average *average, Measure *measure, Stars *star));
void       resort_catalog         PROTO((Catalog *catalog));
Stars     *rfits                  PROTO((FILE *f, unsigned int *nstars));
Stars     *rtext                  PROTO((FILE *f, unsigned int *nstars));
Stars     *ReadStarsFITS          PROTO((FILE *f, Header *header, Header *in_theader, unsigned int *nstars));
Stars     *ReadStarsTEXT          PROTO((FILE *f, unsigned int *nstars));
Stars     *ReadStarsSDSS          PROTO((FILE *f, char *name, Header *header, Header *in_theader, Image *images, int *nimages, unsigned int *nstars));
int        ReadImageHeader        PROTO((Header *header, Image *image, int photcode));
Stars     *FilterStars            PROTO((Stars *instars, Image *image, unsigned int imageID));
Stars     *MergeStars             PROTO((Stars *stars, int *Nstars, Stars *instars, int Ninstars));
void       save_pt_catalog        PROTO((Catalog *catalog));  /*** choose new name ***/
double     scat_subpix            PROTO((double x, double y));
time_t     short_date_to_sec      PROTO((char *date));
void       sort_lists             PROTO((float *X, float *Y, int *S, int N));
void       sort_stars             PROTO((Stars *stars, int N));
int        str_to_radec           PROTO((double *ra, double *dec, char *str1, char *str2));
void       unlock_image_db        PROTO((FITS_DB *db));
void       update_coords          PROTO((Average *average, Measure *measure, int *next));
void       wcatalog               PROTO((Catalog *catalog));
void       free_catalog           PROTO((Catalog *catalog));
void       wimage                 PROTO((FITS_DB *db, Image *image));
void       create_image_db        PROTO((FITS_DB *db));
void       set_db                 PROTO((FITS_DB *in));
void       uppercase              PROTO((char *string));
void       fsort                  PROTO((float *X, int N));
void       fsort2                 PROTO((float *X, float *Y, int N));
int 	  *init_measure_links     PROTO((Average *average, int Naverage, Measure *measure, int Nmeasure));
int 	  *init_missing_links     PROTO((Average *average, int Naverage, Missing *missing, int Nmissing));
int 	   add_meas_link     	  PROTO((Average *average, int *next, int Nmeasure, int NMEASURE));
int 	   add_miss_link     	  PROTO((Average *average, int *next, int Nmissing));
int 	  *build_measure_links    PROTO((Average *average, int Naverage, Measure *measure, int Nmeasure));
Measure   *sort_measure     	  PROTO((Average *average, int Naverage, Measure *measure, int Nmeasure, int *next));
Missing   *sort_missing     	  PROTO((Average *average, int Naverage, Missing *missing, int Nmissing, int *next_miss));
int        ImageOptions		  PROTO((AddstarClientOptions *options, Image *images, int Nimages));
int        GetFileMode		  PROTO((Header *header));
AddstarClientOptions args_client  PROTO((int argc, char **argv, AddstarClientOptions options));
AddstarClientOptions args_load2mass PROTO((int argc, char **argv, AddstarClientOptions options));
AddstarClientOptions args_sedstar PROTO((int argc, char **argv, AddstarClientOptions options));
void	   args_server		  PROTO((int argc, char **argv));
int 	   CheckPassword	  PROTO((int BindSocket));
int 	   NewImage		  PROTO((int BindSocket));
int 	   NewReflist		  PROTO((int BindSocket));
int 	   NewRefcat		  PROTO((int BindSocket));
int 	   InitServerSocket	  PROTO((SockAddress *Address));
int 	   WaitServerSocket	  PROTO((int InitSocket, SockAddress *Address, int *validIP, int Nvalid));
int 	   GetClientSocket	  PROTO((char *hostname));
int 	   UpdateDatabase_Image	  PROTO((AddstarClientOptions *options, Image *images, int Nimages, Coords *mosaic, Stars *stars, int Nstars));
int 	   UpdateDatabase_Reflist PROTO((AddstarClientOptions *options, Stars *stars, int Nstars));
int 	   UpdateDatabase_Refcat  PROTO((AddstarClientOptions *options, SkyRegion *UserPatch, char *refcat));
SkyList   *SkyListForStars	  PROTO((SkyTable *table, int depth, Stars *stars, int Nstars));
SkyList   *SkyListExistingSubset  PROTO((SkyList *input, char *path));
int        SkyListSetPath	  PROTO((SkyList *list, char *path));
SkyTable  *SkyTableLoadOptimal	  PROTO(());
int 	   InitDataset		  PROTO(());
int 	   PushDataset		  PROTO((DVO_DATA *data));
DVO_DATA  *PopDataset		  PROTO((void));
void	  *ListenClients_Thread	  PROTO((void *data));
int 	   NewImage_Thread	  PROTO((int BindSocket));
int 	   NewRefcat_Thread	  PROTO((int BindSocket));
int 	   NewReflist_Thread	  PROTO((int BindSocket));

Stars     *Convert_SMPDATA	  PROTO((FTable *table, int *nstars));
Stars     *Convert_PS1_DEV_0	  PROTO((FTable *table, int *nstars));
Stars     *Convert_PS1_DEV_1	  PROTO((FTable *table, int *nstars));

int args_skycells (int argc, char **argv);
int ConfigInit_skycells (int *argc, char **argv);
int UpdateImageIDs (Stars *stars, int Nstars, Image *images, int Nimages);
int LoadDataSDSS (FILE *f, char *file, Image **images, int *nvalid, Stars **stars, int *Nstars, Header **headers, int *extsize, HeaderSet *headerSets, int Nimages);
int altaz (double *alt, double *az, double ha, double dec, double latitude);

int LoadDataPMM (FILE *f, char *file, Image **images, int *nvalid, Stars **stars, int *Nstars);
PhotCode *LoadMetadataPMM (char *datafile, Image *image);
time_t pmm_date_to_sec (char *date, char *time);
double pmm_get_ra (char *RA);
double pmm_get_dec (char *DEC);
PhotCode *pmm_get_photcode (char *emulsion, char *filter);

// this is a gnu extension?? caution!
void *memrchr(const void *s, int c, size_t n);

/** 
    there is an inconsistency to be resolved: fixed structures (like Image)
    need a fixed bit-length time (e_time), but these functions all use the
    UNIX time_t types, which may be 32 or 64 bits, depending on the machine.
    This can be resolved by using time_t with these functions, but casting 
    between e_time and time_t when necessary (ie, cannot return data to an
    e_time pointer from one of these functions)
**/


/** function for client / server **/ 

