# include "psastroInternal.h"
# define NONLIN_TOL 0.001 /* tolerance in pixels */

bool psastroChipAstrom (pmConfig *config) {

    pmChip *chip = NULL;
    pmCell *cell = NULL;
    pmReadout *readout = NULL;

    // select the current recipe
    psMetadata *recipe  = psMetadataLookupPtr (NULL, config->recipes, PSASTRO_RECIPE);
    if (!recipe) {
	psError(PSASTRO_ERR_CONFIG, true, "Can't find PSASTRO recipe");
	return false;
    }

    // select the input data sources
    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, "PSASTRO.INPUT");
    if (!input) {
	psError(PSASTRO_ERR_CONFIG, true, "Can't find input data");
	return false;
    }

    pmFPAview *view = pmFPAviewAlloc (0);
    pmFPA *fpa = input->fpa;

    while ((chip = pmFPAviewNextChip (view, fpa, 1)) != NULL) {
        psTrace ("psastro", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
        if (!chip->process || !chip->file_exists) { continue; }
	
	while ((cell = pmFPAviewNextCell (view, fpa, 1)) != NULL) {
            psTrace ("psastro", 4, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
            if (!cell->process || !cell->file_exists) { continue; }

	    // process each of the readouts
	    while ((readout = pmFPAviewNextReadout (view, fpa, 1)) != NULL) {
		if (! readout->data_exists) { continue; }

		// select the raw objects for this readout
		psArray *rawstars = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.RAWSTARS");
		if (rawstars == NULL) { continue; }

		// select the raw objects for this readout
		psArray *refstars = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.REFSTARS");
		if (refstars == NULL) { continue; }

		// the absolute minimum number of stars is 4 (for order = 1)
		if ((rawstars->n < 4) || (refstars->n < 4)) {
		    readout->data_exists = false;
		    psLogMsg ("psastro", 3, "insufficient rawstars (%ld) or refstars (%ld)", 
			    rawstars->n, refstars->n);
		    continue;
		} 

		char *filename = NULL;
		char *chipname = psMetadataLookupStr (NULL, chip->concepts, "CHIP.NAME");

		if (psTraceGetLevel("psastro.dump") > 0) {
		    psStringAppend (&filename, "rawstars.ch.%s.dat", chipname);
		    psastroDumpStars (rawstars, filename);
		    psFree (filename);
		    filename = NULL;

		    psStringAppend (&filename, "refstars.ch.%s.dat", chipname);
		    psastroDumpStars (refstars, filename);
		    psFree (filename);
		    filename = NULL;
		}

		// save WCS and analysis metadata in update header
		psMetadata *updates = psMetadataAlloc();

		// XXX update the header with info to reflect the failure
		if (!psastroOneChip (fpa, chip, refstars, rawstars, recipe, updates)) {
		    readout->data_exists = false;
		    psLogMsg ("psastro", 3, "failed to find a solution\n");
		    psFree (updates);
		    continue;
		}
		pmAstromWriteWCS (updates, fpa, chip, NONLIN_TOL);
		psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSASTRO.HEADER",  PS_DATA_METADATA, "psastro header stats", updates);
		psFree (updates);
	    }
	}
    }
    psFree (view);
    return true;
}

/* coordinate frame hierachy
   pixels (on a given readout)
   cell
   chip
   FP (focal plane)
   TP (tangent plane)
   sky (ra, dec)
*/
