#include <stdio.h>
#include <string.h>
#include "pslib.h"
#include "psAdditionals.h"

#include "pmFPA.h"


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Allocators
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

pmFPA *pmFPAAlloc(const psMetadata *camera, // Camera configuration
		  psDB *db		// Database
    )
{
    pmFPA *fpa = psAlloc(sizeof(pmFPA));// The FPA
    psMemSetDeallocator(fpa, (psFreeFcn)p_pmFPAFree);

    // Fill in the components
    fpa->fromTangentPlane = NULL;
    fpa->toTangentPlane = NULL;
    fpa->projection = NULL;

    fpa->values = psMetadataAlloc();
//    fpa->camera = psMemIncrRefCounter((psPtr)camera);
    fpa->db = db;
    fpa->chips = psArrayAlloc(0);

    fpa->extname = NULL;
    fpa->pixels = NULL;
    fpa->header = NULL;

    return fpa;
}

void p_pmFPAFree(pmFPA *fpa)
{
    psFree(fpa->fromTangentPlane);
    psFree(fpa->toTangentPlane);
    psFree(fpa->projection);

    psFree(fpa->values);
    psFree((psPtr)fpa->camera);
    psFree(fpa->db);
    psFree(fpa->chips);

    psFree(fpa->pixels);
    psFree(fpa->header);
}

pmChip *pmChipAlloc(pmFPA *fpa,	// FPA to which the chip belongs
		    psString name	// Chip name
    )
{
    pmChip *chip = psAlloc(sizeof(pmChip)); // The chip
    psMemSetDeallocator(chip, (psFreeFcn)p_pmChipFree);

    // Push onto the array of chips
    fpa->chips = psArrayAdd(fpa->chips, 0, chip);

    // Fill in the components
    *(int*)&chip->col0 = 0;		// Good enough for now
    *(int*)&chip->row0 = 0;		// Good enough for now

    chip->toFPA = NULL;
    chip->fromFPA = NULL;

    chip->values = psMetadataAlloc();
//    chip->parent = psMemIncrRefCounter(fpa);
    chip->cells = psArrayAlloc(0);

    chip->extname = NULL;
    chip->pixels = NULL;
    chip->header = NULL;

    psMetadataAddStr(chip->values, PS_LIST_HEAD, "CHIP.NAME", "Chip name added at pmChipAlloc", name);

    return chip;
}

void p_pmChipFree(pmChip *chip)
{
    psFree(chip->toFPA);
    psFree(chip->fromFPA);

    psFree(chip->values);
    psFree(chip->cells);
//    psFree(chip->parent);

    psFree(chip->pixels);
    psFree(chip->header);
}

pmCell *pmCellAlloc(pmChip *chip,	// Chip to which the cell belongs
		    psMetadata *values,	// Initial values for concepts
		    psString name	// Name of cell
    )
{
    pmCell *cell = psAlloc(sizeof(pmCell)); // The cell
    psMemSetDeallocator(cell, (psFreeFcn)p_pmCellFree);

    // Push onto the array of chips
    chip->cells = psArrayAdd(chip->cells, 0, cell);

    // Fill in components
    *(int*)&cell->col0 = 0;		// Good enough for now
    *(int*)&cell->row0 = 0;		// Good enough for now

    cell->toChip = NULL;
    cell->fromChip = NULL;
    cell->toFPA = NULL;
    cell->toTP = NULL;
    cell->toSky = NULL;

    cell->values = psMemIncrRefCounter(values);
    cell->readouts = psArrayAlloc(0);
//    cell->parent = psMemIncrRefCounter(chip);

    cell->extname = NULL;
    cell->pixels = NULL;
    cell->header = NULL;

    psMetadataAddStr(cell->values, PS_LIST_HEAD, "CELL.NAME", "Cell name added at pmCellAlloc", name);

    return cell;
}

void p_pmCellFree(pmCell *cell)
{
    psFree(cell->toChip);
    psFree(cell->fromChip);
    psFree(cell->toFPA);
    psFree(cell->toTP);
    psFree(cell->toSky);

    psFree(cell->values);
    psFree(cell->readouts);
//    psFree(cell->parent);

    psFree(cell->pixels);
    psFree(cell->header);
}

pmReadout *pmReadoutAlloc(pmCell *cell, // Cell to which the readout belongs
			  int readoutNum, // Number of the readout
			  psImage *image, // The pixels
			  psList *overscans, // The overscan images
			  int col0, int row0, int colParity, int rowParity, int colBin, int rowBin // Data
    )
{
    pmReadout *readout = psAlloc(sizeof(pmReadout));
    psMemSetDeallocator(readout, (psFreeFcn)p_pmReadoutFree);
    psArray *readouts = cell->readouts;
    if (readoutNum >= readouts->nalloc) {
	readouts = psArrayRealloc(readouts, readoutNum);
	cell->readouts = readouts;
    }
    readouts->data[readoutNum] = readout;
    
    // Set the components
    readout->image = image;
    readout->overscans = overscans;
    
    readout->values = psMetadataAlloc();
    
    *(int*)&readout->col0 = col0;
    *(int*)&readout->row0 = row0;
    *(int*)&readout->colParity = colParity;
    *(int*)&readout->rowParity = rowParity;
    *(int*)&readout->colBins = colBin;
    *(int*)&readout->rowBins = rowBin;

    return readout;
}

void p_pmReadoutFree(pmReadout *readout)
{
    psFree(readout->image);
    psFree(readout->overscans);
    psFree(readout->values);
}
