/*****************************************************************************
******************************************************************************
**<AUTO>
**
** FILE:	tclCatalogs.c
**
**<HTML>
**	This file contains TCL functions read an delete FIRST and ROSAT
**	catalogs.
**</HTML>
**</AUTO>
**
**
** ENVIRONMENT:
**	ANSI C.
**
******************************************************************************
******************************************************************************
*/

#include "taCatalogs.h"
#include "taCalibObj.h"

static int versionStringLength = 80;   /* Maximum length of version strings */

#define N_ROSAT_FIELDS 14
static char *rosatFieldName[N_ROSAT_FIELDS] = {
  "id",
  "lambda",
  "eta",
  "posErr",
  "cps",
  "cpserr",
  "hr1",
  "hr1Err",
  "hr2",
  "hr2Err",
  "extent",
  "extentLike",
  "detectLike",
  "exposure"
};
enum rosatFieldId {
  ROSAT_ID,
  ROSAT_LAMBDA,
  ROSAT_ETA,
  POSERR,
  CPS,
  CPSERR,
  HR1,
  HR1ERR,
  HR2,
  HR2ERR,
  EXT,
  EXTLIKE,
  DETECTLIKE,
  EXPOSURE
};

#define N_FIRST_FIELDS 10
static char *firstFieldName[N_FIRST_FIELDS] = {
  "id",
  "lambda",
  "eta",
  "wflag",
  "fpeak",
  "fint",
  "rms",
  "maj",
  "min",
  "pa"
};
enum firstFieldId {
  FIRST_ID,
  FIRST_LAMBDA,
  FIRST_ETA,
  WFLAG,
  FPEAK,
  FINT,
  RMS,
  MAJ,
  MIN,
  PA
};

#define N_USNO_FIELDS 2
static char *usnoFieldName[N_USNO_FIELDS] = {
  "field",
  "epoch"
};
enum usnoFieldId {
  USNO_FIELD,
  USNO_EPOCH
};


/********************************************************************/
/* qsort helper function. Final list is ordered from smallest to largest */
static int rosatCmpLambda (const void *d1, const void *d2)
{
  TA_ROSAT *f1, *f2;
  f1 = (TA_ROSAT *)d1;
  f2 = (TA_ROSAT *)d2;
  if (f1->lambda < f2->lambda) return -1;
  if (f1->lambda > f2->lambda) return 1;
  return 0;
}

/********************************************************************/
/* qsort helper function. Final list is ordered from smallest to largest */
static int firstCmpLambda (const void *d1, const void *d2)
{
  TA_FIRST *f1, *f2;
  f1 = (TA_FIRST *)d1;
  f2 = (TA_FIRST *)d2;
  if (f1->lambda < f2->lambda) return -1;
  if (f1->lambda > f2->lambda) return 1;
  return 0;
}


/********************************************************************/
/* qsort helper function. Final list is ordered from smallest to largest */
static int usnoCmpLambda (const void *d1, const void *d2)
{
  TA_USNO *f1, *f2;
  f1 = (TA_USNO *)d1;
  f2 = (TA_USNO *)d2;
  if (f1->lambda < f2->lambda) return -1;
  if (f1->lambda > f2->lambda) return 1;
  return 0;
}


/*============================================================================
**<AUTO EXTRACT>
**
** TCL VERB: rosatRead
**
**<HTML>
**	Read a ROSAT catalog into a TA_ROSAT_CATALOG structure.  Returns a
**	handle to the new catalog structure.
**	The catalog will be sorted by increasing lambda.
**</HTML>
**</AUTO>
**============================================================================
*/
static char rosatReadCmd[] = "rosatRead";
static int rosatReadFlg = FTCL_ARGV_NO_LEFTOVERS;
static ftclArgvInfo rosatReadTbl[] = {
   {NULL, FTCL_ARGV_HELP, NULL, NULL,
    "Read a ROSAT catalog\n"},
   {"[file]", FTCL_ARGV_STRING, "/data/dp1.16/data/rosat/rosat.fit",
    NULL, "Rosat catalog file"},
   {NULL, FTCL_ARGV_END, NULL, NULL, NULL}
};

