/*****************************************************************************
******************************************************************************
**<AUTO>
**
** FILE:	rosat.c
**
**<HTML>
**	This file contains C functions to select spectroscopic targets for
**	ROSAT objects.
**</HTML>
**</AUTO>
**
**
** ENVIRONMENT:
**	ANSI C.
**
******************************************************************************
******************************************************************************
*/
#include <dervish.h>
#include "taCalibObj.h"
#include "taRosat.h"
#include "arTargetType.h"


/***************************************************************************
 * below are the private functions which pass/fail an object in each of
 * the ROSAT categories.  Their definitions appear after the
 * main routine, below.
 */
static int is_rosat_d (TA_CALIB_OBJ *obj,
                            const TA_ROSAT_PARAMS *params);
static int is_rosat_brtstar (TA_CALIB_OBJ *obj,
                                const TA_ROSAT_PARAMS *params);
static int is_rosat_brtgal (TA_CALIB_OBJ *obj,
                                const TA_ROSAT_PARAMS *params);
static int is_rosat_bluegal (TA_CALIB_OBJ *obj,
                                const TA_ROSAT_PARAMS *params);
static int is_rosat_uvstar (TA_CALIB_OBJ *obj,
                                const TA_ROSAT_PARAMS *params);
static int is_rosat_qsorej (TA_CALIB_OBJ *obj,
                                const TA_ROSAT_PARAMS *params);
static int is_rosat_uvagn (TA_CALIB_OBJ *obj,
                            const TA_ROSAT_PARAMS *params);
static int is_rosat_qso (TA_CALIB_OBJ *obj,
                            const TA_ROSAT_PARAMS *params);
static int is_rosat_first (TA_CALIB_OBJ *obj,
                            const TA_ROSAT_PARAMS *params);
static int is_rosat_firstqso (TA_CALIB_OBJ *obj,
                            const TA_ROSAT_PARAMS *params);


