/*****************************************************************************
******************************************************************************
**<AUTO>
**
** FILE:	fieldFile.c
**
**<HTML>
**	This file contains C functions to write tsField files.
**</HTML>
**</AUTO>
**
**
** ENVIRONMENT:
**	ANSI C.
**
******************************************************************************
******************************************************************************
*/
#include <string.h>
#include <dervish.h>

// Define all fields in the tsField TBLCOL
#define N_TBL_FIELDS 98  /* Number of FITS fields in tsField file */
#define N_TBL_FILTERS 5  /* Number of camera filters */
#define N_MAX_PROFILES 15 /* Maximum number of profile bins for each object */

typedef struct taField
{
  char *name;
  int dimCnt;
  int dim[2];
  char *type;
  char *units;
} TA_FIELD;

static TA_FIELD fields[N_TBL_FIELDS] = {
  {"field", 0, {0, 0}, "INT", ""},
  {"quality", 0, {0, 0}, "INT", ""},
  {"a", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"b", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"c", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"d", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"e", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"f", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"dRow0", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"dRow1", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"dRow2", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"dRow3", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"dCol0", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"dCol1", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"dCol2", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"dCol3", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"csRow", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"csCol", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"ccRow", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"ccCol", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"riCut", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"mjd", 1, {N_TBL_FILTERS, 0}, "DOUBLE", "MJD(TAI)"},
  {"airmass", 1, {N_TBL_FILTERS, 0}, "DOUBLE", ""},
  {"muErr", 1, {N_TBL_FILTERS, 0}, "DOUBLE", "arcsec"},
  {"nuErr", 1, {N_TBL_FILTERS, 0}, "DOUBLE", "arcsec"},
  {"seqId", 0, {0, 0}, "INT", ""},
  {"numStars", 1, {N_TBL_FILTERS, 0}, "INT", ""},
  {"aa", 1, {N_TBL_FILTERS, 0}, "FLOAT", "mag"},
  {"aaErr", 1, {N_TBL_FILTERS, 0}, "FLOAT", "mag"},
  {"bb", 1, {N_TBL_FILTERS, 0}, "FLOAT", "mag"},
  {"bbErr", 1, {N_TBL_FILTERS, 0}, "FLOAT", "mag"},
  {"cc", 1, {N_TBL_FILTERS, 0}, "FLOAT", "mag"},
  {"ccErr", 1, {N_TBL_FILTERS, 0}, "FLOAT", "mag"},
  {"kk", 1, {N_TBL_FILTERS, 0}, "FLOAT", "mag"},
  {"kkErr", 1, {N_TBL_FILTERS, 0}, "FLOAT", "mag"},
  {"frames_status", 0, {0, 0}, "INT", ""},
  {"rowOffset", 1, {N_TBL_FILTERS, 0}, "FLOAT", "pixels"},
  {"colOffset", 1, {N_TBL_FILTERS, 0}, "FLOAT", "pixels"},
  {"nObjects", 0, {0, 0}, "INT", ""},
  {"nChild", 0, {0, 0}, "INT", ""},
  {"nStars", 0, {0, 0}, "INT", ""},
  {"nGals", 0, {0, 0}, "INT", ""},
  {"saturation_level", 1, {N_TBL_FILTERS, 0}, "INT", ""},
  {"neff_psf", 1, {N_TBL_FILTERS, 0}, "FLOAT", "pixels"},
  {"sky_psp", 1, {N_TBL_FILTERS, 0}, "FLOAT", "maggies/arcsec^2"},
  {"sky_frames", 1, {N_TBL_FILTERS, 0}, "FLOAT", "maggies/arcsec^2"},
  {"sky_frames_sub", 1, {N_TBL_FILTERS, 0}, "FLOAT", "maggies/arcsec^2"},
  {"sigPix", 1, {N_TBL_FILTERS, 0}, "FLOAT", "maggies/arcsec^2"},
  {"deV_ap_correction", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"deV_ap_correctionErr", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"exp_ap_correction", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"exp_ap_correctionErr", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"deV_model_ap_correction", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"deV_model_ap_correctionErr", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"exp_model_ap_correction", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"exp_model_ap_correctionErr", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"nCR", 1, {N_TBL_FILTERS, 0}, "INT", ""},
  {"nBrightObj", 1, {N_TBL_FILTERS, 0}, "INT", ""},
  {"nFaintObj", 1, {N_TBL_FILTERS, 0}, "INT", ""},
  {"median_fiberColor", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"median_psfColor", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"q", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"u", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"psp_status", 0, {0, 0}, "INT", ""},
  {"status", 1, {N_TBL_FILTERS, 0}, "INT", ""},
  {"sky", 1, {N_TBL_FILTERS, 0}, "FLOAT", "maggies/arcsec^2"},
  {"skySig", 1, {N_TBL_FILTERS, 0}, "FLOAT", "maggies/arcsec^2"},
  {"skyErr", 1, {N_TBL_FILTERS, 0}, "FLOAT", "maggies/arcsec^2"},
  {"skySlope", 1, {N_TBL_FILTERS, 0}, "FLOAT", "maggies/arcsec^2/field"},
  {"lbias", 1, {N_TBL_FILTERS, 0}, "FLOAT", "ADUs x DSCALE"},
  {"rbias", 1, {N_TBL_FILTERS, 0}, "FLOAT", "ADUs x DSCALE"},
  {"psf_nstar", 1, {N_TBL_FILTERS, 0}, "INT", ""},
  {"psf_ap_correctionErr", 1, {N_TBL_FILTERS, 0}, "FLOAT", "mags"},
  {"psf_sigma1", 1, {N_TBL_FILTERS, 0}, "FLOAT", "arcsec"},
  {"psf_sigma2", 1, {N_TBL_FILTERS, 0}, "FLOAT", "arcsec"},
  {"psf_b", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"psf_p0", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"psf_beta", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"psf_sigmap", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"psf_width", 1, {N_TBL_FILTERS, 0}, "FLOAT", "arcsec"},
  {"psf_psfCounts", 1, {N_TBL_FILTERS, 0}, "FLOAT", "counts"},
  {"psf_sigma1_2G", 1, {N_TBL_FILTERS, 0}, "FLOAT", "pixels"},
  {"psf_sigma2_2G", 1, {N_TBL_FILTERS, 0}, "FLOAT", "pixels"},
  {"psf_b_2G", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"psfCounts", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"prof_nprof", 1, {N_TBL_FILTERS, 0}, "INT", ""},
  {"prof_mean", 2, {N_TBL_FILTERS, N_MAX_PROFILES}, "FLOAT", ""},
  {"prof_med", 2, {N_TBL_FILTERS, N_MAX_PROFILES}, "FLOAT", ""},
  {"prof_sig", 2, {N_TBL_FILTERS, N_MAX_PROFILES}, "FLOAT", ""},
  {"gain", 1, {N_TBL_FILTERS, 0}, "FLOAT", "electrons/DN"},
  {"dark_variance", 1, {N_TBL_FILTERS, 0}, "FLOAT", ""},
  {"scanlineArea", 0, {0, 0}, "FLOAT", "deg^2"},
  {"stripeArea", 0, {0, 0}, "FLOAT", "deg^2"},
  {"culled", 0, {0, 0}, "INT", ""},
  {"badMask", 0, {0, 0}, "INT", ""},
  {"acceptableMask", 0, {0, 0}, "INT", ""},
  {"goodMask", 0, {0, 0}, "INT", ""},
  {"holeMask", 0, {0, 0}, "INT", ""}
};