static int
tclRosatRead (ClientData clientData,
	       Tcl_Interp *interp,
	       int argc,
	       char **argv)
{
  char *fileName = NULL;
  int status;

  HANDLE handle;
  TBLCOL *tblCol;
  int fldIdx;
  ARRAY* array[N_ROSAT_FIELDS];
  TA_ROSAT_CATALOG *catalog;
  int k;
  char handleName[HANDLE_NAMELEN];
  HDR *hdr;

  /* Parse the arguments */
  rosatReadTbl[1].dst = &fileName;
  if ((status = shTclParseArgv(interp, &argc, argv, rosatReadTbl,
			       rosatReadFlg, rosatReadCmd))
      != FTCL_ARGV_SUCCESS)
    return status;

  /* Create the TA_ROSAT_CATALOG */
  catalog = shMalloc(sizeof(TA_ROSAT_CATALOG));
  catalog->newSearch = 1;

  /* Get the catalog version from the PDU */
  hdr = shHdrNew();
  if (shHdrReadAsFits(hdr, (char *)fileName, DEF_NONE, NULL, 0) != SH_SUCCESS)
    {
      shHdrDel(hdr);
      shFree(catalog);
      Tcl_AppendResult(interp, rosatReadCmd,
		       ": couldn't read the PDU", NULL);
      return TCL_ERROR;
    }
  catalog->version = shMalloc(versionStringLength * sizeof(char));
  if (shHdrGetAscii(hdr, "VERSION", catalog->version) != SH_SUCCESS)
    {
      shHdrDel(hdr);
      shFree(catalog->version);
      shFree(catalog);
      Tcl_AppendResult(interp, rosatReadCmd,
		       ": couldn't get VERSION keyword from the PDU", NULL);
      return TCL_ERROR;
    }
  shHdrDel(hdr);

  /* Read the file into a TBLCOL */
  tblCol = shTblcolNew();
  handle.ptr = (void *) tblCol;
  handle.type = shTypeGetFromName("TBLCOL");
  if (shFitsRead(&handle, (char *)fileName, DEF_NONE, f_hduBINTABLE, 1,
		 NULL, NULL, 0, 0) != SH_SUCCESS)
    {
      shTblcolDel(tblCol);
      shFree(catalog->version);
      shFree(catalog);
      Tcl_AppendResult(interp, rosatReadCmd,
		       ": couldn't read FITS file", NULL);
      return TCL_ERROR;
    }

  /* Locate each field in the TBLCOL, saving its array pointer. */
  for (fldIdx = 0; fldIdx < N_ROSAT_FIELDS; fldIdx++)
    {
      /* Locate the field */
      if (shTblFldLoc(tblCol, -1, rosatFieldName[fldIdx], 0,
		      SH_CASE_INSENSITIVE, &(array[fldIdx]), NULL, NULL)
	  != SH_SUCCESS)
	{
	  shTblcolDel(tblCol);
	  shFree(catalog->version);
	  shFree(catalog);
	  Tcl_AppendResult(interp, rosatReadCmd,
			   ": couldn't locate field ", rosatFieldName[fldIdx],
			   " in FITS file", NULL);
	  return TCL_ERROR;
	}
    }

  /* For each object ... */
  catalog->nObj = tblCol->rowCnt;
  catalog->obj = shMalloc(tblCol->rowCnt * sizeof(TA_ROSAT));
  for (k = 0; k < tblCol->rowCnt; k++)
    {
      /* Copy its contents from the TBLCOL to the array */
      catalog->obj[k].id      = (((int*)(array[ROSAT_ID]->arrayPtr))[k]);
      catalog->obj[k].lambda  =(((double*)(array[ROSAT_LAMBDA]->arrayPtr))[k]);
      catalog->obj[k].eta     = (((double*)(array[ROSAT_ETA]->arrayPtr))[k]);
      catalog->obj[k].posErr  = (((float*)(array[POSERR]->arrayPtr))[k]);
      catalog->obj[k].cps.val = (((float*)(array[CPS]->arrayPtr))[k]);
      catalog->obj[k].cps.err = (((float*)(array[CPSERR]->arrayPtr))[k]);
      catalog->obj[k].hr1.val = (((float*)(array[HR1]->arrayPtr))[k]);
      catalog->obj[k].hr1.err = (((float*)(array[HR1ERR]->arrayPtr))[k]);
      catalog->obj[k].hr2.val = (((float*)(array[HR2]->arrayPtr))[k]);
      catalog->obj[k].hr2.err = (((float*)(array[HR2ERR]->arrayPtr))[k]);
      catalog->obj[k].ext     = (((float*)(array[EXT]->arrayPtr))[k]);
      catalog->obj[k].extLike = (((float*)(array[EXTLIKE]->arrayPtr))[k]);
      catalog->obj[k].detectLike =(((float*)(array[DETECTLIKE]->arrayPtr))[k]);
      catalog->obj[k].exposure = (((float*)(array[EXPOSURE]->arrayPtr))[k]);
    }
  shTblcolDel(tblCol);

  /* Sort it by increasing lambda */
  qsort((void *)(catalog->obj), catalog->nObj, sizeof(TA_ROSAT),
	rosatCmpLambda);

  /* Return a handle to the TA_ROSAT_CATALOG */
  if (shTclHandleNew(interp, handleName, "TA_ROSAT_CATALOG", (void *)catalog)
      != TCL_OK)
    {
      shFree(catalog->version);
      shFree(catalog->obj);
      shFree(catalog);
      Tcl_AppendResult(interp, rosatReadCmd,
		       ": error allocating TCL handle", NULL);
      return TCL_ERROR;
    }
  Tcl_SetResult(interp, handleName, TCL_VOLATILE);
  return TCL_OK;
}