/*****************************************************************************
******************************************************************************
**<AUTO EXTRACT>
**
** ROUTINE:	taRosatTargetSelect
**
**<HTML>
**	Set the appropriate bit in the primary target bit mask for each
**	ROSAT target selection criterion this object
**	satisfies.  This routine is responsible for setting the following
**	bits:
**	<menu>
**	<li> AR_TARGET_ROSAT_A
**	<li> AR_TARGET_ROSAT_B
**	<li> AR_TARGET_ROSAT_C
**	<li> AR_TARGET_ROSAT_D
**	<li> AR_TARGET_ROSAT_E
**	</menu>
**	It is assumed that the above bits are unset on entry, although other
**	bits may be set.
**</HTML>
**
** RETURNS:
**      -1      error
**      0       not a target by any criteria
**      1-255   is a target by one or more criteria --- priority returned
**              (higher number = higher priority)
**</AUTO>
******************************************************************************
******************************************************************************
*/
int
taRosatTargetSelect(TA_CALIB_OBJ *obj,
			  /* MOD: calibrated object to test */
			  const TA_ROSAT_PARAMS *params
			  /* IN: tunable parameters*/)
{
  int priority = 0;     /* targeting priority (initialize for a non-target) */

       /* must be ROSAT source */
       if (obj->rosatMatch != 0) {

          /* must not be bright, saturated, or edge to get a fiber */
          if(!(obj->objc_flags&(AR_DFLAG_BRIGHT | AR_DFLAG_SATUR 
                                | AR_DFLAG_EDGE)))  {

	        /* check to see if the object satisfies the ROSAT_D criteria */
	        if (is_rosat_d(obj, params)) {
		        obj->primTarget |= AR_TARGET_ROSAT_D;
                        priority = params->priorD;
                        /* increment priority if very clean object */
                        if (!(obj->objc_flags&(AR_DFLAG_BLENDED | AR_DFLAG_CHILD
                                | AR_DFLAG_CR | AR_DFLAG_INTERP
                                | AR_DFLAG_NOTCHECKED | AR_DFLAG_SUBTRACTED 
                                | AR_DFLAG_BADSKY | AR_DFLAG_TOO_LARGE))) {
                            priority++;
                        }
                        /* increment priority if flagged as QSO MAG OUTLIER, or BRG */
                        if (obj->primTarget&(AR_TARGET_QSO_MAG_OUTLIER
                            | AR_TARGET_GALAXY_RED | AR_TARGET_GALAXY_RED_II)) {
                           priority++;
                        }

	        }

                /* check if object satisfies the ROSAT_C bright star criteria */
                if (is_rosat_brtstar(obj, params)) {
                        obj->primTarget |= AR_TARGET_ROSAT_C;
                        priority = params->priorBrtStar;  
	        }

                /* check if object satisfies the ROSAT_C bright galaxy criteria */
                if (is_rosat_brtgal(obj, params)) {
                        obj->primTarget |= AR_TARGET_ROSAT_C;
                        priority = params->priorBrtGal;  
	        }

                /* check if object satisfies the ROSAT_C blue gal criteria */
                if (is_rosat_bluegal(obj, params)) {
                        obj->primTarget |= AR_TARGET_ROSAT_C;
                        priority = params->priorBlueGal;  
	        }

                /* check if object satisfies the ROSAT_C UV star criteria */
                if (is_rosat_uvstar(obj, params)) {
                        obj->primTarget |= AR_TARGET_ROSAT_C;
                        priority = params->priorUVStar;  
	        }

                /* check if object satisfies the ROSAT_C qso reject box criteria */
                if (is_rosat_qsorej(obj, params)) {
                        obj->primTarget |= AR_TARGET_ROSAT_C;
                        priority = params->priorQSORej;  
	        }

                /* check if object satisfies ROSAT_B UVX AGN criteria */
                if (is_rosat_uvagn(obj, params)) {
                        obj->primTarget |= AR_TARGET_ROSAT_B;
                        priority = params->priorUVAGN;  
	        }

                /* check to see if the object flagged by QSO WG */
                if (is_rosat_qso(obj, params)) {
                        obj->primTarget |= AR_TARGET_ROSAT_B;
                        priority = params->priorQSO;  
	        }

                /* check to see if FIRST object, and hence ROSAT_A criteria */
                if (is_rosat_first(obj, params)) {
                        obj->primTarget |= AR_TARGET_ROSAT_A;
                        priority = params->priorFIRST;  
	        }

                /* check if flagged as FIRST QSO, hence ROSAT_A criteria */
                if (is_rosat_firstqso(obj, params)) {
                        obj->primTarget |= AR_TARGET_ROSAT_A;
                        priority = params->priorFIRSTQSO;  
                }

	  }

          /* if in 1' circle, not suitable for spectrum, ROSAT_E */
          if( (obj->rosatDelta > params->deltaMax) || 
              (obj->rosatDetectLike < params->detectLikeMin) || 
              ( !(obj->primTarget&(AR_TARGET_ROSAT_A | AR_TARGET_ROSAT_B
                           | AR_TARGET_ROSAT_C | AR_TARGET_ROSAT_D))) ) {
                obj->primTarget |= AR_TARGET_ROSAT_E;
                priority = 0;
          }

       }         
	
  /* Successful return */
  return priority;
}


/************************************************************************
 * the routines which follow are "private": they are not visible to
 *   functions outside this source code file.  Each is called from the
 *   the function "taRosatTargetSelect" above, and decides whether
 *   the given "TA_CALIB_OBJ" structure contains data which satisfies
 *   one of the ROSAT sub-categories' criteria.
 */


/* ROSAT_D other
 * return 1 if the given object satisfies the ROSAT_D criteria 
 * basically, its a ROSAT match bright enough for spectra
*/

