#if !defined(PS_OBJECT_H)
#define PS_OBJECT_H

/** \file psObject.h
 *  \brief Definition and manipulation of astronomical objects 
 *  \ingroup AstroGroup
 */

/***********************************************************************************************************/

/** Object definition, to handle both objects we detect, and catalogues */
typedef struct {
    psCoord *cell;			///< Centre position on Cell, with associated error
    psCoord *sky;			///< Position on the sky, with associated error
    float mag, magErr;			///< Magnitude and associated error
    float isoMag, isoMagErr;		///< Isophotal magnitude and associated error
    float fwhm, fwhmErr;		///< FWHM and associated error
    float ellipA, ellipB;		///< Elliptical semi-major (A) and semi-minor (B) axes
    float ellipAngle;			///< Ellipse position angle
    float sky, skyErr;			///< Local sky level, and associated error
    float colour, colourErr;		///< Colour and associated error, if known
    psPhotSysrem colorPlus, colorMinus;	///< Colour reference
    psBitset *quality;			///< Bit mask for quality information
    psCell *parentCell;			///< Cell this measurement came from
} psObject;

/** Constructor */
psObject *
psObjectAlloc(void);

/** Destructor */
void
psObjectFree(psObject *restrict myObject);

/***********************************************************************************************************/

/** An assembly of objects */
typedef struct {
    psType type;			///< Type of data.  THIS STRUCT ELEMENT MUST BE FIRST IN THE STRUCT!
    int size;				///< Total number of elements available
    int n;				///< Number of elements in use
    psObject *arr;			///< The array data
} psObjectArray;

/** Constructor */
psObjectArray *psObjectArrayAlloc(int s, ///< Total number of elements to make available
				  int n	///< Number of elements that will be used
    );
/** Reallocator */
psObjectArray *psObjectArrayRealloc(psObjectArray *myArray, ///< Array to reallocate
				    int s ///< Total number of elements to make available
    );
/** Destructor */
void psObjectArrayFree(psObjectArray *restrict myArray ///< Array to free
    );

/***********************************************************************************************************/

/** Associates objects on an image with the image */
typedef struct {
    const struct psImage *image;	///< Image that produced the objects, which has metadata we need
    psObjectArray *objects;		///< The objects
} psImageObjects;

/** Constructor */
psImageObjects *
psImageObjectsAlloc(const struct psImage *image, ///< Image that produced the objects, with needed metadata
		    psObjectArray *objects ///< The objects
    );

/** Destructor */
void
psImageObjectsFree(psImageObjects *restrict myImageObjects ///< Object to destroy
		  );

/***********************************************************************************************************/

/** Objects from a catalogue */
typedef struct {
    psCatalogue catalogue;		///< Source catalogue from which objects come
    psObjectArray *object;		///< The objects
} psCatalogueObjects;

/** Constructor */
psCatalogueObjects *
psCatalogueObjectsAlloc(enum psCatalogue *catalogue, ///< Source catalogue
			psObjectArray *objects ///< The objects
    );

/** Destructor */
void
psCatalogueObjectsFree(psCatalogueObjects *restrict myCatalogueObjects ///< Object to destroy
		      );

/***********************************************************************************************************/

/** A "super" object --- an object with multiple detections in different images */
typedef struct {
    const struct  psImageArray *images;	///< Images that provided the different measurements
    const psObjectArray *objects;	///< Individual object measurements

    /* Derived quantities */
    psSkyPos *meanSkyPos;		///< Mean position on the sky
    double pmRA, pmDec;			///< Proper motion in RA and Dec
    double pmRAErr, pmDecErr;		///< Errors in proper motion
    float posChi2;			///< chi^2 for position
} psSuperObject;

/** Constructor */
psSuperObject *
psSuperObjectAlloc(const struct psImageArray *images, ///< The images with the measurements
		   const psObjectArray *objects ///< Object measurements
    );

/** Destructor */
void
psSuperObjectFree(psSuperObject *restrict mySuperObject ///< Object to destroy
		 );


/***********************************************************************************************************/

/* Correlation */


/** Correlate two OTA object arrays.
 * Returns an array with the indices of the object in the second bunch that matched the corresponding object
 * in the first bunch, or -1 if none that match.
 */
psIntArray *
psCorrelateObjects(const psObjectArray *restrict myObjects1, ///< First bunch of objects
		   const psObjectArray *restrict myObjects2, ///< Second bunch of objects
		   const psOTADescription *myOTA1, ///< OTA description for first bunch of objects, or NULL for
						   ///< sky
		   const psOTADescription *myOTA2 ///< OTA description for second bunch of objects, or NULL for
						  ///< sky
		   );


/** Get matched lists from a correlated index array Returns a status number, and matched1 and matched2
 * are manipulated to contain matches
 */
int
psGetCorrelatedMatches(const psIntArray matches, ///< Index array specifying matches */
		       const psObjectArray *restrict myObjects1, ///< First bunch of objects
		       const psObjectArray *restrict myObjects2, ///< Second bunch of objects
		       psObjectArray *matched1, ///< Matched objects in first bunch
		       psObjectArray *matched2 ///< Matched objects in second bunch
		       );

/***********************************************************************************************************/

/* Object selection */

/** Get objects within a particular magnitude range */
psObjectArray *
psSelectObjectMag(psObjectArray *restrict myArray, ///< Bunch of objects to select from
		  float magLower,	///< Lower bound for magnitude
		  float magUpper	///< Upper bound for magnitude
		  );

/** Get objects within a radius on the sky */
psObjectArray *
psSelectObjectSkyDist(psObjectArray *restrict myArray, ///< Bunch of objects to select from
		      psSkyPos *skyPos,	///< Position on the sky
		      float radius,	///< Radius of search
		      int circleOrSquare ///< Circle = 1, Square = 2
		      );

/** Get objects within a particular colour range */
psObjectArray *
psSelectObjectColour(psObjectArray *restrict myArray, ///< Bunch of objects to select from
		     float magLower,	///< Lower bound for colour
		     float magUpper,	///< Upper bound for colour
		     psColourRef colourRef ///< Only select those with this colour reference
		     );


#endif