/*============================================================================
**<AUTO EXTRACT>
**
** TCL VERB: rosatDel
**<HTML>
**	Delete a TA_ROSAT_CATALOG structure.
**</HTML>
**</AUTO>
**============================================================================
*/
static char rosatDelCmd[] = "rosatDel";
static int rosatDelFlg = FTCL_ARGV_NO_LEFTOVERS;
static ftclArgvInfo rosatDelTbl[] = {
   {NULL, FTCL_ARGV_HELP, NULL, NULL, "Delete a TA_ROSAT_CATALOG structure\n"},
   {"<handle>", FTCL_ARGV_STRING, NULL, NULL, "Structure to delete"},
   {NULL, FTCL_ARGV_END, NULL, NULL, NULL}
};

static int
tclRosatDel (ClientData clientData,
		    Tcl_Interp *interp,
		    int argc,
		    char **argv)
{
  char *handle = NULL;
  TA_ROSAT_CATALOG *catalog = NULL;
  int status;

  /* Parse the arguments */
  rosatDelTbl[1].dst = &handle;
  if ((status = shTclParseArgv(interp, &argc, argv, rosatDelTbl,
			       rosatDelFlg, rosatDelCmd))
      != FTCL_ARGV_SUCCESS)
    return status;
   
  /* Get handle to the catalog */
  if (shTclAddrGetFromName (interp, handle, (void **)&catalog,
			    "TA_ROSAT_CATALOG") != TCL_OK)
    {
      Tcl_AppendResult(interp, rosatDelCmd,
		       ": error getting handle to catalog", NULL);
      return TCL_ERROR;
    }

  /* Delete it and its handle */
  shFree(catalog->version);
  shFree(catalog->obj);
  shFree(catalog);
  p_shTclHandleDel(interp, handle);

  /* Return */
  Tcl_SetResult(interp,"",TCL_STATIC);
  return(TCL_OK);
}