enum fieldNames
{
  FIELD,
  QUALITY,
  A,
  B,
  C,
  D,
  E,
  F,
  DROW0,
  DROW1,
  DROW2,
  DROW3,
  DCOL0,
  DCOL1,
  DCOL2,
  DCOL3,
  CSROW,
  CSCOL,
  CCROW,
  CCCOL,
  RICUT,
  MJD,
  AIRMASS,
  MUERR,
  NUERR,
  SEQID,
  NUMSTARS,
  AA,
  AAERR,
  BB,
  BBERR,
  CC,
  CCERR,
  KK,
  KKERR,
  FRAMES_STATUS,
  ROWOFFSET,
  COLOFFSET,
  NOBJECTS,
  NCHILD,
  NSTARS,
  NGALS,
  SATURATION_LEVEL,
  NEFF_PSF,
  SKY_PSP,
  SKY_FRAMES,
  SKY_FRAMES_SUB,
  SIGPIX,
  DEV_AP_CORRECTION,
  DEV_AP_CORRECTIONERR,
  EXP_AP_CORRECTION,
  EXP_AP_CORRECTIONERR,
  DEV_MODEL_AP_CORRECTION,
  DEV_MODEL_AP_CORRECTIONERR,
  EXP_MODEL_AP_CORRECTION,
  EXP_MODEL_AP_CORRECTIONERR,
  NCR,
  NBRIGHTOBJ,
  NFAINTOBJ,
  MEDIAN_FIBERCOLOR,
  MEDIAN_PSFCOLOR,
  Q,
  U,
  PSP_STATUS,
  STATUS,
  SKY,
  SKYSIG,
  SKYERR,
  SKYSLOPE,
  LBIAS,
  RBIAS,
  PSF_NSTAR,
  PSF_AP_CORRECTIONERR,
  PSF_SIGMA1,
  PSF_SIGMA2,
  PSF_B,
  PSF_P0,
  PSF_BETA,
  PSF_SIGMAP,
  PSF_WIDTH,
  PSF_PSFCOUNTS,
  PSF_SIGMA1_2G,
  PSF_SIGMA2_2G,
  PSF_B_2G,
  PSFCOUNTS,
  PROF_NPROF,
  PROF_MEAN,
  PROF_MED,
  PROF_SIG,
  GAIN,
  DARK_VARIANCE,
  SCANLINE_AREA,
  STRIPE_AREA,
  CULLED,
  BAD_MASK,
  ACCEPTABLE_MASK,
  GOOD_MASK,
  HOLE_MASK
};