static int
is_rosat_d(
        TA_CALIB_OBJ *obj,
	const TA_ROSAT_PARAMS *params
	)
{
        float gmag, gerr;
        float rmag, rerr;
        float imag, ierr;

        shAssert(obj != NULL);
        shAssert(obj->detection != NULL);
        shAssert(params != NULL);

        gmag = obj->detection[TA_G].fiberCounts.val;
        gerr = obj->detection[TA_G].fiberCounts.err;
        rmag = obj->detection[TA_R].fiberCounts.val;
        rerr = obj->detection[TA_R].fiberCounts.err;
        imag = obj->detection[TA_I].fiberCounts.val;
        ierr = obj->detection[TA_I].fiberCounts.err;

        /* must not be too bright */
        if ( (gmag < params->gMin) || (rmag < params->rMin)
                || (imag < params->iMin) ) {
                return(0);
        }

        /* must be within a mag range accessible to spectra */
        if ( ((gmag < params->gMin) || (gmag > params->gMax)) && 
                ((rmag < params->rMin) || (rmag > params->rMax)) && 
                ((imag < params->iMin) || (imag > params->iMax)) ) {
                return(0);
        }
         
        /* 
         * if the object survives to this point, it satisfies all
         * criteria for a ROSAT_D.  Return 1 to signal success!
         */
        return(1);
}



/* ROSAT_C bright star
 * return 1 if the given object satisfies the ROSAT_C criteria 
 *    for bright star 
 * return 0 otherwise
 */
static int
is_rosat_brtstar(
        TA_CALIB_OBJ *obj,
        const TA_ROSAT_PARAMS *params
        )
{
        float rmag,gfib,rfib,ifib;
        
        shAssert(obj != NULL);
        shAssert(obj->detection != NULL);
        shAssert(params != NULL);
        
        rmag = obj->detection[TA_R].psfCounts.val;  
        gfib = obj->detection[TA_G].fiberCounts.val;  
        rfib = obj->detection[TA_R].fiberCounts.val;  
        ifib = obj->detection[TA_I].fiberCounts.val;  

        /* must not be too bright */
        if ( (gfib < params->gMin) || (rfib < params->rMin)
                || (ifib < params->iMin) ) {
                return(0);
        }

        /* must be star */
        if (obj->objc_type != AR_OBJECT_TYPE_STAR) {
               return(0); 
        }

        /* must be bright star */
        if ( rmag > params->rBrtStar ) {
                return(0);
        }
        
        /* 
         * if the object survives to this point, it satisfies all
         * criteria for a bright star ROSAT_C object.  Return 1 to signal success!
         */
        return(1);
}


/*
 * return 1 if the given object satisfies the ROSAT_C criteria 
 *    for bright galaxy
 * return 0 otherwise
 */
static int
is_rosat_brtgal(
        TA_CALIB_OBJ *obj,
        const TA_ROSAT_PARAMS *params
        )
{
        float gmag,rmag,imag;
        
        shAssert(obj != NULL);
        shAssert(obj->detection != NULL);
        shAssert(params != NULL);
        
        gmag = obj->detection[TA_G].fiberCounts.val;  
        rmag = obj->detection[TA_R].fiberCounts.val;  
        imag = obj->detection[TA_I].fiberCounts.val;  

        /* must not be too bright */
        if ( (gmag < params->gMin) || (rmag < params->rMin)
                || (imag < params->iMin) ) {
                return(0);
        }

        /* must be a galaxy */
        if (obj->objc_type != AR_OBJECT_TYPE_GALAXY) {
               return(0); 
        }

        /* must be bright galaxy */
        if ( rmag > params->rBrtGal ) {
                return(0);
        }
        
        /* 
         * if the object survives to this point, it satisfies all
         * criteria for a bright galaxy ROSAT_C object.  Return 1 to signal success!
         */
        return(1);
}




/*
 * return 1 if the given object satisfies the ROSAT_C criteria 
 *    for ROSAT match to a blue in g-r galaxy
 * return 0 otherwise
 */