/*============================================================================
**<AUTO EXTRACT>
**
** TCL VERB: firstRead
**
**<HTML>
**	Read a FIRST catalog into a TA_FIRST_CATALOG structure.  Returns a
**	handle to the new catalog structure.
**	The catalog will be sorted by increasing lambda.
** 
**      Fixed some bugs here.  (GTR, 10/05/00)
**
**</HTML>
**</AUTO>
**============================================================================
*/
static char firstReadCmd[] = "firstRead";
static int firstReadFlg = FTCL_ARGV_NO_LEFTOVERS;
static ftclArgvInfo firstReadTbl[] = {
   {NULL, FTCL_ARGV_HELP, NULL, NULL,
    "Read a FIRST catalog\n"},
   {"[file]", FTCL_ARGV_STRING, "/data/dp1.16/data/first/first_south.fit",
    NULL, "First catalog file"},
   {NULL, FTCL_ARGV_END, NULL, NULL, NULL}
};

static int
tclFirstRead (ClientData clientData,
	       Tcl_Interp *interp,
	       int argc,
	       char **argv)
{
  char *fileName = NULL;
  int status;

  HANDLE handle;
  TBLCOL *tblCol;
  int fldIdx;
  ARRAY* array[N_FIRST_FIELDS];
  TA_FIRST_CATALOG *catalog;
  int k;
  char handleName[HANDLE_NAMELEN];
  HDR *hdr;

  /* Parse the arguments */
  firstReadTbl[1].dst = &fileName;
  if ((status = shTclParseArgv(interp, &argc, argv, firstReadTbl,
			       firstReadFlg, firstReadCmd))
      != FTCL_ARGV_SUCCESS)
    return status;

  /* Create the TA_FIRST_CATALOG */
  catalog = shMalloc(sizeof(TA_FIRST_CATALOG));
  catalog->newSearch = 1;

  /* Get the catalog version from the PDU */
  hdr = shHdrNew();
  if (shHdrReadAsFits(hdr, (char *)fileName, DEF_NONE, NULL, 0) != SH_SUCCESS)
    {
      shHdrDel(hdr);
      shFree(catalog);
      Tcl_AppendResult(interp, firstReadCmd,
		       ": couldn't read the PDU", NULL);
      return TCL_ERROR;
    }
  catalog->version = shMalloc(versionStringLength * sizeof(char));
  if (shHdrGetAscii(hdr, "VERSION", catalog->version) != SH_SUCCESS)
    {
      shHdrDel(hdr);
      shFree(catalog->version);
      shFree(catalog);
      Tcl_AppendResult(interp, firstReadCmd,
		       ": couldn't get VERSION keyword from the PDU", NULL);
      return TCL_ERROR;
    }
  shHdrDel(hdr);

  /* Read the file into a TBLCOL */
  tblCol = shTblcolNew();
  handle.ptr = (void *) tblCol;
  handle.type = shTypeGetFromName("TBLCOL");
  if (shFitsRead(&handle, (char *)fileName, DEF_NONE, f_hduBINTABLE, 1,
		 NULL, NULL, 0, 0) != SH_SUCCESS)
    {
      shTblcolDel(tblCol);
      shFree(catalog->version);
      shFree(catalog); 
      Tcl_AppendResult(interp, firstReadCmd,
		       ": couldn't read FITS file", NULL);
      return TCL_ERROR;
    }

  /* Locate each field in the TBLCOL, saving its array pointer. */
  for (fldIdx = 0; fldIdx < N_FIRST_FIELDS; fldIdx++)
    {
      /* Locate the field */
      if (shTblFldLoc(tblCol, -1, firstFieldName[fldIdx], 0,
		      SH_CASE_INSENSITIVE, &(array[fldIdx]), NULL, NULL)
	  != SH_SUCCESS)
	{
	  shTblcolDel(tblCol);
	  shFree(catalog->version);
	  shFree(catalog);
	  Tcl_AppendResult(interp, firstReadCmd,
			 ": couldn't locate field in FITS file", NULL);
	  return TCL_ERROR;
	}
    }

  /* For each object ... */
  catalog->nObj = tblCol->rowCnt;
  catalog->obj = shMalloc(tblCol->rowCnt * sizeof(TA_FIRST));
  for (k = 0; k < tblCol->rowCnt; k++)
    {
      /* Copy its contents from the TBLCOL to the array */
      catalog->obj[k].id    = (((int*)(array[FIRST_ID]->arrayPtr))[k]);
      catalog->obj[k].lambda= (((double*)(array[FIRST_LAMBDA]->arrayPtr))[k]);
      catalog->obj[k].eta   = (((double*)(array[FIRST_ETA]->arrayPtr))[k]);
      catalog->obj[k].wflag = (((int*)(array[WFLAG]->arrayPtr))[k]);
      catalog->obj[k].fpeak = (((float*)(array[FPEAK]->arrayPtr))[k]);
      catalog->obj[k].fint  = (((float*)(array[FINT]->arrayPtr))[k]);
      catalog->obj[k].rms   = (((float*)(array[RMS]->arrayPtr))[k]);
      catalog->obj[k].maj   = (((float*)(array[MAJ]->arrayPtr))[k]);
      catalog->obj[k].min   = (((float*)(array[MIN]->arrayPtr))[k]);
      catalog->obj[k].pa    = (((float*)(array[PA]->arrayPtr))[k]);
    }
  shTblcolDel(tblCol);

  /* Sort it by increasing lambda */
  qsort((void *)(catalog->obj), catalog->nObj, sizeof(TA_FIRST),
	firstCmpLambda);

  /* Return a handle to the TA_FIRST_CATALOG */
  if (shTclHandleNew(interp, handleName, "TA_FIRST_CATALOG", (void *)catalog)
      != TCL_OK)
    {
      shFree(catalog->version);
      shFree(catalog->obj);
      shFree(catalog);
      Tcl_AppendResult(interp, firstReadCmd,
		       ": error allocating TCL handle", NULL);
      return TCL_ERROR;
    }
  Tcl_SetResult(interp, handleName, TCL_VOLATILE);
  return TCL_OK;
}


