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

#include "pmConfig.h"
#include "pmHDU.h"
#include "pmFPA.h"
#include "pmFPARead.h"
#include "pmFPAWrite.h"
#include "pmFPAMaskWeight.h"
#include "pmFPAConstruct.h"
#include "pmFPAview.h"
#include "pmFPAfile.h"
#include "pmFPAfileFitsIO.h"

// given an already-opened fits file, read the components corresponding
// to the specified view
bool pmFPAviewReadFitsImage (const pmFPAview *view, pmFPAfile *file)
{
    PS_ASSERT_PTR_NON_NULL(view, false);
    PS_ASSERT_PTR_NON_NULL(file, false);

    bool status;
    pmFPA *fpa = file->fpa;
    psFits *fits = file->fits;

    if (view->chip == -1) {
        status = pmFPARead (fpa, fits, NULL);
        return status;
    }

    if (view->chip >= fpa->chips->n) {
        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %d", view->chip, fpa->chips->n);
        return false;
    }
    pmChip *chip = fpa->chips->data[view->chip];

    if (view->cell == -1) {
        status = pmChipRead (chip, fits, NULL);
        return status;
    }

    if (view->cell >= chip->cells->n) {
        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %d", view->cell, chip->cells->n);
        return false;
    }
    pmCell *cell = chip->cells->data[view->cell];

    if (view->readout == -1) {
        status = pmCellRead (cell, fits, NULL);
        return status;
    }
    psError(PS_ERR_UNKNOWN, true, "Returning false");
    return false;

    // XXX pmReadoutRead, pmReadoutReadSegement disabled for now
    #if 0

    if (view->readout >= cell->readouts->n) {
        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouts->n == %d",
                view->readout, cell->readouts->n);
        return false;
    }
    pmReadout *readout = cell->readouts->data[view->readout];

    if (view->nRows == 0) {
        pmReadoutRead (readout, fits, NULL);
    } else {
        pmReadoutReadSegment (readout, fits, view->nRows, view->iRows, NULL, NULL);
    }
    return true;
    #endif
}

// given an already-opened fits file, write the components corresponding
// to the specified view. when the file was opened, pmFPA/Chip/CellWrite was
// called on it with blank=true to write the (possible) blank PHU
// do NOT call the functions below with blank=true or they will write
// out data in an inconsistent fashion
// the calls below should recurse down the element to write out all components.
bool pmFPAviewWriteFitsImage (const pmFPAview *view, pmFPAfile *file)
{
    PS_ASSERT_PTR_NON_NULL(view, false);
    PS_ASSERT_PTR_NON_NULL(file, false);

    pmFPA *fpa = file->fpa;
    psFits *fits = file->fits;

    // pmFPAWrite takes care of all PHUs as needed
    if (view->chip == -1) {
        pmFPAWrite(fpa, fits, NULL, false, true);
        return true;
    }

    if (view->chip >= fpa->chips->n) {
        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %d", view->chip, fpa->chips->n);
        return false;
    }
    pmChip *chip = fpa->chips->data[view->chip];

    if (view->cell == -1) {
        pmChipWrite (chip, fits, NULL, false, true);
        return true;
    }

    if (view->cell >= chip->cells->n) {
        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %d", view->cell, chip->cells->n);
        return false;
    }
    pmCell *cell = chip->cells->data[view->cell];

    if (view->readout == -1) {
        return pmCellWrite (cell, fits, NULL, false);
    }
    psError(PS_ERR_UNKNOWN, true, "Returning false");
    return false;

    // XXX disable readout write for now
    #if 0

    if (view->readout >= cell->readouts->n) {
        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouts->n == %d",
                view->readout, cell->readouts->n);
        return false;
    }
    pmReadout *readout = cell->readouts->data[view->readout];

    if (view->nRows == 0) {
        pmReadoutWrite (readout, fits, NULL, NULL);
    } else {
        pmReadoutWriteSegment (readout, fits, view->nRows, view->iRows, NULL, NULL);
    }
    return true;
    #endif
}

// this old code was used to write the blank by hand.
// pmFPAWrite now takes care of this choice.
# if 0
// do we need to write out a PHU for this entry?
if (file->phu == NULL)
    {
        pmHDU *hdu = pmFPAviewThisHDU (view, file->fpa);
        pmHDU *phu = pmFPAviewThisPHU (view, file->fpa);
        // if this hdu is the phu, the write function below will create the phu
        if (hdu != phu) {
            // we assume that the PHU is just a header
            // header may not be defined for constructed images; make a dummy one
            psMetadata *outhead = NULL;
            if (phu->header) {
                outhead = psMetadataCopy (NULL, phu->header);
            } else {
                outhead = psMetadataAlloc ();
            }
            psMetadataAdd (outhead, PS_LIST_TAIL, "EXTEND", PS_DATA_BOOL | PS_META_REPLACE, "this file has extensions", true);
            psFitsWriteBlank (file->fits, outhead);
            file->phu = phu->header;
            psTrace ("pmFPAfile", 5, "wrote phu %s (type: %d)\n", file->filename, file->type);
            psFree (outhead);
        }
    }
# endif

// given an already-opened fits file, read the components corresponding
// to the specified view
bool pmFPAviewFreeFitsImage (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) {
        psTrace ("pmFPAfile", 5, "freeing fpa for %s\n", file->filename);
        pmFPAFreeData (fpa);
        // XXX drop me: file->fpa = NULL;
        return true;
    }

    if (view->chip >= fpa->chips->n) {
        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %d", view->chip, fpa->chips->n);
        return false;
    }
    pmChip *chip = fpa->chips->data[view->chip];

    if (view->cell == -1) {
        psTrace ("pmFPAfile", 5, "freeing chip %d for %s\n", view->chip, file->filename);
        pmChipFreeData (chip);
        return true;
    }

    if (view->cell >= chip->cells->n) {
        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %d", view->cell, chip->cells->n);
        return false;
    }
    pmCell *cell = chip->cells->data[view->cell];

    if (view->readout == -1) {
        psTrace ("pmFPAfile", 5, "freeing cell %d for %s\n", view->cell, file->filename);
        pmCellFreeData (cell);
        return true;
    }
    psError(PS_ERR_UNKNOWN, true, "Returning false");
    return false;

    // XXX pmReadoutRead, pmReadoutReadSegement disabled for now
    #if 0

    if (view->readout >= cell->readouts->n) {
        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouts->n == %d",
                view->readout, cell->readouts->n);
        return false;
    }
    pmReadout *readout = cell->readouts->data[view->readout];

    if (view->nRows == 0) {
        pmReadoutRead (readout, fits, NULL);
    } else {
        pmReadoutReadSegment (readout, fits, view->nRows, view->iRows, NULL, NULL);
    }
    return true;
    #endif
}