static int
is_rosat_bluegal(
        TA_CALIB_OBJ *obj,
        const TA_ROSAT_PARAMS *params
        )
{
        float gmag, gerr;
        float rmag, rerr;
        float imag, ierr;
        float g_minus_r;
        
        shAssert(obj != NULL);
        shAssert(obj->detection != NULL);
        shAssert(params != NULL);
        
        gmag = obj->detection[TA_G].fiberCounts.val;
        gerr = obj->detection[TA_G].fiberCounts.err;
        rmag = obj->detection[TA_R].fiberCounts.val;  
        rerr = obj->detection[TA_R].fiberCounts.err;
        imag = obj->detection[TA_I].fiberCounts.val;  
        ierr = obj->detection[TA_I].fiberCounts.err;
        g_minus_r = gmag - rmag;

        /* must not be too bright */
        if ( (gmag < params->gMin) || (rmag < params->rMin)
                || (imag < params->iMin) ) {
                return(0);
        }

        /* must be within a mag range accessible to spectra */
        if ( ((gmag < params->gMin) || (gmag > params->gMax)) && 
                ((rmag < params->rMin) || (rmag > params->rMax)) && 
                ((imag < params->iMin) || (imag > params->iMax)) ) {
                return(0);
        }

        
        /* must be galaxy (may change to stellar likelihood) */
        if (obj->objc_type != AR_OBJECT_TYPE_GALAXY) {
               return(0); 
        }

        /* must have small errors in g and r mags */
        if ((gerr > params->gerrMax) || (rerr > params->rerrMax)) {
                return(0);
        }
 
        /* must be bluer than a certain g-r color */
        if (g_minus_r > params->grMaxBlueGal) {
               return(0);
        }
        
        /* 
         * if the object survives to this point, it satisfies all
         * criteria for a blue galaxy ROSAT_C object.  Return 1 to signal success!
         */
        return(1);
}

/*
 * return 1 if the given object satisfies the ROSAT_C criteria 
 *    for a moderately blue in u-g star
 * return 0 otherwise
 */
static int
is_rosat_uvstar(
        TA_CALIB_OBJ *obj,
        const TA_ROSAT_PARAMS *params
        )
{
        float umag, uerr; 
        float gmag, gerr;
        float rmag, rerr;
        float imag, ierr;
        float u_minus_g, g_minus_r;
        float gfib,rfib,ifib;
        
        shAssert(obj != NULL);
        shAssert(obj->detection != NULL);
        shAssert(params != NULL);
        
        umag = obj->detection[TA_U].psfCounts.val;
        uerr = obj->detection[TA_U].psfCounts.err;
        gmag = obj->detection[TA_G].psfCounts.val;
        gerr = obj->detection[TA_G].psfCounts.err;
        rmag = obj->detection[TA_R].psfCounts.val;  
        rerr = obj->detection[TA_R].psfCounts.err;
        imag = obj->detection[TA_I].psfCounts.val;  
        ierr = obj->detection[TA_I].psfCounts.err;
        gfib = obj->detection[TA_G].fiberCounts.val;  
        rfib = obj->detection[TA_R].fiberCounts.val;  
        ifib = obj->detection[TA_I].fiberCounts.val;  
        u_minus_g = umag - gmag;
        g_minus_r = gmag - rmag;


        /* must not be too bright */
        if ( (gfib < params->gMin) || (rfib < params->rMin)
                || (ifib < params->iMin) ) {
                return(0);
        }

        /* must be within a mag range accessible to spectra */
        if ( ((gmag < params->gMin) || (gmag > params->gMax)) && 
                ((rmag < params->rMin) || (rmag > params->rMax)) && 
                ((imag < params->iMin) || (imag > params->iMax)) ) {
                return(0);
        }

        
        /* must be stellar */
        if (obj->objc_type != AR_OBJECT_TYPE_STAR) {
               return(0); 
        }

        /* must have small errors in u and g mags */
        if ((uerr > params->uerrMax) || (gerr > params->gerrMax)) {
                return(0);
        }
 
        /* must be bluer than a certain u-g color */
        if (u_minus_g > params->ugMaxUVStar) {
               return(0);
        }
        
        /* 
         * if the object survives to this point, it satisfies all
         * criteria for a ROSAT_C, moderately blue in u-g star or QSO.  
         * Return 1 to signal success!
         */
        return(1);
}