/*============================================================================
**<AUTO EXTRACT>
**
** TCL VERB: firstDel
**<HTML>
**	Delete a TA_FIRST_CATALOG structure.
**</HTML>
**</AUTO>
**============================================================================
*/
static char firstDelCmd[] = "firstDel";
static int firstDelFlg = FTCL_ARGV_NO_LEFTOVERS;
static ftclArgvInfo firstDelTbl[] = {
   {NULL, FTCL_ARGV_HELP, NULL, NULL, "Delete a TA_FIRST_CATALOG structure\n"},
   {"<handle>", FTCL_ARGV_STRING, NULL, NULL, "Structure to delete"},
   {NULL, FTCL_ARGV_END, NULL, NULL, NULL}
};

static int
tclFirstDel (ClientData clientData,
		    Tcl_Interp *interp,
		    int argc,
		    char **argv)
{
  char *handle = NULL;
  TA_FIRST_CATALOG *catalog = NULL;
  int status;

  /* Parse the arguments */
  firstDelTbl[1].dst = &handle;
  if ((status = shTclParseArgv(interp, &argc, argv, firstDelTbl,
			       firstDelFlg, firstDelCmd))
      != FTCL_ARGV_SUCCESS)
    return status;
   
  /* Get handle to the catalog */
  if (shTclAddrGetFromName (interp, handle, (void **)&catalog,
			    "TA_FIRST_CATALOG") != TCL_OK)
    {
      Tcl_AppendResult(interp, firstDelCmd,
		       ": error getting handle to catalog", NULL);
      return TCL_ERROR;
    }

  /* Delete it and its handle */
  shFree(catalog->version);
  shFree(catalog->obj);
  shFree(catalog);
  p_shTclHandleDel(interp, handle);

  /* Return */
  Tcl_SetResult(interp,"",TCL_STATIC);
  return(TCL_OK);
}


