# include "ppMerge.h"

ppMergeFileGroup *ppMergeReadChunk (bool *status, psArray *fileGroups, pmConfig *config, int numChunk) {

    *status = true;

    bool mdok;
    bool haveMasks = psMetadataLookupBool(&mdok, config->arguments, "INPUTS.MASKS"); // Do we have masks?
    bool haveWeights = psMetadataLookupBool(&mdok, config->arguments, "INPUTS.WEIGHTS"); // Do we have weights?
    int rows = psMetadataLookupS32(NULL, config->arguments, "ROWS"); // Number of rows to read per chunk

    // select an available fileGroup
    while (1) {
	// check for any fileGroups which can read data
	for (int j = 0; j < fileGroups->n; j++) {
	    ppMergeFileGroup *fileGroup = fileGroups->data[j];
	    if (fileGroup->read) continue;

	    // find max last scan so far
	    int lastScan = 0;
	    for (int i = 0; i < fileGroups->n; i++) {
		ppMergeFileGroup *fileGroup = fileGroups->data[i];
		lastScan = PS_MAX (fileGroup->lastScan, lastScan);
	    }
	    fileGroup->firstScan = lastScan;
	    fileGroup->lastScan = lastScan + rows;

	    psArray *readouts = fileGroup->readouts;

	    psTimerStart ("ppMergeReadChunk");

	    psTrace("ppStack", 2, "Reading data for chunk %d into fileGroup %d....n", numChunk, j);
	    for (int i = 0; i < readouts->n; i++) {
		pmReadout *inRO = readouts->data[i]; // Input readout

		// override the recorded last scan
		inRO->thisImageScan  = fileGroup->firstScan;
		inRO->thisWeightScan = fileGroup->firstScan;
		inRO->thisMaskScan   = fileGroup->firstScan;

		// Read a chunk from a file
		pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPMERGE.INPUT", i); 

		bool keepReading = false;
		if (pmReadoutMore(inRO, file->fits, 0, rows, config)) {
		    keepReading = true;
		    if (!pmReadoutReadChunk(inRO, file->fits, 0, rows, 0, config)) { 
			psError(PS_ERR_IO, false, "Unable to read chunk %d for file PPMERGE.INPUT %d", numChunk, i);
			*status = false;
			return NULL;
		    }							
		}

		if (haveMasks && pmReadoutMoreMask(inRO, file->fits, 0, rows, config)) {
		    keepReading = true;
		    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPMERGE.INPUT.MASK", i); 
		    if (!pmReadoutReadChunkMask(inRO, file->fits, 0, rows, 0, config)) { 
			psError(PS_ERR_IO, false, "Unable to read chunk %d for file PPMERGE.INPUT.MASK %d", numChunk, i);
			*status = false;
			return NULL;
		    }							
		}

		if (haveWeights && pmReadoutMoreWeight(inRO, file->fits, 0, rows, config)) {
		    keepReading = true;
		    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPMERGE.INPUT.WEIGHT", i); 
		    if (!pmReadoutReadChunkWeight(inRO, file->fits, 0, rows, 0, config)) {
			psError(PS_ERR_IO, false, "Unable to read chunk %d for file PPMERGE.INPUT.WEIGHT %d", numChunk, i);
			*status = false;
			return NULL;
		    }							
		}
		if (!keepReading) {
		    return NULL;
		}
	    }

	    fileGroup->read = fileGroup->busy = true;
	    return fileGroup;
	}

	// check for any fileGroups which are done processing
	bool wait = false;
	for (int j = 0; j < fileGroups->n; j++) {
	    ppMergeFileGroup *fileGroup = fileGroups->data[j];
	    if (!fileGroup->read || fileGroup->busy) continue;
	    fileGroup->read = false;
	    wait = true;
	}
	if (wait) usleep (10000);
    }
    return NULL;
}
