/* FITS specific macros and structures */

# include <assert.h>
# include <errno.h>

# ifndef GFITSIO
# define GFITSIO

/* also defined in libautocode/def/common.h */
/* what about lin64 ?? - 'linux' might be defined automatically by linux */
# ifndef BYTE_SWAP
# ifdef linux
# define BYTE_SWAP
# endif

# ifdef sid
# define BYTE_SWAP
# endif

# ifdef darwin_x86
# define BYTE_SWAP
# endif

# ifdef dec
# define BYTE_SWAP
# endif
# endif /* BYTE_SWAP */

# ifndef NEWLINE
# define NEWLINE                 10  /* UNIX RETURN character */
# endif /* NEWLINE */

/********** FITS Constants *********/
# define FT_TEXT_LENGTH          18  /* max length text header field */
# define FT_MAX_NAXES            10  /* max number of axes */
# define FT_FIELD_LENGTH          8  /* max length header field */   
# define FT_COMMENT_LENGTH       47  /* max length comment field */
# define FT_HISTORY_LENGTH       72  /* max length history / comment */
# define FT_LINE_LENGTH          80  /* FITS header line length */
# define FT_RECORD_SIZE        2880  /* FITS block size */

/* this structure defines the buffer which contains a header
   and contains the minimum required keywords */

typedef struct {
  int                     simple; // T or F
  int                     unsign; // T or F
  int                     extend; // T or F
  int                     bitpix; // 8, 16, 32, 64, or -32, -64
  int                     Naxes;  // < FT_MAX_NAXES (10)
  off_t                   Naxis[FT_MAX_NAXES];
  off_t                   datasize;
  int                     pcount;
  int                     gcount;
  double                  bzero;
  double                  bscale;
  char                   *buffer;
} Header;

/* this structure defines the buffer which contains a matrix
   and contains some relavant info */

typedef struct {
  int                     unsign;
  int                     bitpix;
  int                     Naxes;
  off_t                   Naxis[FT_MAX_NAXES];
  off_t                   datasize;
  double                  bzero;
  double                  bscale;
  char                   *buffer;
} Matrix;
   
/* the FTable represents a complete table on disk */          
typedef struct {
  Header                 *header;
  char                   *buffer;
  off_t                   datasize;
} FTable;

/* the VTable represents rows from a table on disk */          
typedef struct {
  Header                 *header;
  char                  **buffer;
  off_t                   Nrow;
  off_t                  *row;
  off_t                   datasize;  /* total buffer size */
  off_t                   pad;   /* bytes of padding at the end */
} VTable;

typedef struct {
  int   maxlen; 	      // max size of all table rows
  int   nbytes;		      // number of bytes per column element
  int   Nstart;		      // byte offset of this column relative to first column
  off_t heap_start;	      // byte offset to start of HEAP
  char  format;		      // data format character (one of: XLABIJEDCM)
  char  mode;		      // access data pointer type (one of P or Q)
} VarLengthColumn;

# ifndef PROTO
# define PROTO(A) A
# endif

char   *gfits_version                  PROTO((void));

/******************************* Header functions *************/

