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

#include <pslib.h>

#include "pmReadoutStack.h"


bool pmReadoutUpdateSize(pmReadout *readout, int minCols, int minRows,
                         int numCols, int numRows, bool mask)
{
    PS_ASSERT_PTR_NON_NULL(readout, false);

    if (readout->image) {
        *(psS32*) &(readout->col0) = PS_MIN(minCols, readout->col0);
        *(psS32*) &(readout->row0) = PS_MIN(minRows, readout->row0);
    } else {
        *(psS32*) &(readout->col0) = minCols;
        *(psS32*) &(readout->row0) = minRows;
    }

    // (reAllocate the images
    if (!readout->image) {
        readout->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
    }
    if (readout->image->numCols < numCols || readout->image->numRows < numRows) {
        // Generate the new output image by extending the current one, or making a whole new one
        psImage *newImage = psImageAlloc(numCols, numRows, PS_TYPE_F32);
        psImageInit(newImage, 0.0);
        psImageOverlaySection(newImage, readout->image, readout->col0, readout->row0, "=");
        psFree(readout->image);
        readout->image = newImage;
    }

    if (mask) {
        if (!readout->mask) {
            readout->mask = psImageAlloc(numCols, numRows, PS_TYPE_MASK);
        }
        if (readout->mask->numCols < numCols || readout->mask->numRows < numRows) {
            psImage *newMask = psImageAlloc(numCols, numRows, PS_TYPE_MASK);
            psImageInit(newMask, 0);
            psImageOverlaySection(newMask, readout->mask, readout->col0, readout->row0, "=");
            psFree(readout->mask);
            readout->mask = newMask;
        }
    }

    return true;
}

bool pmReadoutStackValidate(int *minInputColsPtr, int *maxInputColsPtr, int *minInputRowsPtr,
                            int *maxInputRowsPtr, int *numColsPtr, int *numRowsPtr, 
                            const psArray *inputs)
{
    PS_ASSERT_ARRAY_NON_NULL(inputs, false);
    PS_ASSERT_PTR_NON_NULL(minInputColsPtr, false);
    PS_ASSERT_PTR_NON_NULL(maxInputColsPtr, false);
    PS_ASSERT_PTR_NON_NULL(minInputRowsPtr, false);
    PS_ASSERT_PTR_NON_NULL(maxInputRowsPtr, false);
    PS_ASSERT_PTR_NON_NULL(numColsPtr, false);
    PS_ASSERT_PTR_NON_NULL(numRowsPtr, false);

    // Step through each readout in the input image list to determine how big of an output image is needed to
    // combine these input images.
    int maxInputCols = 0;               // The largest input column value
    int maxInputRows = 0;               // The largest input row value
    int minInputCols = INT_MAX;         // The smallest input column value
    int minInputRows = INT_MAX;         // The smallest input row value
    int xSize = 0, ySize = 0;           // The size of the output image

    int xMin = INT_MAX;
    int yMin = INT_MAX;
    int xMax = 0;
    int yMax = 0;

    bool valid = false;                 // Do we have a single valid input?
    for (long i = 0; i < inputs->n; i++) {
        pmReadout *readout = inputs->data[i]; // Readout of interest

        if (!readout || !readout->image) {
            psError(PS_ERR_UNEXPECTED_NULL, true, "Input readout %ld is NULL or has NULL image.\n", i);
            return false;
        }

        // use the trimsec to define the max full range of the output pixels
        pmCell *cell = readout->parent; // The parent cell
        bool mdok = true;       // Status of MD lookup
        psRegion *trimsec = psMetadataLookupPtr(&mdok, cell->concepts, "CELL.TRIMSEC"); // Trim section
        if (!mdok || !trimsec || psRegionIsNaN(*trimsec)) {
            psWarning("CELL.TRIMSEC is not set for readout %ld --- ignored.\n", i);
        } else {
            xSize = PS_MAX(xSize, trimsec->x1 - trimsec->x0);
            ySize = PS_MAX(ySize, trimsec->y1 - trimsec->y0);
            xMin  = PS_MIN(xMin,  trimsec->x0);
            xMax  = PS_MAX(xMax,  trimsec->x1);
            yMin  = PS_MIN(yMin,  trimsec->y0);
            yMax  = PS_MAX(yMax,  trimsec->y1);
        }

        valid = true;

        // Range of pixels on output images
        minInputCols = PS_MAX(xMin, PS_MIN(minInputCols, readout->col0));
        maxInputCols = PS_MIN(xMax, PS_MAX(maxInputCols, readout->col0 + readout->image->numCols));
        minInputRows = PS_MAX(yMin, PS_MIN(minInputRows, readout->row0));
        maxInputRows = PS_MIN(yMax, PS_MAX(maxInputRows, readout->row0 + readout->image->numRows));
        psTrace("psModules.camera", 7, "Readout %ld: offset %d,%d; size %dx%d\n", i,
                readout->col0, readout->row0, readout->image->numCols, readout->image->numRows);
    }

    if (minInputColsPtr) {
        *minInputColsPtr = minInputCols;
    }
    if (maxInputColsPtr) {
        *maxInputColsPtr = maxInputCols;
    }
    if (minInputRowsPtr) {
        *minInputRowsPtr = minInputRows;
    }
    if (maxInputRowsPtr) {
        *maxInputRowsPtr = maxInputRows;
    }
    if (numColsPtr) {
        *numColsPtr = xSize;
    }
    if (numRowsPtr) {
        *numRowsPtr = ySize;
    }

    return valid;
}
