/*===========================================================================
  Copyright (C) 1993-2009 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/
/*
++++++++++++++++++++++++++++++++++++++++++++++++++
 
.IDENTIFICATION: program ccdrebin
 
.KEYWORDS:       bulk data frames, average
 
.PURPOSE:        average a no. of image frames, the result will either be a 
                 frame with size equal to common area of all frames involved 
                 or size equal to union of all frame areas
 
.ALGORITHM:      extract input frames either from given parameter string or 
                 from catalogue, add up all frames + divide in the end
 
.INPUT/OUTPUT:   the following keys are used:
                 ACTION/C/1/2  (1:1) = M or N, for merging option
 		               (2:2) = I or W, for AVERAGE/IMAGE, /WEIGHTS
                 OUT_A/C/1/60  result frame
                 P3/C/1/80  list of frames to be averaged
 
.VERSIONS:       930311 RHW Created; original version from Klaus (G.) Banse
.VERSION:        940118 RHW long int -> int, unit -> *int

 090903		last modif
--------------------------------------------------
*/

/*
 * Define _POSIX_SOURCE to indicate
 * that this is a POSIX program
 */
#define _POSIX_SOURCE 1

/*
 * definition of the used functions
 */
#include <midas_def.h>
#include <math.h>

#include <mutil.h>
#include <stdlib.h> 

/*
 * define some macros and constants
 */
#define  MAXPIX	    512    /* max frame dimension (X,Y) accessed at once */
#define  MAXSIZ     (MAXPIX * MAXPIX)


/*

*/
void CCD_MEAN(x,n,ave,sdev,svar)

float      *x;
int        n;
float      *ave, *sdev, *svar;

{
int        j;
float      s;


if (n <= 1) SCETER( 2, "*** FATAL: At least two points are needed");



s = 0.0;
for (j=0; j<n; j++) s += x[j];
*ave  = s/n;
*svar = 0.0;
for (j=0; j<n;j++) 
   {
   s = x[j]-(*ave);
   *svar += s*s;
   }
*svar /= (n-1);
*sdev=sqrt(*svar);
}

/*

*/
void CCD_MED(x,n,xmed)
float *x,*xmed;
int n;

{
int n2,n2p;

float  median0, median1; 
float  *arr1; 

 // printf("Entering CCD_MED\n"); 
 //Original code
 /* 
 sort(n,x);
 n2p=(n2=n/2)+1;
 *xmed=(n % 2 ? x[n2p] : 0.5*(x[n2]+x[n2p]));
 */ 

 arr1 = (float*) malloc ((size_t)((n)*sizeof (float)));
 heap_copy(n,x, arr1); 

 //sort(n,arr1);
 // Normally, std_sortf or hsort(n,arr1), but this is for 
 // backward compatibility with the original implementation bug. 
 // std_sortf((n-1),&(arr1[1])); 
 hsort((n-1),&(arr1[1])); 

 n2     = (n % 2 ? (n-1)/2   : n/2); 
 n2p    = n2+1; 
 median1 = (n % 2 ? arr1[n2p] : 0.5*(arr1[n2]+arr1[n2p]));
 *xmed = median1; 

 /*
 if (median0 != median1) 
 printf ("CCD_MED DIFF: %f %f\n",median0,median1); 
 */ 

 free(arr1); 
}


/*++++++++++++++++++++++++++++++
.PURPOSE     Copy (part of) frame A to frame B, start pixels don't have to be
             the same
.ALGORITHM   straight forward
.INPUT/OUTPUT
  call as    Ccopyf1( pntrA, npixA, bgnA, dimwA, pntrB, npixB, bgnB )

  input:
          float *pntrA		input frame A
          int   npixA[2]	NPIX of A
          int   bgnA[2]         start pixel of window in A
          int   dimwA[2]        dimension of window in A
          float *pntrB		output frame B
          int   npixB[2]	NPIX of B
          int   bgnB[2]		start pixel of window in B

.RETURNS     nothing
------------------------------*/

void Ccpfrm1( pntrA, npixA, bgnA, dimwA, pntrB, npixB, bgnB )
int   *npixA, *npixB, *bgnA, *bgnB, *dimwA;
float *pntrA, *pntrB;
{
register int ix, iy;

int offsA = npixA[0] - dimwA[0],
    offsB = npixB[0] - dimwA[0];
      
/*
 * Move the pointers to start positions
 */
pntrA += bgnA[0] - 1 + npixA[0] * (bgnA[1] - 1);
pntrB += bgnB[0] - 1 + npixB[0] * (bgnB[1] - 1);

/*
 * Copy frame A to frame B
 */
for ( iy = 0; iy < dimwA[1]; iy++ )
    { for ( ix = 0; ix < dimwA[0]; ix++ ) *pntrB++ = *pntrA++;
      pntrA += offsA;
      pntrB += offsB;
    }
}