char   *gfits_header_field             PROTO((Header *header, char *field, int N)); 
char   *gfits_header_lineno            PROTO((Header *header, off_t N)); 
char   *gfits_keyword_end              PROTO((char *line));
int     gfits_copy_header              PROTO((Header *in, Header *out)); 
int     gfits_create_header            PROTO((Header *header)); 
int     gfits_delete                   PROTO((Header *header, char *field, int N)); 
int     gfits_fread_Xheader            PROTO((FILE *f, Header *header, int N));
int     gfits_fread_header             PROTO((FILE *f, Header *header));
void    gfits_free_header              PROTO((Header *header)); 
int     gfits_fwrite_header            PROTO((FILE *f, Header *header)); 
int     gfits_get_unsign_mode          PROTO((void));
int     gfits_init_header              PROTO((Header *header));
int     gfits_load_header              PROTO((FILE *f, Header *header));
int     gfits_modify                   PROTO((Header *header, char *field, char *mode, int N,...)) OHANA_FORMAT(printf, 3, 5); 
int     gfits_print                    PROTO((Header *header, char *field, char *mode, int N,...)) OHANA_FORMAT(printf, 3, 5); 
int     gfits_modify_alt               PROTO((Header *header, char *field, char *mode, int N,...)); 
int     gfits_print_alt                PROTO((Header *header, char *field, char *mode, int N,...)); 
int     gfits_read_Xheader             PROTO((char *filename, Header *header, int N));
int     gfits_read_header              PROTO((char *filename, Header *header));
int     gfits_save_header              PROTO((FILE *f, Header *header));
int     gfits_scan                     PROTO((Header *header, char *field, char *mode, int N,...)) OHANA_FORMAT(scanf, 3, 5);
int     gfits_scan_alt                 PROTO((Header *header, char *field, char *mode, int N,...));
int     gfits_set_unsign_mode          PROTO((int mode));
int     gfits_stripwhite               PROTO((char *string));
int     gfits_vscan                    PROTO((Header *header, char *field, char *mode, int N, va_list argp));
int     gfits_vscan_alt                PROTO((Header *header, char *field, char *mode, int N, va_list argp));
int     gfits_write_header             PROTO((char *filename, Header *header)); 
off_t   gfits_data_size                PROTO((Header *header));
off_t   gfits_data_min_size            PROTO((Header *header));
int 	gfits_extended_to_primary      PROTO((Header *header, int simple, char *comment));
int 	gfits_primary_to_extended      PROTO((Header *header, char *exttype, char *comment));
int 	gfits_modify_extended          PROTO((Header *header, char *exttype, char *comment));
char   *gfits_keyword_start 	       PROTO((char *line));
char   *gfits_keyword_end   	       PROTO((char *line));
char   *gfits_hierarch_keyword_start   PROTO((char *line, char *field));
char   *gfits_hierarch_keyword_end     PROTO((char *line, char *field));
void    gfits_pad_ending               PROTO((char *line, char value, int Nbyte));
int     gfits_vscan_hierarch           PROTO((Header *header, char *field, char *mode, int N, va_list argp));
char   *gfits_header_hierarch_field    PROTO((Header *header, char *field, int N));

/******************************* Matrix functions *************/

void   	gfits_add_matrix_value         PROTO((Matrix *matrix, off_t x, off_t y, double value)); 
int    	gfits_convert_format           PROTO((Header *header, Matrix *matrix, int outBitpix, double outScale, double outZero, int inBlank, int outUnsign));
int     gfits_copy_matrix              PROTO((Matrix *in, Matrix *out)); 
int     gfits_create_matrix            PROTO((Header *header, Matrix *matrix)); 
int    	gfits_divide_matrix            PROTO((Matrix *M1, Matrix *M2, Matrix *M3)); 
int    	gfits_fread_matrix             PROTO((FILE *f, Matrix *matrix, Header *header));
int    	gfits_fread_matrix_segment     PROTO((FILE *f, Matrix *matrix, Header *header, char *region));
void    gfits_free_matrix              PROTO((Matrix *matrix)); 
int     gfits_fwrite_matrix            PROTO((FILE *f, Matrix *matrix));      
double  gfits_get_matrix_value         PROTO((Matrix *matrix, off_t x, off_t y)); 
void   	gfits_insert_matrix            PROTO((Matrix *matrix, Matrix *array, off_t x, off_t y)); 
int    	gfits_load_matrix              PROTO((FILE *f, Matrix *matrix, Header *header));
int    	gfits_multiply_matrix          PROTO((Matrix *M1, Matrix *M2, Matrix *M3)); 
int     gfits_read_matrix              PROTO((char *filename, Matrix *matrix));      
int    	gfits_read_matrix_segment      PROTO((char *filename, Matrix *matrix, char *region));
int     gfits_read_portion             PROTO((char *filename, Matrix *matrix, off_t Nskip, off_t Npix));
void   	gfits_set_matrix_value         PROTO((Matrix *matrix, off_t x, off_t y, double value)); 
int     gfits_write_matrix             PROTO((char *filename, Matrix *matrix)); 
int     gfits_uncompress_image 	       PROTO((Header *header, Matrix *matrix, FTable *ftable));
int     gfits_uncompress_data  	       PROTO((char *zdata, int Nzdata, char *cmptype, char **optname, char **optvalue, int Nopt, char *outdata, int *Nout, int out_pixsize));
int     gfits_distribute_data  	       PROTO((Matrix *matrix, int bitpix, char *data, int Ndata, int *otile, int oblank, int *ztile, int zblank, float zscale, float zzero));
int     gfits_byteswap_zdata   	       PROTO((char *zdata, int Nzdata, int bitpix));
int     gfits_extension_is_compressed  PROTO((Header *header));
off_t   gfits_tile_size                PROTO((Matrix *matrix, int *otile, int *ztile));
int     gfits_uncompressed_data_pixsize PROTO((char *cmptype, int out_bitpix, char **optname, char **optvalue, int Noptions));
int     gfits_vartable_heap_pixsize    PROTO((char format));