/*****************************************************************************
******************************************************************************
**<AUTO EXTRACT>
**
** ROUTINE:	taFieldTblColInit
**
**<HTML>
**	Create a TBLCOL for a "tsField" file, containing all information
**	for a single field that is to be exported to the SX.  The number of
**	rows in the TBLCOL is specified by the argument "nRows".
**	Returns a pointer to the newly created TBLCOL, or NULL on error.
**</HTML>
**</AUTO>
******************************************************************************
******************************************************************************
*/
TBLCOL*
taFieldTblColInit(int nRows  /* number of rows to allocate */)
{
  int fldIdx, dimIdx;
  TBLCOL *tblCol = NULL;
  ARRAY* array[N_TBL_FIELDS];

  // Create the TBLCOL
  if (shTblColCreate(nRows, N_TBL_FIELDS, 0, &tblCol) != SH_SUCCESS)
    {
      shErrStackPush("taFieldTblColInit: couldn't create TBLCOL");
      return NULL;
    }

  // Set up each field in the TBLCOL, saving its array pointer.
  for (fldIdx = 0; fldIdx < N_TBL_FIELDS; fldIdx++)
    {
      // Locate the field
      if (shTblFldLoc(tblCol, fldIdx, NULL, 0, SH_CASE_INSENSITIVE,
		      &(array[fldIdx]), NULL, NULL) != SH_SUCCESS)
	{
	  shErrStackPush("taFieldTblColInit: couldn't create TBLFLD");
	  shTblcolDel(tblCol);
	  return NULL;
	}

      // Set the array dimensions
      for (dimIdx = 0; dimIdx < fields[fldIdx].dimCnt; dimIdx++)
	{
	  array[fldIdx]->dim[array[fldIdx]->dimCnt++] =
	    fields[fldIdx].dim[dimIdx];
	}

      // Allocate storage for the array
      if (shArrayDataAlloc(array[fldIdx],fields[fldIdx].type) != SH_SUCCESS)
	{
	  shErrStackPush("taFieldTblColInit: couldn't allocate storage");
	  shTblcolDel(tblCol);
	  return NULL;
	}
      if (shTblTBLFLDsetWithAscii(array[fldIdx], SH_TBL_TTYPE,
				  fields[fldIdx].name, (TBLFLD**) 0)
	  != SH_SUCCESS)
	{
	  shErrStackPush("taFieldTblColInit: couldn't set field name");
	  shTblcolDel(tblCol);
	  return NULL;
	}
      if (strlen(fields[fldIdx].units) > 0)
	if (shTblTBLFLDsetWithAscii(array[fldIdx], SH_TBL_TUNIT,
				    fields[fldIdx].units, (TBLFLD**) 0)
	    != SH_SUCCESS)
	  {
	    shErrStackPush("taFieldTblColInit: couldn't set units");
	    shTblcolDel(tblCol);
	    return NULL;
	  }
    }

  // Return pointer to the TBLCOL
  return tblCol;
}
