/** @file  pmSourceIO.c
 *
 *  @author EAM, IfA
 *
 *  @version $Revision: 1.1.2.7 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2006-04-17 17:10:08 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 *
 */

#include <stdio.h>
#include <math.h>
#include <string.h>
#include "pslib.h"
#include "psEllipse.h"
#include "pmHDU.h"
#include "pmFPA.h"
#include "pmFPAview.h"
#include "pmFPAfile.h"

#include "pmPeaks.h"
#include "pmMoments.h"
#include "pmGrowthCurve.h"
#include "pmModel.h"
#include "pmPSF.h"
#include "pmSource.h"
#include "pmModelGroup.h"
#include "pmSourceIO.h"

// elixir-style FITS table output (header + table in 1st extension)
// this format consists of a header derived from the image header
// followed by a zero-size matrix, followed by the table data
bool pmSourcesWriteCMF (psFits *fits, psArray *sources, psMetadata *header, char *extname)
{

    psArray *table;
    psMetadata *row;
    int i, type;
    psF32 *PAR, *dPAR;
    float lsky;
    bool status;
    psEllipseShape shape;
    psEllipseAxes axes;

    // find config information for output header
    float ZERO_POINT = psMetadataLookupF32 (&status, header, "ZERO_PT");

    table = psArrayAlloc (sources->n);
    table->n = 0;

    for (i = 0; i < sources->n; i++) {
        pmSource *source = (pmSource *) sources->data[i];
        pmModel *model = pmSourceSelectModel (source);
        if (model == NULL)
            continue;

        PAR = model->params->data.F32;
        dPAR = model->dparams->data.F32;

        type = pmSourceDophotType (source);
        lsky = (PAR[0] < 1.0) ? 0.0 : log10(PAR[0]);

        shape.sx  = PAR[4];
        shape.sy  = PAR[5];
        shape.sxy = PAR[6];
        axes = psEllipseShapeToAxes (shape);

        row = psMetadataAlloc ();
        psMetadataAdd (row, PS_LIST_TAIL, "X_PIX",   PS_DATA_F32, "", PAR[2]);
        psMetadataAdd (row, PS_LIST_TAIL, "Y_PIX",   PS_DATA_F32, "", PAR[3]);
        psMetadataAdd (row, PS_LIST_TAIL, "MAG_RAW", PS_DATA_F32, "", PS_MIN (99.0, source->psfMag + ZERO_POINT));
        psMetadataAdd (row, PS_LIST_TAIL, "MAG_GAL", PS_DATA_F32, "", PS_MIN (99.0, source->extMag + ZERO_POINT));
        psMetadataAdd (row, PS_LIST_TAIL, "MAG_AP",  PS_DATA_F32, "", PS_MIN (99.0, source->apMag + ZERO_POINT));
        psMetadataAdd (row, PS_LIST_TAIL, "MAG_ERR", PS_DATA_F32, "", PS_MIN (999, 1000*source->errMag));
        psMetadataAdd (row, PS_LIST_TAIL, "LOG_SKY", PS_DATA_F32, "", lsky);
        psMetadataAdd (row, PS_LIST_TAIL, "FWHM_X",  PS_DATA_F32, "", axes.major);
        psMetadataAdd (row, PS_LIST_TAIL, "FWHM_Y",  PS_DATA_F32, "", axes.minor);
        psMetadataAdd (row, PS_LIST_TAIL, "THETA",   PS_DATA_F32, "", axes.theta);
        psMetadataAdd (row, PS_LIST_TAIL, "DOPHOT",  PS_DATA_U8,  "", type);
        psMetadataAdd (row, PS_LIST_TAIL, "WEIGHT",  PS_DATA_U8,  "", PS_MIN (255, PS_MAX(0, 255*source->pixWeight)));
        psMetadataAdd (row, PS_LIST_TAIL, "DUMMY",   PS_DATA_STRING, "", "12");

        psArrayAdd (table, 100, row);
        psFree (row);
    }

    // create the basic table header
    psMetadataAdd (header, PS_LIST_HEAD, "EXTNAME", PS_DATA_STRING | PS_META_REPLACE, "extension name", extname);

    // XXX this is broken : does not write the existing header elements except EXTNAME
    psFitsWriteTable (fits, header, table);
    psTrace ("pmFPAfile", 5, "wrote ext data %s\n", extname);

    psFree (table);
    return true;
}

// read in a readout from the fits file
psArray *pmSourcesReadCMF (psFits *fits, psMetadata *header)
{

    bool status;
    psF32 *PAR, *dPAR;
    psEllipseShape shape;
    psEllipseAxes axes;
    float lsky;

    // define PSF model type
    int modelType = pmModelSetType ("PS_MODEL_GAUSS");

    char *PSF_NAME = psMetadataLookupStr (&status, header, "PSF_NAME");
    if (PSF_NAME != NULL) {
        modelType = pmModelSetType (PSF_NAME);
    }

    // find config information for output header
    float ZERO_POINT = psMetadataLookupF32 (&status, header, "ZERO_PT");
    if (!status)
        ZERO_POINT = 25.0;

    psArray *table = psFitsReadTable (fits);
    // validate a single row of the table (must match SMP)

    psArray *sources = psArrayAlloc (table->n);

    // convert the table to the pmSource entries
    // XXX need to chooose PSF vs EXT, based on type?
    for (int i = 0; i < table->n; i++) {
        pmSource *source = pmSourceAlloc ();
        pmModel *model = pmModelAlloc (modelType);
        source->modelPSF  = model;

        PAR = model->params->data.F32;
        dPAR = model->dparams->data.F32;

        psMetadata *row = table->data[i];

        lsky           = psMetadataLookupF32 (&status, row, "LOG_SKY");
        PAR[0]         = pow(lsky, 10.0);
        PAR[2]         = psMetadataLookupF32 (&status, row, "X_PIX");
        PAR[3]         = psMetadataLookupF32 (&status, row, "Y_PIX");
        axes.major     = psMetadataLookupF32 (&status, row, "FWHM_X");
        axes.minor     = psMetadataLookupF32 (&status, row, "FWHM_Y");
        axes.theta     = psMetadataLookupF32 (&status, row, "THETA");

        shape = psEllipseAxesToShape (axes);

        PAR[4] = shape.sx;
        PAR[5] = shape.sy;
        PAR[6] = shape.sxy;

        source->psfMag = psMetadataLookupF32 (&status, row, "MAG_RAW") - ZERO_POINT;
        source->extMag = psMetadataLookupF32 (&status, row, "MAG_GAL") - ZERO_POINT;
        source->errMag = psMetadataLookupF32 (&status, row, "MAG_ERR");
        source->apMag  = psMetadataLookupF32 (&status, row, "MAG_AP")  - ZERO_POINT;

        sources->data[i] = source;
    }
    return (sources);
}
