/** @file censorLoop.c
 *
 *  @ingroup censor
 *
 *  @author IfA
 *  @version $Revision: 1.12 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2009-02-07 02:03:34 $
 *  Copyright 2009 Institute for Astronomy, University of Hawaii
 */

# include "censor.h"

# define ESCAPE { \
  psError(PS_ERR_UNKNOWN, false, "Failure in censorLoop"); \
  psFree (view); \
  return false; \
}
  
/**
 * \brief this loop loads the data from the input smf file(s) and mask(s).  call censorReadout
 * to perform the actual rejection.
 */
bool censorLoop (pmConfig *config) {
    pmChip *chip;
    pmCell *cell;
    pmReadout *readout;

    psTimerStart ("censor");




    // select the current recipe
    psMetadata *recipe  = psMetadataLookupPtr (NULL, config->recipes, CENSOR_RECIPE);
    if (!recipe) {
	psError(CENSOR_ERR_CONFIG, true, "Can't find CENSOR recipe!\n");
	return false;
    }

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

    // select the input data sources
    pmFPAfile *inMask = psMetadataLookupPtr (NULL, config->files, "CENSOR.INPUT.MASK");
    if (!inMask) {
	psError(CENSOR_ERR_CONFIG, true, "Can't find input masks!\n");
	return false;
    }

    pmFPAview *view = pmFPAviewAlloc (0);

    bool badMaskFile = false;

    // check on the mask file at this level if possible
    badMaskFile = censorBadFileByView(badMaskFile, inMask, config, view);

    // files associated with the science image
    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;

    // check PHU header to see if we are using mosaic-level or per-chip astrometry
    bool bilevelAstrometry = false;
    pmHDU *phu = pmFPAviewThisPHU (view, input->fpa);
    if (phu) {
      char *ctype = psMetadataLookupStr (NULL, phu->header, "CTYPE1");
      if (ctype) bilevelAstrometry = !strcmp (&ctype[4], "-DIS");
    }
    if (bilevelAstrometry) {
      pmAstromReadBilevelMosaic (input->fpa, phu->header);
    } 

    while ((chip = pmFPAviewNextChip (view, input->fpa, 1)) != NULL) {
	psTrace ("censor", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
	if (!chip->process || !chip->file_exists) { continue; }
	
	// check on the mask file at this level if possible
	badMaskFile = censorBadFileByView(badMaskFile, inMask, config, view);

	if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;

	// read WCS data from the corresponding header

	pmHDU *hdu = pmFPAviewThisHDU (view, input->fpa);
	
	if (bilevelAstrometry) {
	  if (!pmAstromReadBilevelChip (chip, hdu->header)) {
	    psWarning("Could not get WCS information from header for chip %d, skipping", view->chip); 
	    continue;
	  }
	} else {
	  if (!pmAstromReadWCS(input->fpa, chip, hdu->header, 1.0)) {
	    psWarning( "Unable to read WCS astrometry from chip %d, skipping", view->chip);
	    continue;
	  }
	}

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

	    // check on the mask file at this level if possible
	    badMaskFile = censorBadFileByView(badMaskFile, inMask, config, view);

	    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;

	    // process each of the readouts
	    while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {

		// check on the mask file at this level if possible
		badMaskFile = censorBadFileByView(badMaskFile, inMask, config, view);

		if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
		if (!readout->data_exists) { continue; }

		if (!censorReadout (readout, config, view, badMaskFile)) ESCAPE;

		if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
	    }
	    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
	}
	if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
    }
    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;

    psLogMsg ("censor", 3, "censorLoop done : %f sec\n", psTimerMark ("censor"));

    psFree (view);
    return true;
}

bool censorBadFileByView (bool badFile, pmFPAfile *file, pmConfig *config, pmFPAview *view) {

    // get the current level
    pmFPALevel level = pmFPAviewLevel (view);

    // can we try to open this file? (if not, leave the existing badView intact)
    if (level != file->fileLevel) return badFile;

    // free, and if needed, realloc badView below
    badFile = false;

    char *filename = pmFPAfileName(file, view, config);
    if (filename) {
	// activate the file
	pmFPAfileActivate (config->files, true, file->name);
	psFree (filename);
	return false;
    }

    // de-activate the file
    pmFPAfileActivate (config->files, false, file->name);
    return true;
}

/**
 * \brief this loop loads the data from the input smf file(s) and mask(s).  call censorReadout
 * to perform the actual rejection.
 */
bool checkInputLoop (pmConfig *config) {
    pmChip *chip;
    pmCell *cell;
    pmReadout *readout;

    psTimerStart ("checksources");

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

    pmFPAview *view = pmFPAviewAlloc (0);

    // files associated with the science image
    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;

    // check PHU header to see if we are using mosaic-level or per-chip astrometry
    bool bilevelAstrometry = false;
    pmHDU *phu = pmFPAviewThisPHU (view, input->fpa);
    if (phu) {
      char *ctype = psMetadataLookupStr (NULL, phu->header, "CTYPE1");
      if (ctype) bilevelAstrometry = !strcmp (&ctype[4], "-DIS");
    }
    if (bilevelAstrometry) {
      pmAstromReadBilevelMosaic (input->fpa, phu->header);
    } 

    while ((chip = pmFPAviewNextChip (view, input->fpa, 1)) != NULL) {
	psTrace ("checksources", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
	if (!chip->process || !chip->file_exists) { continue; }
	
	if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;

	// read WCS data from the corresponding header

	pmHDU *hdu = pmFPAviewThisHDU (view, input->fpa);
	
	if (bilevelAstrometry) {
	  if (!pmAstromReadBilevelChip (chip, hdu->header)) {
	    psWarning("Could not get WCS information from header for chip %d, skipping", view->chip); 
	    continue;
	  }
	} else {
	  if (!pmAstromReadWCS(input->fpa, chip, hdu->header, 1.0)) {
	    psWarning( "Unable to read WCS astrometry from chip %d, skipping", view->chip);
	    continue;
	  }
	}

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

	    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;

	    // process each of the readouts
	    while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {

		if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
		if (!readout->data_exists) { continue; }
                
                // select the raw objects for this readout, flag is they fall in a mask
                pmDetections *detections = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.DETECTIONS");
                if (detections == NULL) {
                    psError(CENSOR_ERR_CONFIG, true, "Can't find detections for this readout");
                    return false;
                }
                if (!detections->allSources) {
                    psError(CENSOR_ERR_CONFIG, true, "Can't find sources for this readout");
                    return false;
                }

		if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
	    }
	    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
	}
	if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
    }
    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;

    psLogMsg ("checksources", 3, "checkInputLoop done : %f sec\n", psTimerMark ("checksources"));

    psFree (view);
    return true;
}
