# include "psphotInternal.h"

pmReadout *psphotSelectBackground (pmConfig *config,
                                   const pmFPAview *view,
                                   const bool stdev // return background's standard deviation?
                                   ) {

    bool status;
    pmReadout *background;

    pmFPAfile *file = psMetadataLookupPtr (&status, config->files, "PSPHOT.BACKMDL");
    if (!file) return NULL;
    if (file->mode == PM_FPA_MODE_INTERNAL) {
        background = file->readout;
    } else {
        background = pmFPAviewThisReadout (view, file->fpa);
    }
    return background;
}

// XXX replace this with a call to a pmConfig function (pmConfigDump...)
bool psphotDumpConfig (pmConfig *config) {

  psMetadataConfigWrite (config->user, "user.md");
  psMetadataConfigWrite (config->camera, "camera.md");
  psMetadataConfigWrite (config->recipes, "recipes.md");
  psMetadataConfigWrite (config->arguments, "arguments.md");
  psMetadataConfigWrite (config->files, "files.md");
  return true;
}

int psphotSaveImage (psMetadata *header, psImage *image, char *filename) {

    psFits *fits = psFitsOpen (filename, "w");
    psFitsWriteImage (fits, NULL, image, 0, NULL);
    psFitsClose (fits);
    return (TRUE);
}

bool psphotDumpMoments (psMetadata *recipe, psArray *sources) {

    bool status;

    // optional dump of all rough source data
    char *output = psMetadataLookupStr (&status, recipe, "MOMENTS_OUTPUT_FILE");
    if (!output) return false;
    if (output[0] == 0) return false;
    if (!strcasecmp (output, "NONE")) return false;

    pmMomentsWriteText (sources, output);
    return true;
}

bool psphotDumpSource (pmSource *source, char *name) {

    FILE *f = fopen (name, "w");
    if (f == NULL) psAbort("can't open file");

    for (int i = 0; i < source->pixels->numRows; i++) {
        for (int j = 0; j < source->pixels->numCols; j++) {
            // skip masked points
            if (source->maskObj->data.U8[i][j]) {
                continue;
            }
            // skip zero-weight points
            if (source->weight->data.F32[i][j] == 0) {
                continue;
            }

            fprintf (f, "%d %d %f %f %d\n",
                     (j + source->pixels->col0),
                     (i + source->pixels->row0),
                     source->pixels->data.F32[i][j],
                     1.0 / source->weight->data.F32[i][j],
                     source->maskObj->data.U8[i][j]);
        }
    }
    fclose (f);
    return true;
}

bool psphotAddPhotcode (psMetadata *recipe, pmConfig *config, const pmFPAview *view, const char *filerule) {

    bool status;

    pmFPAfile *input = psMetadataLookupPtr (&status, config->files, filerule);
    PS_ASSERT (status, false);

    // determine PHOTCODE from fpa & view, overwrite in recipe
    char *photcode = pmConceptsPhotcodeForView (input, view);
    PS_ASSERT (photcode, false);

    psMetadataAddStr (recipe, PS_LIST_TAIL, "PHOTCODE", PS_META_REPLACE, "photcode from FPA concepts", photcode);
    psLogMsg ("psphot", 3, "PHOTCODE is %s", photcode);

    psFree (photcode);
    return true;
}

bool psphotSetHeaderNstars (psMetadata *recipe, psArray *sources) {

    int nSrc = 0;

    // count the number of sources which will be written
    for (int i = 0; (sources != NULL) && (i < sources->n); i++) {
        pmSource *source = (pmSource *) sources->data[i];
        pmModel *model = pmSourceGetModel (NULL, source);
        if (model == NULL)
            continue;
        nSrc ++;
    }
    psMetadataAdd (recipe, PS_LIST_TAIL, "NSTARS", PS_DATA_S32 | PS_META_REPLACE, "NUMBER OF STARS", nSrc);
    return true;
}

// these values are saved in an output header stub - they are added to either the
// PHU header (CMP) or the MEF table header (CMF)
psMetadata *psphotDefineHeader (psMetadata *recipe) {

    psMetadata *header = psMetadataAlloc ();

    // write necessary information to output header
    psMetadataItemSupplement (header, recipe, "ZERO_PT");
    psMetadataItemSupplement (header, recipe, "PHOTCODE");

    psMetadataItemSupplement (header, recipe, "APMIFIT");
    psMetadataItemSupplement (header, recipe, "DAPMIFIT");
    psMetadataItemSupplement (header, recipe, "NAPMIFIT");
    psMetadataItemSupplement (header, recipe, "SKYBIAS");
    psMetadataItemSupplement (header, recipe, "SKYSAT");

    // PSF model parameters (shape values for image center)
    psMetadataItemSupplement (header, recipe, "NPSFSTAR");
    psMetadataItemSupplement (header, recipe, "APLOSS");
    psMetadataItemSupplement (header, recipe, "FWHM_X");
    psMetadataItemSupplement (header, recipe, "FWHM_Y");
    psMetadataItemSupplement (header, recipe, "ANGLE");

    // XXX these need to be defined from elsewhere
    psMetadataAdd (header, PS_LIST_TAIL, "FSATUR",   PS_DATA_F32 | PS_META_REPLACE, "SATURATION MAG",      0.0);
    psMetadataAdd (header, PS_LIST_TAIL, "FLIMIT",   PS_DATA_F32 | PS_META_REPLACE, "COMPLETENESS MAG",    0.0);
    psMetadataItemSupplement (header, recipe, "NSTARS");

    // sky background model statistics
    psMetadataItemSupplement (header, recipe, "MSKY_MN");
    psMetadataItemSupplement (header, recipe, "MSKY_SIG");
    psMetadataItemSupplement (header, recipe, "MSKY_MIN");
    psMetadataItemSupplement (header, recipe, "MSKY_MAX");
    psMetadataItemSupplement (header, recipe, "MSKY_NX");
    psMetadataItemSupplement (header, recipe, "MSKY_NY");

    psMetadataAddF32 (header, PS_LIST_TAIL, "DT_PHOT", PS_META_REPLACE, "elapsed psphot time", psTimerMark ("psphotReadout"));

    // XXX : don't require any of these about values to exist
    psErrorClear ();

    return header;
}
