/** @file  psImageBinning.c
 *
 *  @brief Functions to define the binning strategy and to perform image binning / unbinning
 *  (resampling).
 *
 *  @ingroup Image
 *
 *  @author Eugene Magnier, IfA
 *
 *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2007-03-31 02:59:41 $
 *
 *  Copyright 2007 Institute for Astronomy, University of Hawaii
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>
#include "psError.h"
#include "psAbort.h"
#include "psAssert.h"
#include "psRegion.h"
#include "psImage.h"
#include "psImageBinning.h"

static void psImageBinningFree(psImageBinning *binning) {
    return;
}

psImageBinning *psImageBinningAlloc() {
    psImageBinning *binning = (psImageBinning*)psAlloc(sizeof(psImageBinning));
    psMemSetDeallocator(binning, (psFreeFunc)psImageBinningFree);

    return binning;
}

void psImageBinningSetRuffSize(psImageBinning *binning, psImageBinningAlign align) {
    
    assert (binning->nXfine > 0);
    assert (binning->nYfine > 0);
    assert (binning->nXbin > 0);
    assert (binning->nYbin > 0);

    binning->nXruff = binning->nXfine / binning->nXbin;
    if (binning->nXfine % binning->nXbin) binning->nXruff ++;

    binning->nYruff = binning->nYfine / binning->nYbin;
    if (binning->nYfine % binning->nYbin) binning->nYruff ++;

    switch (align) {
      case PS_IMAGE_BINNING_LEFT:
	binning->nXoff = 0;
	binning->nYoff = 0;
	break;
      case PS_IMAGE_BINNING_CENTER:
	binning->nXoff = ((binning->nXruff * binning->nXbin) % binning->nXfine) / 2;
	binning->nYoff = ((binning->nYruff * binning->nYbin) % binning->nYfine) / 2;
	break;
      case PS_IMAGE_BINNING_RIGHT:
	binning->nXoff = ((binning->nXruff * binning->nXbin) % binning->nXfine);
	binning->nYoff = ((binning->nYruff * binning->nYbin) % binning->nYfine);
	break;
      default:
	psAbort ("programming error in %s: impossible case\n", __func__);
    }
    return;
}

void psImageBinningSetFineSize(psImageBinning *binning, psImageBinningAlign align) {

    binning->nXfine = binning->nXruff * binning->nXbin;
    binning->nYfine = binning->nYruff * binning->nYbin;
    return;
}

void psImageBinningSetSkip(psImageBinning *binning, psImage *image) {

    binning->nXskip = image->col0 - binning->nXoff;
    binning->nYskip = image->row0 - binning->nYoff;
    return;
}

void psImageBinningSetScale(psImageBinning *binning, psImageBinningAlign align) {
    
    assert (binning->nXfine > 0);
    assert (binning->nYfine > 0);
    assert (binning->nXruff > 0);
    assert (binning->nYruff > 0);

    binning->nXbin = binning->nXfine / binning->nXruff;
    if (binning->nXfine % binning->nXruff) binning->nXbin ++;

    binning->nYbin = binning->nYfine / binning->nYruff;
    if (binning->nYfine % binning->nYruff) binning->nYbin ++;

    switch (align) {
      case PS_IMAGE_BINNING_LEFT:
	binning->nXoff = 0;
	binning->nYoff = 0;
	break;
      case PS_IMAGE_BINNING_CENTER:
	binning->nXoff = (binning->nXfine % binning->nXbin) / 2;
	binning->nYoff = (binning->nYfine % binning->nYbin) / 2;
	break;
      case PS_IMAGE_BINNING_RIGHT:
	binning->nXoff = (binning->nXfine % binning->nXbin);
	binning->nYoff = (binning->nYfine % binning->nYbin);
	break;
      default:
	psAbort ("programming error in %s: impossible case\n", __func__);
    }
    return;
}

psRegion psImageBinningSetFineRegion (psImageBinning *binning, psRegion ruffRegion) {

    psRegion fineRegion;

    fineRegion.x0 = ruffRegion.x0 * binning->nXbin;
    fineRegion.x1 = ruffRegion.x1 * binning->nXbin;
    fineRegion.y0 = ruffRegion.y0 * binning->nYbin;
    fineRegion.y1 = ruffRegion.y1 * binning->nYbin;
    return fineRegion;
}

psRegion psImageBinningSetRuffRegion (psImageBinning *binning, psRegion fineRegion) {

    psRegion ruffRegion;

    ruffRegion.x0 = fineRegion.x0 / binning->nXbin;
    ruffRegion.x1 = fineRegion.x1 / binning->nXbin;
    ruffRegion.y0 = fineRegion.y0 / binning->nYbin;
    ruffRegion.y1 = fineRegion.y1 / binning->nYbin;
    return ruffRegion;
}

/*** pmFPACopy.c:binRegion had the following logic ***/
# if (0)
    // Want to include the lower bound: 1 binned by 4 --> 0; 3 binned by 4 --> 0; 4 binned by 4 --> 1
    region->x0 = (int)(region->x0 / xBin);
    region->y0 = (int)(region->y0 / yBin);
    // Want to exclude the upper bound: 4 binned by 4 --> 1; 5 binned by 4 --> 2; 7 binned by 4 --> 2
    region->x1 = (int)((region->x1 + xBin - 1) / xBin);
    region->y1 = (int)((region->y1 + yBin - 1) / yBin);
# endif

/* 
 * dvoMakeCorrUnbin ** OK
 * psphotImageMedian ** OK?
 * psphotMagnitudes ** OK
 * pmFPACopy ** OK
 * pmConceptsUpdate ** OK
 * pmFPAMosaic ** OK (needs more use of psImageBinning functions)
 * psImageUnbin 
 * psImageRebin
 * ppImageRebinReadout
 */

