/*****************************************************************************
******************************************************************************
**<AUTO>
**
** FILE:	target.c
**
**<HTML>
**	This file contains C functions to select spectroscopic targets.
**</HTML>
**</AUTO>
**
**
** ENVIRONMENT:
**	ANSI C.
**
******************************************************************************
******************************************************************************
*/
#include <dervish.h>
#include "taCalibObj.h"
#include "arObjectStatus.h"
#include "arTargetType.h"
#include "taQuasars.h"
#include "taGalaxies.h"
#include "taStars.h"
#include "taSerendipity.h"
#include "taStandards.h"
#include "taTarget.h"
#include "taCatalogs.h"
#include "taRosat.h"
#include "taDiag.h"

/*****************************************************************************
******************************************************************************
**<AUTO EXTRACT>
**
** ROUTINE:	taTargetSelectFromChain
**
**<HTML>
**	Select spectroscopic targets from all PRIMARY and SECONDARY objects in
**	 a chain
**	of calibrated objects.  For each object, the appropriate target
**	selection bit is set for each target selection criterion it meets;
**	if any criteria are met, then the AR_OBJECT_STATUS_TARGET
**	bit is set in the object's status flag, indicating that this object
**	is a spectroscopic target.  Those bits are cleared on entry.
**	Only those criterion which have a non-NULL tunable parameters
**	structure passed in are tested.  Optionally, if pointers to either
**	the FIRST, ROSAT, and/or USNO catalogs are non-NULL, then the objects
**	are matched against those catalogs and the FIRST, ROSAT, and/or USNO
**	information fields are reset (the matching is done before selecting
**	targets).
**</HTML>
**</AUTO>
******************************************************************************
******************************************************************************
*/
RET_CODE
taTargetSelectFromChain(CHAIN *objs,
			/* MODIFIED: chain of calibrated objects*/
			const TA_GALAXIES_PARAMS *galaxiesParams,
			/* IN: Galaxies WG tunable parameters */
			const TA_QUASARS_PARAMS *quasarsParams,
			/* IN: Quasars WG tunable parameters */
			const TA_SERENDIPITY_PARAMS *serendipityParams,
			/* IN: Serendipity WG tunable parameters */
			const TA_ROSAT_PARAMS *rosatParams,
			/* IN: ROSAT tunable parameters */
			const TA_STARS_PARAMS *starsParams,
			/* IN: Stars WG tunable parameters */
			const TA_STANDARDS_PARAMS *standardsParams,
			/* IN: Standards tunable parameters */
			TA_FIRST_CATALOG *first,
			/* IN: FIRST catalog */
			TA_ROSAT_CATALOG *rosat,
			/* IN: ROSAT catalog */
			TA_USNO_CATALOG *usno,
			/* IN: USNO catalog */
			TA_DIAG *diag
			/* MOD: running diagnostics */
			)
{
  CURSOR_T curse;
  TA_CALIB_OBJ *obj;

  curse = shChainCursorNew(objs);
  while ((obj = shChainWalk(objs, curse, NEXT)) != NULL)
    {
      /* If this is a primary or secondary object, pass it through the target
       * selection algorithms.
       */

      if (obj->status & AR_OBJECT_STATUS_PRIMARY ||\
	  obj->status & AR_OBJECT_STATUS_SECONDARY)
	{
	  if (taTargetSelectFromObj(obj, galaxiesParams, quasarsParams,
				    serendipityParams, rosatParams,
				    starsParams, standardsParams, first,
				    rosat, usno)
	      != SH_SUCCESS)
	    {
	      shChainCursorDel(objs, curse);
	      return SH_GENERIC_ERROR;
	    }
	  if (diag != NULL)
	    if (taDiagUpdate(diag, obj) != SH_SUCCESS)
	      {
		shChainCursorDel(objs, curse);
		return SH_GENERIC_ERROR;
	      }
	}
    }
  shChainCursorDel(objs, curse);
  return SH_SUCCESS;
}