/*
 * return 1 if the given object satisfies the ROSAT_C criteria 
 *    via check against QSO REJECT BOX flags.
 * return 0 otherwise
 */
static int
is_rosat_qsorej(
        TA_CALIB_OBJ *obj,
        const TA_ROSAT_PARAMS *params
        )
{
        float gmag,rmag,imag;

        shAssert(obj != NULL);
        shAssert(obj->detection != NULL);
        shAssert(params != NULL);

        gmag = obj->detection[TA_G].fiberCounts.val;  
        rmag = obj->detection[TA_R].fiberCounts.val;  
        imag = obj->detection[TA_I].fiberCounts.val;  

        /* must not be too bright */
        if ( (gmag < params->gMin) || (rmag < params->rMin)
                || (imag < params->iMin) ) {
                return(0);
        }
        
        /* must be within a mag range accessible to spectra */
        if ( ((gmag < params->gMin) || (gmag > params->gMax)) && 
                ((rmag < params->rMin) || (rmag > params->rMax)) && 
                ((imag < params->iMin) || (imag > params->iMax)) ) {
                return(0);
        }

        /* must be in QSO WG rejection box (adopt their mag limit--no) */
        if (!(obj->primTarget&(AR_TARGET_QSO_REJECT))) {
                return(0);
        }

        
        /* 
         * if the object survives to this point, it satisfies all
         * criteria for a ROSAT_C object.  Return 1 to signal success!
         */
        return(1);
}

/*
 * return 1 if the given object satisfies the ROSAT_B criteria 
 *    basically it's just a ROSAT match to a blue in u-g 
 *    Temp substitute for AGN/QSO, but want to add check against QSO
 *    flags (instead or in addition).
 * return 0 otherwise
 */
static int
is_rosat_uvagn(
        TA_CALIB_OBJ *obj,
        const TA_ROSAT_PARAMS *params
        )
{
        float umag, uerr; 
        float gmag, gerr;
        float rmag, rerr;
        float imag, ierr;
        float u_minus_g, g_minus_r;
        
        shAssert(obj != NULL);
        shAssert(obj->detection != NULL);
        shAssert(params != NULL);
        
        umag = obj->detection[TA_U].fiberCounts.val;
        uerr = obj->detection[TA_U].fiberCounts.err;
        gmag = obj->detection[TA_G].fiberCounts.val;
        gerr = obj->detection[TA_G].fiberCounts.err;
        rmag = obj->detection[TA_R].fiberCounts.val;  
        rerr = obj->detection[TA_R].fiberCounts.err;
        imag = obj->detection[TA_I].fiberCounts.val;  
        ierr = obj->detection[TA_I].fiberCounts.err;
        u_minus_g = umag - gmag;
        g_minus_r = gmag - rmag;


        /* must not be too bright */
        if ( (gmag < params->gMin) || (rmag < params->rMin)
                || (imag < params->iMin) ) {
                return(0);
        }

        /* must be within a mag range accessible to spectra */
        if ( ((gmag < params->gMin) || (gmag > params->gMax)) && 
                ((rmag < params->rMin) || (rmag > params->rMax)) && 
                ((imag < params->iMin) || (imag > params->iMax)) ) {
                return(0);
        }

        
        /* must be star or galaxy (may change to star_l) */
        if ((obj->objc_type != AR_OBJECT_TYPE_STAR) &&
                (obj->objc_type != AR_OBJECT_TYPE_GALAXY)) {
               return(0); 
        }

        /* must have small errors in u and g mags */
        if ((uerr > params->uerrMax) || (gerr > params->gerrMax)) {
                return(0);
        }
 
        /* must be bluer than a certain u-g color */
        if (u_minus_g > params->ugMaxQSO) {
               return(0);
        }
        
        /* 
         * if the object survives to this point, it satisfies all
         * criteria for a ROSAT_B object.  Return 1 to signal success!
         */
        return(1);
}

/*
 * return 1 if the given object satisfies the ROSAT_B criteria 
 *    via check against several QSO HIZ and CAP/SKIRT flags.
 * return 0 otherwise
 */