/*============================================================================
**<AUTO EXTRACT>
**
** TCL VERB: usnoRead
**
**<HTML>
**	Read a USNO catalog into a TA_USNO_CATALOG structure.
**	Only that portion of the catalog that intersects a scan, as
**	defined	by a strip, 3 degrees wide, along a section of a great circle,
**	will be read in.  Returns a handle to the new catalog structure.
**	The catalog will be sorted by increasing lambda.
**</HTML>
**</AUTO>
**============================================================================
*/
static char usnoReadCmd[] = "usnoRead";
static int usnoReadFlg = FTCL_ARGV_NO_LEFTOVERS;
static ftclArgvInfo usnoReadTbl[] = {
   {NULL, FTCL_ARGV_HELP, NULL, NULL,
    "Read a USNO catalog\n"},
   {"<dir>", FTCL_ARGV_STRING, NULL, NULL, "Directory containing USNO catalog files"},
   {"<node>", FTCL_ARGV_DOUBLE, NULL, NULL, "Ascending node of great circle (degrees)"},
   {"<incl>", FTCL_ARGV_DOUBLE, NULL, NULL, "Inclination of great circle (degrees)"},
   {"<equinox>", FTCL_ARGV_DOUBLE, NULL, NULL, "Equinox of great circle (Julian years)"},
   {"<minMu>", FTCL_ARGV_DOUBLE, NULL, NULL, "Minimum great circle longitude in scan (degrees)"},
   {"<maxMu>", FTCL_ARGV_DOUBLE, NULL, NULL, "Maximum great circle longitude in scan (degrees)"},
   {NULL, FTCL_ARGV_END, NULL, NULL, NULL}
};

