/** @file  pmFPAview.c
 *
 *  @author EAM, IfA
 *
 *  @version $Revision: 1.1.2.6 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2006-03-29 20:55:42 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 *
 */

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

static void pmFPAviewFree (pmFPAview *view)
{
    if (view == NULL)
        return;
    return;
}

pmFPAview *pmFPAviewAlloc (int nRows)
{
    pmFPAview *view = psAlloc (sizeof(pmFPAview));
    psMemSetDeallocator (view, (psFreeFunc) pmFPAviewFree);

    view->chip    = -1;
    view->cell    = -1;
    view->readout = -1;
    view->iRows   =  0;
    view->nRows   = nRows;
    return (view);
}

pmFPAdepth pmFPAviewDepth (const pmFPAview *view)
{

    if (view->chip < 0) {
        return PM_FPA_DEPTH_FPA;
    }
    if (view->cell < 0) {
        return PM_FPA_DEPTH_CHIP;
    }
    if (view->readout < 0) {
        return PM_FPA_DEPTH_CELL;
    }
    return PM_FPA_DEPTH_READOUT;
}

pmChip *pmFPAviewThisChip (const pmFPAview *view, pmFPA *fpa)
{

    if (view->chip < 0) {
        return NULL;
    }

    if (view->chip >= fpa->chips->n) {
        return NULL;
    }

    pmChip *chip = fpa->chips->data[view->chip];
    return chip;
}

pmChip *pmFPAviewNextChip (pmFPAview *view, pmFPA *fpa, int nStep)
{
    view->cell = -1;
    view->readout = -1;
    view->iRows = 0;

    // if there are no available chips, return NULL
    if (fpa->chips->n <= 0) {
        view->chip = -1;
        return NULL;
    }

    // clean up < -1 values
    if (view->chip < -1) {
        view->chip = -1;
    }

    // increment to the next chip
    view->chip += nStep;

    // if we are at the end of the stack, return NULL
    if (view->chip >= fpa->chips->n) {
        view->chip = -1;
        return NULL;
    }

    // get the correct chip pointer
    pmChip *chip = fpa->chips->data[view->chip];
    return (chip);
}

pmCell *pmFPAviewThisCell (const pmFPAview *view, pmFPA *fpa)
{

    if (view->cell < 0) {
        return NULL;
    }

    pmChip *chip = pmFPAviewThisChip (view, fpa);
    if (chip == NULL) {
        return NULL;
    }

    if (view->cell >= chip->cells->n) {
        return NULL;
    }

    pmCell *cell = chip->cells->data[view->cell];
    return cell;
}

pmCell *pmFPAviewNextCell (pmFPAview *view, pmFPA *fpa, int nStep)
{

    pmChip *chip = pmFPAviewThisChip (view, fpa);
    if (chip == NULL) {
        return NULL;
    }

    view->readout = -1;
    view->iRows = 0;

    // if there are no available cells, return NULL
    if (chip->cells->n <= 0) {
        view->cell = -1;
        return NULL;
    }

    // clean up < -1 values
    if (view->cell < -1) {
        view->cell = -1;
    }

    // increment to the next cell
    view->cell += nStep;

    // if we are at the end of the stack, return NULL
    if (view->cell >= chip->cells->n) {
        view->cell = -1;
        return NULL;
    }

    // get the correct cell pointer
    pmCell *cell = chip->cells->data[view->cell];
    return (cell);
}

pmReadout *pmFPAviewThisReadout (const pmFPAview *view, pmFPA *fpa)
{

    if (view->readout < 0) {
        return NULL;
    }

    pmCell *cell = pmFPAviewThisCell (view, fpa);
    if (cell == NULL) {
        return NULL;
    }

    if (view->readout >= cell->readouts->n) {
        return NULL;
    }

    pmReadout *readout = cell->readouts->data[view->readout];
    return readout;
}

pmReadout *pmFPAviewNextReadout (pmFPAview *view, pmFPA *fpa, int nStep)
{

    pmCell *cell = pmFPAviewThisCell (view, fpa);
    if (cell == NULL) {
        return NULL;
    }

    view->iRows = 0;

    // if there are no available cells, return NULL
    if (cell->readouts->n <= 0) {
        view->readout = -1;
        return NULL;
    }

    // clean up < -1 values
    if (view->readout < -1) {
        view->readout = -1;
    }

    // increment to the next cell
    view->readout += nStep;

    // if we are at the end of the stack, return NULL
    if (view->readout >= cell->readouts->n) {
        view->readout = -1;
        return NULL;
    }

    // get the correct cell pointer
    pmReadout *readout = cell->readouts->data[view->readout];
    return (readout);
}

pmHDU *pmFPAviewThisHDU (const pmFPAview *view, pmFPA *fpa)
{
    // the HDU is attached to a cell, chip or fpa
    // if this view has a -1 for the level which contains the hdu,
    // there is no unambiguous HDU

    if (view->chip < 0) {
        return pmHDUFromFPA (fpa);
    }
    if (view->cell < 0) {
        return pmHDUFromChip (pmFPAviewThisChip (view, fpa));
    }
    if (view->readout < 0) {
        return pmHDUFromCell (pmFPAviewThisCell (view, fpa));
    }
    return NULL;
}

pmHDU *pmFPAviewThisPHU (const pmFPAview *view, pmFPA *fpa)
{
    // select the HDU which corresponds to the PHU containing this view

    pmHDU *hdu;
    pmFPAview new;
    pmChip *chip;
    pmCell *cell;

    new = *view;

    if (view->chip < 0) {
        hdu = pmHDUFromFPA (fpa);
        if (hdu->phu)
            return hdu;
        return NULL;
    }
    if (view->cell < 0) {
        chip = pmFPAviewThisChip (view, fpa);
        hdu  = pmHDUFromChip (chip);
        if (hdu->phu)
            return hdu;
        new.chip = -1;
        hdu = pmFPAviewThisPHU (&new, fpa);
        return hdu;
    }
    if (view->readout < 0) {
        cell = pmFPAviewThisCell (view, fpa);
        hdu  = pmHDUFromCell (cell);
        if (hdu->phu)
            return hdu;
        new.cell = -1;
        hdu = pmFPAviewThisPHU (&new, fpa);
        return hdu;
    }
    return NULL;
}
