/** @file  pmFPA_JPEG.c
 *
 * This file contains functions to write JPEG images.
 *
 *  @author EAM, IfA
 *
 *  @version $Revision: 1.9 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2006-09-25 20:23:10 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*****************************************************************************/
/* INCLUDE FILES                                                             */
/*****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <pslib.h>

#include "pmHDU.h"
#include "pmFPA.h"
#include "pmFPAfile.h"
#include "pmFPAview.h"
#include "pmFPA_JPEG.h"


bool pmFPAviewWriteJPEG(const pmFPAview *view, pmFPAfile *file)
{
    PS_ASSERT_PTR_NON_NULL(view, false);
    PS_ASSERT_PTR_NON_NULL(file, false);

    pmFPA *fpa = file->fpa;

    if (view->chip == -1) {
        pmFPAWriteJPEG (fpa, view, file);
        return true;
    }

    if (view->chip >= fpa->chips->n) {
        return false;
    }
    pmChip *chip = fpa->chips->data[view->chip];

    if (view->cell == -1) {
        pmChipWriteJPEG (chip, view, file);
        return true;
    }

    if (view->cell >= chip->cells->n) {
        return false;
    }
    pmCell *cell = chip->cells->data[view->cell];

    if (view->readout == -1) {
        pmCellWriteJPEG (cell, view, file);
        return true;
    }

    if (view->readout >= cell->readouts->n) {
        return false;
    }
    pmReadout *readout = cell->readouts->data[view->readout];

    pmReadoutWriteJPEG (readout, view, file);
    return true;
}

// read in all chip-level JPEG files for this FPA
bool pmFPAWriteJPEG (pmFPA *fpa, const pmFPAview *view, pmFPAfile *file)
{
    PS_ASSERT_PTR_NON_NULL(fpa, false);
    PS_ASSERT_PTR_NON_NULL(view, false);
    PS_ASSERT_PTR_NON_NULL(file, false);

    for (int i = 0; i < fpa->chips->n; i++) {

        pmChip *chip = fpa->chips->data[i];
        pmChipWriteJPEG (chip, view, file);
    }
    return true;
}

// read in all cell-level JPEG files for this chip
bool pmChipWriteJPEG (pmChip *chip, const pmFPAview *view, pmFPAfile *file)
{
    PS_ASSERT_PTR_NON_NULL(chip, false);
    PS_ASSERT_PTR_NON_NULL(view, false);
    PS_ASSERT_PTR_NON_NULL(file, false);

    for (int i = 0; i < chip->cells->n; i++) {

        pmCell *cell = chip->cells->data[i];
        pmCellWriteJPEG (cell, view, file);
    }
    return true;
}

// read in all readout-level JPEG files for this cell
bool pmCellWriteJPEG (pmCell *cell, const pmFPAview *view, pmFPAfile *file)
{
    PS_ASSERT_PTR_NON_NULL(cell, false);
    PS_ASSERT_PTR_NON_NULL(view, false);
    PS_ASSERT_PTR_NON_NULL(file, false);

    for (int i = 0; i < cell->readouts->n; i++) {

        pmReadout *readout = cell->readouts->data[i];
        pmReadoutWriteJPEG (readout, view, file);
    }
    return true;
}

// read in all readout-level Objects files for this cell
bool pmReadoutWriteJPEG (pmReadout *readout, const pmFPAview *view, pmFPAfile *file)
{
    PS_ASSERT_PTR_NON_NULL(readout, false);
    PS_ASSERT_PTR_NON_NULL(view, false);
    PS_ASSERT_PTR_NON_NULL(file, false);

    switch (file->type) {
    case PM_FPA_FILE_JPEG: {
            // XXX we need to decide where the scale will come from in the long term
            psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS, 0);
            psStats *stats = psImageBackground(readout->image, NULL, 0, 0.25, 0.75, 10000, rng);
            psFree(rng);

            if (!isfinite(stats->robustMedian) || !isfinite(stats->robustUQ) || !isfinite(stats->robustLQ)) {
                psError(PS_ERR_UNKNOWN, false, "Unable to measure statistics for image.\n");
                psFree(stats);
                return false;
            }
            float delta = stats->robustUQ - stats->robustLQ; // Inter-quartile range
            float min, max;                 // Minimum and maximum for stretch

            psString mode = pmFPAfileNameFromRule (file->extrule, file, view);
            psString word = pmFPAfileNameFromRule (file->extxtra, file, view);
            psArray *range = psStringSplitArray (word, ":", false);

            if (!strcasecmp (mode, "RANGE") && range) {
                float fmin = atof(range->data[0]);
                float fmax = atof(range->data[1]);
                min = stats->robustMedian + fmin*delta;
                max = stats->robustMedian + fmax*delta;
            } else if (!strcasecmp (mode, "FRACTION")) {
                float fmin = atof(range->data[0]);
                float fmax = atof(range->data[1]);
                min = fmin*stats->robustMedian;
                max = fmax*stats->robustMedian;
            } else {
                min = stats->robustMedian - 3*delta;
                max = stats->robustMedian + 6*delta;
            }
            psFree(mode);
            psFree(word);
            psFree(range);
            psFree(stats);

            if (!isfinite(min) || !isfinite(max)) {
                psError(PS_ERR_UNKNOWN, true, "The stretch parameters are not both finite.\n");
                return false;
            }

            psString name = pmFPAfileNameFromRule (file->filerule, file, view);
            psString mapname = pmFPAfileNameFromRule (file->filextra, file, view);
            psImageJpegColormap *map = psImageJpegColormapSet (NULL, mapname);
            psFree(mapname);
            if (!map) {
                map = psImageJpegColormapSet (NULL, "-greyscale");
            }

            psImageJpeg (map, readout->image, name, min, max);
            psFree(name);
            psFree(map);

            return true;
        }
    default:
        fprintf (stderr, "warning: type mismatch\n");
        break;
    }
    return false;
}