static int
tclUsnoRead (ClientData clientData,
	     Tcl_Interp *interp,
	     int argc,
	     char **argv)
{
  char *dirName = NULL;
  double node, incl, equinox, minMu, maxMu;
  int status;

  HANDLE handle;
  TA_USNO_CATALOG *catalog;
  char handleName[HANDLE_NAMELEN];
  char fileName[300];
  HDR *hdr;
  int k;
  TBLCOL *tblCol;
  int fldIdx;
  ARRAY* array[N_USNO_FIELDS];

  /* Parse the arguments */
  usnoReadTbl[1].dst = &dirName;
  usnoReadTbl[2].dst = &node;
  usnoReadTbl[3].dst = &incl;
  usnoReadTbl[4].dst = &equinox;
  usnoReadTbl[5].dst = &minMu;
  usnoReadTbl[6].dst = &maxMu;
  if ((status = shTclParseArgv(interp, &argc, argv, usnoReadTbl,
			       usnoReadFlg, usnoReadCmd))
      != FTCL_ARGV_SUCCESS)
    return status;

  /* Create the TA_USNO_CATALOG */
  catalog = shMalloc(sizeof(TA_USNO_CATALOG));
  catalog->newSearch = 1;

  /* Get the catalog version from the epochs file PDU */
  sprintf(fileName, "%s/epochs.fit", dirName);
  hdr = shHdrNew();
  if (shHdrReadAsFits(hdr, (char *)fileName, DEF_NONE, NULL, 0) != SH_SUCCESS)
    {
      shHdrDel(hdr);
      shFree(catalog);
      Tcl_AppendResult(interp, usnoReadCmd,
		       ": couldn't read the PDU", NULL);
      return TCL_ERROR;
    }
  catalog->version = shMalloc(versionStringLength * sizeof(char));
  if (shHdrGetAscii(hdr, "VERSION", catalog->version) != SH_SUCCESS)
    {
      shHdrDel(hdr);
      shFree(catalog->version);
      shFree(catalog);
      Tcl_AppendResult(interp, usnoReadCmd,
		       ": couldn't get VERSION keyword from the PDU", NULL);
      return TCL_ERROR;
    }
  shHdrDel(hdr);

  /* Read the epochs file into a TBLCOL */
  tblCol = shTblcolNew();
  handle.ptr = (void *) tblCol;
  handle.type = shTypeGetFromName("TBLCOL");
  if (shFitsRead(&handle, (char *)fileName, DEF_NONE, f_hduBINTABLE, 1,
		 NULL, NULL, 0, 0) != SH_SUCCESS)
    {
      shTblcolDel(tblCol);
      shFree(catalog->version);
      shFree(catalog); 
      Tcl_AppendResult(interp, usnoReadCmd,
		       ": couldn't read epochs file", NULL);
      return TCL_ERROR;
    }

  /* Locate each field in the TBLCOL, saving its array pointer. */
  for (fldIdx = 0; fldIdx < N_USNO_FIELDS; fldIdx++)
    {
      /* Locate the field */
      if (shTblFldLoc(tblCol, -1, usnoFieldName[fldIdx], 0,
		      SH_CASE_INSENSITIVE, &(array[fldIdx]), NULL, NULL)
	  != SH_SUCCESS)
	{
	  shTblcolDel(tblCol);
	  shFree(catalog->version);
	  shFree(catalog);
	  Tcl_AppendResult(interp, usnoReadCmd,
			 ": couldn't locate field in epochs file", NULL);
	  return TCL_ERROR;
	}
    }

  /* Set the epoch for each field in the catalog */
  for (k = 0; k < tblCol->rowCnt; k++)
    catalog->epoch[((int*)(array[USNO_FIELD]->arrayPtr))[k]] =
      ((double*)(array[USNO_EPOCH]->arrayPtr))[k];
  shTblcolDel(tblCol);

  /* Read the catalog */
  catalog->obj = NULL;
  catalog->nObj = 0;
  if (taUSNORead(node, incl, equinox, minMu, maxMu, dirName, &(catalog->obj),
		 &(catalog->nObj)) != SH_SUCCESS)
    {
      shFree(catalog->version);
      shFree(catalog);
      shTclInterpAppendWithErrStack(interp);
      return TCL_ERROR;
    }

  /* Sort it by increasing lambda */
  qsort((void *)(catalog->obj), catalog->nObj, sizeof(TA_USNO),
	usnoCmpLambda);

  /* Return a handle to the TA_USNO_CATALOG */
  if (shTclHandleNew(interp, handleName, "TA_USNO_CATALOG", (void *)catalog)
      != TCL_OK)
    {
      shFree(catalog->version);
      shFree(catalog->obj);
      shFree(catalog);
      Tcl_AppendResult(interp, usnoReadCmd,
		       ": error allocating TCL handle", NULL);
      return TCL_ERROR;
    }
  Tcl_SetResult(interp, handleName, TCL_VOLATILE);
  return TCL_OK;
}


/*============================================================================
**<AUTO EXTRACT>
**
** TCL VERB: usnoDel
**<HTML>
**	Delete a TA_USNO_CATALOG structure.
**</HTML>
**</AUTO>
**============================================================================
*/
static char usnoDelCmd[] = "usnoDel";
static int usnoDelFlg = FTCL_ARGV_NO_LEFTOVERS;
static ftclArgvInfo usnoDelTbl[] = {
   {NULL, FTCL_ARGV_HELP, NULL, NULL, "Delete a TA_USNO_CATALOG structure\n"},
   {"<handle>", FTCL_ARGV_STRING, NULL, NULL, "Structure to delete"},
   {NULL, FTCL_ARGV_END, NULL, NULL, NULL}
};