int main()

{


float        *p_img, *ave, *sdev, *svar, *med;
char         *a_img;

double       bgnB[2], stpB[2];

int          imnol, imnom, imnos;
int          naxis, npixA[2], npixB[2];
int          dimwP[2], sizeA, sizeB;
int          ibgnA[2], ibgnB[2];
int          iav, stat;
int          boxsize, boxpix;
int          uni, nulo;
int          ix, iy;
int          info[5];
int          mean;

char         output[64];
char         in_frm[82];
char         out_frm1[62], out_frm2[62];
char         *osmmget();


 
/* set up MIDAS environment + enable automatic error abort */

SCSPRO("averag");

/* get result frame, input frame list */
stat = SCKGETC("IN_A",1,80,&iav,in_frm);

stat = SCFINF(in_frm,2,info);
stat = SCFOPN(in_frm,info[1],0,F_IMA_TYPE,&imnol);
   
stat = SCKGETC("REBIN",1,3,&iav,output);
output[4] = '\0';
CGN_UPSTR(output);                               /* convert to upper case */
if (strcmp(output,"MEA") == 0)                                /* set flag */
   mean = 1;
else
   mean = 0;

/* get the size of the box area in pixels */
stat     = SCKRDI("NBOX",1,1,&iav,&boxsize,&uni,&nulo); 
dimwP[0] = dimwP[1] = boxsize;
boxpix   = boxsize*boxsize;

stat     = SCDRDI(imnol,"NAXIS",1,1,&iav,&naxis,&uni,&nulo);
stat     = SCDRDI(imnol,"NPIX",1,2,&iav,npixA,&uni,&nulo);
sizeA    = npixA[0]*npixA[1];
npixB[0] = npixA[0]/boxsize;
npixB[1] = npixA[1]/boxsize;
sizeB    = npixB[0] * npixB[1]; 
bgnB[0]  = bgnB[1] = 1.;
stpB[0]  = stpB[1] = 1.;
ibgnB[0] = ibgnB[1] = 1.;

p_img    = (float *) osmmget( boxpix * sizeof( float ));   
ave      = (float *) osmmget( npixB[0] * sizeof( float ));     
med      = (float *) osmmget( npixB[0] * sizeof( float ));     
sdev     = (float *) osmmget( npixB[0] * sizeof( float ));     
svar     = (float *) osmmget( npixB[0] * sizeof( float ));     


SCFMAP(imnol, F_I_MODE, 1, sizeA, &iav, &a_img );
stat = SCKGETC("OUT_A",1,60,&iav,out_frm1);
SCFCRE(out_frm1, D_R4_FORMAT, F_O_MODE, F_IMA_TYPE, sizeB, &imnom);
stat = SCDCOP(imnol,imnom,1," "); 
stat = SCDWRI(imnom,"NPIX",npixB,1,naxis,&uni);
stat = SCDWRD(imnom,"STEP",stpB,1,naxis,&uni);
/*
 Here for the standard deviation image
 */
if (mean == 1)
   {
   stat = SCKGETC("OUT_B",1,60,&iav,out_frm2);
   SCFCRE(out_frm2, D_R4_FORMAT, F_O_MODE, F_IMA_TYPE, sizeB, &imnos);
   stat = SCDCOP(imnol,imnos,1," ");
   stat = SCDWRI(imnos,"NPIX",npixB,1,naxis,&uni);
   stat = SCDWRD(imnos,"STEP",stpB,1,naxis,&uni);
   }

for (iy=0; iy<npixB[1]; iy++)
   {
   ibgnA[1] = iy * boxsize + 1;
   for (ix=0; ix<npixB[0]; ix++)
      {
      ibgnA[0] = ix * boxsize + 1;
      Ccpfrm1( (float *) a_img, npixA, ibgnA, dimwP, p_img, 
               dimwP, ibgnB ); 
      if (mean == 1) 
         CCD_MEAN(p_img, boxpix,&ave[ix],&sdev[ix],&svar[ix]);
      else
         CCD_MED(p_img, boxpix,&med[ix]);
      }
   if (mean == 1)
      {
      SCFPUT(imnom, iy*npixB[0] + 1, npixB[0], (char *) ave);
      SCFPUT(imnos, iy*npixB[0] + 1, npixB[0], (char *) sdev);
      }
   else
      SCFPUT(imnom, iy*npixB[0] + 1, npixB[0], (char *) med);
   }

SCSEPI();

return 0;

}