/*****************************************************************************
******************************************************************************
**<AUTO EXTRACT>
**
** ROUTINE:	taTargetSelectFromObj
**
**<HTML>
**	Test a single object against the target selection criteria.  The
**	appropriate target selection bit is set for each criterion it meets;
**	if any criteria are met, then the AR_OBJECT_STATUS_TARGET
**	bit is set in the object's status flag, indicating that this object
**	is a spectroscopic target.  Those bits are cleared on entry.
**	Only those criterion which have a non-NULL tunable parameters
**	structure passed in are tested.  Optionally, if pointers to either
**	the FIRST, ROSAT, and/or USNO catalogs are non-NULL, then the objects
**	are matched against those catalogs and the FIRST, ROSAT, and/or USNO
**	information fields are reset (the matching is done before selecting
**	targets).
**</HTML>
**</AUTO>
******************************************************************************
******************************************************************************
*/
RET_CODE
taTargetSelectFromObj(TA_CALIB_OBJ *obj,   /* MODIFIED: object to target */
		      const TA_GALAXIES_PARAMS *galaxiesParams,
		      /* IN: Galaxies WG tunable parameters */
		      const TA_QUASARS_PARAMS *quasarsParams,
		      /* IN: Quasars WG tunable parameters */
		      const TA_SERENDIPITY_PARAMS *serendipityParams,
		      /* IN: Serendipity WG tunable parameters */
		      const TA_ROSAT_PARAMS *rosatParams,
		      /* IN: ROSAT tunable parameters */
		      const TA_STARS_PARAMS *starsParams,
		      /* IN: Stars WG tunable parameters */
		      const TA_STANDARDS_PARAMS *standardsParams,
		      /* IN: Standards tunable parameters */
		      TA_FIRST_CATALOG *first,
		      /* IN: FIRST catalog */
		      TA_ROSAT_CATALOG *rosat,
		      /* IN: ROSAT catalog */
		      TA_USNO_CATALOG *usno
		      /* IN: USNO catalog */
		      )
{
  int galaxiesPriority = 0, quasarsPriority = 0, starsPriority = 0;
  int serendipityPriority = 0, rosatPriority = 0, standardsPriority = 0;

  /* Clear all target selection flags and bits */
  obj->primTarget = 0;
  obj->secTarget = 0;
  obj->priority = 0;
  obj->status &= (~ AR_OBJECT_STATUS_TARGET);

  /* Match against external catalogs */
  if (first != NULL) taObjMatchAgainstFirst(obj, first);
  if (rosat != NULL) taObjMatchAgainstRosat(obj, rosat);
  if (usno != NULL)  taObjMatchAgainstUSNO(obj, usno);

  /* Test object against each target type criterion */
  if (galaxiesParams != NULL)
    if ((galaxiesPriority = taGalaxiesTargetSelect(obj, galaxiesParams)) == -1)
      return SH_GENERIC_ERROR;
  if (quasarsParams != NULL)
    if ((quasarsPriority = taQuasarsTargetSelect(obj, quasarsParams)) == -1)
      return SH_GENERIC_ERROR;
  if (starsParams != NULL)
    if ((starsPriority = taStarsTargetSelect(obj, starsParams)) == -1)
      return SH_GENERIC_ERROR;
  if (serendipityParams != NULL)
    if ((serendipityPriority =
	 taSerendipityTargetSelect(obj, serendipityParams)) == -1)
      return SH_GENERIC_ERROR;
  if (rosatParams != NULL)
    if ((rosatPriority = taRosatTargetSelect(obj, rosatParams)) == -1)
      return SH_GENERIC_ERROR;
  if (standardsParams != NULL)
    if ((standardsPriority =
	 taStandardsTargetSelect(obj, standardsParams)) == -1)
      return SH_GENERIC_ERROR;

  /* Set TARGET bit in status flag if it met any target criteria */
  if (obj->primTarget || obj->secTarget)
    {
      obj->status |= AR_OBJECT_STATUS_TARGET;
      /* If this is a tilable object, then set its priority based on galaxies,
       * quasars, and HOT_STD or BROWN_DWARF priority, with HOT_STD and
       * BROWN_DWARF always having higher
       * priority followed by quasars and then
       * galaxies.  If not a tilable object, then set priority by
       * assembling the byte-sized priorities into a 4-byte priority, in
       * order stars, serendipity, rosat, and standards. */
      if (galaxiesPriority > 0 || quasarsPriority > 0 ||
	  obj->secTarget & TAR_TARGET_HOT_STD ||
	  obj->primTarget & AR_TARGET_STAR_BROWN_DWARF)
	{
	  obj->priority = (unsigned int) galaxiesPriority |
	    (unsigned int) quasarsPriority << 8;
	  if (obj->secTarget & TAR_TARGET_HOT_STD)
	    obj->priority |= (unsigned int) standardsPriority << 16;
	  else if (obj->primTarget & AR_TARGET_STAR_BROWN_DWARF)
	    obj->priority |= (unsigned int) starsPriority << 16;
	}
      else
	{
	  obj->priority = (unsigned int) starsPriority |
	    (unsigned int) serendipityPriority << 8 |
	    (unsigned int) rosatPriority << 16 |
	    (unsigned int) standardsPriority << 24;
	}
    }

  /* Successful return */
  return SH_SUCCESS;
}