static int
is_rosat_qso(
        TA_CALIB_OBJ *obj,
        const TA_ROSAT_PARAMS *params
        )
{
        float rmag,gfib,rfib,ifib;

        shAssert(obj != NULL);
        shAssert(obj->detection != NULL);
        shAssert(params != NULL);

        rmag = obj->detection[TA_R].psfCounts.val;  
        gfib = obj->detection[TA_G].fiberCounts.val;  
        rfib = obj->detection[TA_R].fiberCounts.val;  
        ifib = obj->detection[TA_I].fiberCounts.val;  

        /* must not be too bright */
        if ( (gfib < params->gMin) || (rfib < params->rMin)
                || (ifib < params->iMin) ) {
                return(0);
        }
        
        /* must be selected by QSO WG (adopt their mag limit--TBD) */
        if (!(obj->primTarget&(AR_TARGET_QSO_HIZ | AR_TARGET_QSO_CAP |
                AR_TARGET_QSO_SKIRT))) {
                return(0);
        }

        
        /* 
         * if the object survives to this point, it satisfies all
         * criteria for a ROSAT_B object.  Return 1 to signal success!
         */
        return(1);
}


static int
is_rosat_first(
        TA_CALIB_OBJ *obj,
	const TA_ROSAT_PARAMS *params
	)
{
        float gmag, gerr;
        float rmag, rerr;
        float imag, ierr;

        shAssert(obj != NULL);
        shAssert(obj->detection != NULL);
        shAssert(params != NULL);

        gmag = obj->detection[TA_G].fiberCounts.val;
        gerr = obj->detection[TA_G].fiberCounts.err;
        rmag = obj->detection[TA_R].fiberCounts.val;
        rerr = obj->detection[TA_R].fiberCounts.err;
        imag = obj->detection[TA_I].fiberCounts.val;
        ierr = obj->detection[TA_I].fiberCounts.err;

        /* must be FIRST source */
        if(obj->firstMatch ==0 ) { 
               return(0);
        } 


        /* must not be too bright */
        if ( (gmag < params->gMin) || (rmag < params->rMin)
                || (imag < params->iMin) ) {
                return(0);
        }

        /* must be within a mag range accessible to spectra */
        if ( ((gmag < params->gMin) || (gmag > params->gMax)) && 
                ((rmag < params->rMin) || (rmag > params->rMax)) && 
                ((imag < params->iMin) || (imag > params->iMax)) ) {
                return(0);
        }
         

        /* some error check to avoid some junk, currently turned off */
/*        if ((gerr > params->gerrMax) && (rerr > params->rerrMax)
 *                && (ierr > params->ierrMax)) {
 *                return(0);
 *        }
*/


        /* 
         * if the object survives to this point, it satisfies all
         * criteria for a ROSAT_A.  Return 1 to signal success!
         */
        return(1);
}

static int
is_rosat_firstqso(
        TA_CALIB_OBJ *obj,
	const TA_ROSAT_PARAMS *params
	)
{
        float rmag,gfib,rfib,ifib;

        shAssert(obj != NULL);
        shAssert(obj->detection != NULL);
        shAssert(params != NULL);

        rmag = obj->detection[TA_R].psfCounts.val;  
        gfib = obj->detection[TA_G].fiberCounts.val;  
        rfib = obj->detection[TA_R].fiberCounts.val;  
        ifib = obj->detection[TA_I].fiberCounts.val;  

        /* must not be too bright */
        if ( (gfib < params->gMin) || (rfib < params->rMin)
                || (ifib < params->iMin) ) {
                return(0);
        }

        /* FIRST source selected by QSO WG (adopt their mag limit--TBD) */
        if (!(obj->primTarget&(AR_TARGET_QSO_FIRST_CAP | 
                AR_TARGET_QSO_FIRST_SKIRT))) {
                return(0);
        }

        /* 
         * if the object survives to this point, it satisfies all
         * criteria for a ROSAT_A.  Return 1 to signal success!
         */
        return(1);
}