static int
tclUsnoDel (ClientData clientData,
		    Tcl_Interp *interp,
		    int argc,
		    char **argv)
{
  char *handle = NULL;
  TA_USNO_CATALOG *catalog = NULL;
  int status;

  /* Parse the arguments */
  usnoDelTbl[1].dst = &handle;
  if ((status = shTclParseArgv(interp, &argc, argv, usnoDelTbl,
			       usnoDelFlg, usnoDelCmd))
      != FTCL_ARGV_SUCCESS)
    return status;
   
  /* Get handle to the catalog */
  if (shTclAddrGetFromName (interp, handle, (void **)&catalog,
			    "TA_USNO_CATALOG") != TCL_OK)
    {
      Tcl_AppendResult(interp, usnoDelCmd,
		       ": error getting handle to catalog", NULL);
      return TCL_ERROR;
    }

  /* Delete it and its handle */
  if (catalog->version != NULL) shFree(catalog->version);
  if (catalog->obj != NULL) shFree(catalog->obj);
  shFree(catalog);
  p_shTclHandleDel(interp, handle);

  /* Return */
  Tcl_SetResult(interp,"",TCL_STATIC);
  return(TCL_OK);
}


/*****************************************************************************
 *
 * Declare my new tcl verbs to tcl
 */
void
taTclCatalogsDeclare(Tcl_Interp *interp) 
{
  char *tclHelpFacil = "ta";
  shTclDeclare(interp, firstReadCmd,
	       (Tcl_CmdProc *)tclFirstRead,
	       (ClientData) 0,	(Tcl_CmdDeleteProc *)NULL, tclHelpFacil,
	       shTclGetArgInfo(interp, firstReadTbl, firstReadFlg,
			       firstReadCmd),
	       shTclGetUsage(interp, firstReadTbl, firstReadFlg,
			     firstReadCmd));
  shTclDeclare(interp, firstDelCmd,
	       (Tcl_CmdProc *)tclFirstDel,
	       (ClientData) 0,	(Tcl_CmdDeleteProc *)NULL, tclHelpFacil,
	       shTclGetArgInfo(interp, firstDelTbl, firstDelFlg,
			       firstDelCmd),
	       shTclGetUsage(interp, firstDelTbl, firstDelFlg,
			     firstDelCmd));
  shTclDeclare(interp, rosatReadCmd,
	       (Tcl_CmdProc *)tclRosatRead,
	       (ClientData) 0,	(Tcl_CmdDeleteProc *)NULL, tclHelpFacil,
	       shTclGetArgInfo(interp, rosatReadTbl, rosatReadFlg,
			       rosatReadCmd),
	       shTclGetUsage(interp, rosatReadTbl, rosatReadFlg,
			     rosatReadCmd));
  shTclDeclare(interp, rosatDelCmd,
	       (Tcl_CmdProc *)tclRosatDel,
	       (ClientData) 0,	(Tcl_CmdDeleteProc *)NULL, tclHelpFacil,
	       shTclGetArgInfo(interp, rosatDelTbl, rosatDelFlg,
			       rosatDelCmd),
	       shTclGetUsage(interp, rosatDelTbl, rosatDelFlg,
			     rosatDelCmd));
  shTclDeclare(interp, usnoReadCmd,
	       (Tcl_CmdProc *)tclUsnoRead,
	       (ClientData) 0,	(Tcl_CmdDeleteProc *)NULL, tclHelpFacil,
	       shTclGetArgInfo(interp, usnoReadTbl, usnoReadFlg,
			       usnoReadCmd),
	       shTclGetUsage(interp, usnoReadTbl, usnoReadFlg,
			     usnoReadCmd));
  shTclDeclare(interp, usnoDelCmd,
	       (Tcl_CmdProc *)tclUsnoDel,
	       (ClientData) 0,	(Tcl_CmdDeleteProc *)NULL, tclHelpFacil,
	       shTclGetArgInfo(interp, usnoDelTbl, usnoDelFlg,
			       usnoDelCmd),
	       shTclGetUsage(interp, usnoDelTbl, usnoDelFlg,
			     usnoDelCmd));
}