/******************************* Table functions *************/

char   *gfits_table_print              PROTO((FTable *ftable,...));
int     gfits_add_rows                 PROTO((FTable *ftable, char *data, off_t Nrow, off_t Nbytes));
int     gfits_bintable_format          PROTO((char *format, char *type, int *Nval, int *Nbytes));
int     gfits_create_table             PROTO((Header *header, FTable *ftable));
int     gfits_create_table_header      PROTO((Header *header, char *type, char *extname));
int     gfits_define_bintable_column   PROTO((Header *header, char *format, char *label, char *comment, char *unit, double bscale, double bzero));
int     gfits_define_table_column      PROTO((Header *header, char *format, char *label, char *comment, char *unit));
int   	gfits_fread_ftable             PROTO((FILE *f, FTable *ftable, char *extname)); 
int   	gfits_fread_ftable_data        PROTO((FILE *f, FTable *ftable));
int   	gfits_fread_ftable_range       PROTO((FILE *f, FTable *ftable, off_t start, off_t Nrows));
int   	gfits_fread_vtable             PROTO((FILE *f, VTable *vtable, char *extname, off_t Nrow, off_t *row));
int   	gfits_fread_vtable_range       PROTO((FILE *f, VTable *vtable, off_t start, off_t Nrows));
int     gfits_free_table               PROTO((FTable *ftable));
int     gfits_free_vtable              PROTO((VTable *vtable));
int     gfits_fwrite_table             PROTO((FILE *f, FTable *table));
int     gfits_fwrite_vtable            PROTO((FILE *f, VTable *table));
int     gfits_fwrite_ftable_range      PROTO((FILE *f, FTable *table, off_t start, off_t Nrows, off_t Ndisk, off_t Ntotal));
int     gfits_get_bintable_column      PROTO((Header *header, FTable *table, char *label, void **data));
int     gfits_get_bintable_column_type PROTO((Header *header, char *label, char *type, int *Nval));
void   *gfits_get_bintable_column_data PROTO((Header *header, FTable *table, char *label, char *type, off_t *Nrow, int *Ncol));
int     gfits_get_table_column         PROTO((Header *header, FTable *table, char *label, void **data));
int     gfits_get_table_column_type    PROTO((Header *header, char *label, char *type));
int     gfits_read_ftable              PROTO((char *filename, FTable *table, char *extname));
int     gfits_read_table               PROTO((char *filename, FTable *ftable)); 
int     gfits_set_bintable_column      PROTO((Header *header, FTable *table, char *label, void *data, off_t Nrow));
int     gfits_set_table_column         PROTO((Header *header, FTable *table, char *label, void *data, off_t Nrow));
int     gfits_table_column             PROTO((FTable *ftable, char *field, char *mode,...)) OHANA_FORMAT(printf, 3, 4);
int     gfits_table_format             PROTO((char *format, char *type, int *Nval, int *Nbytes));
int     gfits_table_scale_data         PROTO((FTable *ftable));
int     gfits_table_scale_storage      PROTO((FTable *ftable));
int     gfits_table_to_vtable          PROTO((FTable *ftable, VTable *vtable, off_t start, off_t Nkeep));
int     gfits_vadd_rows                PROTO((VTable *vtable, char *data, off_t Nrow, off_t Nbytes));
int     gfits_vtable_from_ftable       PROTO((FTable *ftable, VTable *vtable, off_t *row, off_t Nrow));
int     gfits_write_table              PROTO((char *filename, FTable *ftable)); 

int     gfits_create_Theader           PROTO((Header *header, char *type));
int     gfits_fread_Theader            PROTO((FILE *f, Header *header));
int     gfits_fwrite_Theader           PROTO((FILE *f, Header *header));
int     gfits_load_Theader             PROTO((FILE *f, Header *header));
int     gfits_read_Theader             PROTO((char *filename, Header *header));     
int     gfits_write_Theader            PROTO((char *filename, Header *header));

int     gfits_varlength_column_define  PROTO((FTable *ftable, VarLengthColumn *def, int column));
void   *gfits_varlength_column_pointer PROTO((FTable *ftable, VarLengthColumn *column, off_t row, off_t *length));

#endif /* FITSIO */
