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

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

#include "pmFPA.h"
#include "pmFPAFlags.h"


/** functions to turn on/off the file_exists flag **/
bool pmFPASetFileStatus(pmFPA *fpa, bool status)
{
    PS_ASSERT_PTR_NON_NULL(fpa, false);

    for (int i = 0; i < fpa->chips->n; i++) {
        pmChip *chip = fpa->chips->data[i];
        pmChipSetFileStatus (chip, status);
    }
    return true;
}

bool pmChipSetFileStatus(pmChip *chip, bool status)
{
    PS_ASSERT_PTR_NON_NULL(chip, false);

    chip->file_exists = status;
    for (int i = 0; i < chip->cells->n; i++) {
        pmCell *cell = chip->cells->data[i];
        pmCellSetFileStatus (cell, status);
    }
    return true;
}

bool pmCellSetFileStatus(pmCell *cell, bool status)
{
    PS_ASSERT_PTR_NON_NULL(cell, false);

    cell->file_exists = status;
    for (int i = 0; i < cell->readouts->n; i++) {
        pmReadout *readout = cell->readouts->data[i];
        readout->file_exists = status;
    }
    return true;
}

bool pmFPACheckFileStatus(const pmFPA *fpa)
{
    PS_ASSERT_PTR_NON_NULL(fpa, false);

    for (int i = 0; i < fpa->chips->n; i++) {
        pmChip *chip = fpa->chips->data[i];
        if (!pmChipCheckFileStatus(chip)) {
            return false;
        }
    }
    return true;
}

bool pmChipCheckFileStatus(const pmChip *chip)
{
    PS_ASSERT_PTR_NON_NULL(chip, false);
    if (!chip->file_exists) {
        return false;
    }

    for (int i = 0; i < chip->cells->n; i++) {
        pmCell *cell = chip->cells->data[i];
        if (!pmCellCheckFileStatus(cell)) {
            return false;
        }
    }
    return true;
}

bool pmCellCheckFileStatus(const pmCell *cell)
{
    PS_ASSERT_PTR_NON_NULL(cell, false);
    if (!cell->file_exists) {
        return false;
    }

    for (int i = 0; i < cell->readouts->n; i++) {
        pmReadout *readout = cell->readouts->data[i];
        if (!readout->file_exists) {
            return false;
        }
    }
    return true;
}

/** functions to turn on/off the data_exists flag **/
bool pmFPASetDataStatus(pmFPA *fpa, bool status)
{
    PS_ASSERT_PTR_NON_NULL(fpa, false);

    for (int i = 0; i < fpa->chips->n; i++) {
        pmChip *chip = fpa->chips->data[i];
        pmChipSetDataStatus (chip, status);
    }
    return true;
}

bool pmChipSetDataStatus(pmChip *chip, bool status)
{
    PS_ASSERT_PTR_NON_NULL(chip, false);

    chip->data_exists = status;
    for (int i = 0; i < chip->cells->n; i++) {
        pmCell *cell = chip->cells->data[i];
        pmCellSetDataStatus (cell, status);
    }
    return true;
}

bool pmCellSetDataStatus (pmCell *cell, bool status)
{
    PS_ASSERT_PTR_NON_NULL(cell, false);

    cell->data_exists = status;
    for (int i = 0; i < cell->readouts->n; i++) {
        pmReadout *readout = cell->readouts->data[i];
        readout->data_exists = status;
    }
    return true;
}


// Set cells within a chip to be processed or not
static bool setCellsProcess(const pmChip *chip, // Chip of interest
                            bool process  // Process this chip?
                           )
{
    PS_ASSERT_PTR_NON_NULL(chip, false);

    psArray *cells = chip->cells;       // Component cells
    if (! cells) {
        return false;
    }
    for (int i = 0; i < cells->n; i++) {
        pmCell *tmpCell = cells->data[i]; // Cell of interest
        if (tmpCell) {
            tmpCell->process = process;
        }
    }

    return true;
}


bool pmFPASelectChip(pmFPA *fpa, int chipNum, bool exclusive)
{
    PS_ASSERT_PTR_NON_NULL(fpa, false);

    psArray *chips = fpa->chips;        // Component chips
    if ((chips == NULL) || (chipNum >= chips->n)) {
        return(false);
    }

    for (int i = 0 ; i < chips->n ; i++) {
        pmChip *tmpChip = (pmChip *) chips->data[i];
        if (tmpChip == NULL) {
            continue;
        }
        if (i == chipNum) {
            tmpChip->process = true;
            setCellsProcess(tmpChip, true);
        } else {
            if (exclusive) {
                tmpChip->process = false;
                setCellsProcess(tmpChip, false);
            }
        }

    }

    return true;
}

// XXX this function should probably be re-defined to merge with 'setCellsProcess'
bool pmChipSelectCell(pmChip *chip, int cellNum, bool exclusive)
{
    PS_ASSERT_PTR_NON_NULL(chip, false);

    psArray *cells = chip->cells;       // Component cells
    if (!cells || cellNum > cells->n) {
        return false;
    }

    for (int i = 0; i < cells->n; i++) {
        pmCell *cell = cells->data[i];
        if (!cell) {
            continue;
        }
        if (i == cellNum) {
            cell->process = true;
        } else {
            if (exclusive) {
                cell->process = false;
            }
        }
    }
    return true;
}


int pmFPAExcludeChip(pmFPA *fpa, int chipNum)
{
    PS_ASSERT_PTR_NON_NULL(fpa, -1);

    psArray *chips = fpa->chips;        // Component chips
    if (chips == NULL) {
        psLogMsg(__func__, PS_LOG_WARN, "WARNING: fpa->chips == NULL\n");
        return(0);
    }
    if ((chipNum >= chips->n) || (NULL == (pmChip *) chips->data[chipNum])) {
        psLogMsg(__func__, PS_LOG_WARN, "WARNING: the specified chip (%d) does not exist.\n", chipNum);
        return(0);
    }

    int numChips = 0;                   // Number of chips to be processed
    for (int i = 0 ; i < chips->n ; i++) {
        pmChip *tmpChip = (pmChip *) chips->data[i]; // Chip of interest
        if (tmpChip != NULL) {
            if (i == chipNum) {
                tmpChip->process = false;
                setCellsProcess(tmpChip, false); // Wipe out the cell as well
            } else if (tmpChip->process) {
                numChips++;
            }
        }
    }

    return(numChips);
}


int pmChipExcludeCell(pmChip *chip, int cellNum)
{
    PS_ASSERT_PTR_NON_NULL(chip, -1);

    psArray *cells = chip->cells;       // The component cells
    if (!cells || cellNum > cells->n) {
        return 0;
    }

    int numCells = 0;                   // Number of cells to be processed
    for (int i = 0; i < cells->n; i++) {
        pmCell *cell = cells->data[i];
        if (!cell) {
            continue;
        }
        if (i == cellNum) {
            cell->process = false;
        } else {
            numCells++;
        }
    }

    return numCells;
}

