/*===========================================================================
  Copyright (C) 2011 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
===========================================================================*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

.IDENT        positions.c
.LANGUAGE     C
.AUTHOR       K. Banse   ESO/IPG
.KEYWORDS     Bulk data frames, Images
.PURPOSE      create an image with data = random numbers generated
	      according to a given distribution
.VERSION 
 110502		creation 
 110607		last modif
---------------------------------------------------------------------*/

#include <midas_def.h>
#include <stdio.h>
#include <stdlib.h>

#include <math.h>

void hsort2(int nsiz,float *ra,int *ia);

 
void show_me(worksiz,fpntr,kpntr)
int  worksiz;
float *fpntr;
int  *kpntr;

{
int   n, nr, mm;
int   *mpntr;
float *gpntr;


n = 1;
gpntr = fpntr;
mpntr = kpntr;
for (nr=0; nr<worksiz; nr+=10)
   {
   printf("%d: ",n);
   for (mm=1; mm<10; mm++) printf("%f, ",*gpntr++);
   printf("%f\n",*gpntr++);
   printf("%d: ",n);
   for (mm=1; mm<10; mm++) printf("%d, ",*mpntr++);
   printf("%d\n",*mpntr++);

   n++;
   }
}


char * ext_subframe(imno,naxis,npix,coord_string,lopix,subnpix)

int   imno;			/* IN: image id */
int   naxis;			/* IN: naxis of father frame */
int   *npix;			/* IN: npix of father frame */
char  *coord_string;		/* IN: subframe string */
int   *lopix;			/* OUT: start pixel of subframe */
int   *subnpix;			/* OUT: npix of subframe */

{
int  nolines, nopix, mm, worksiz, n, nval;
int  subsize, mx1, mx2, my1, my2;
register int  nr;

float  *rpntr, *fpntr, *gpntr, mylo[3], myhi[3];

char  *pntr, *sptr;



sptr = (char *) 0;
subsize = 0;
for (nr=0; nr<3; nr++) mylo[nr] = myhi[nr] = 0.0;

n = XConvcoo(1,imno,coord_string,naxis,&mm,mylo,myhi);
if (n != 0) 
   {
   (void) SCETER(56,"invalid subframe entered");
   goto end_of_it;		/* in case automatic abort is turned off */
   }

/* mylo, myhi start counting from 0 */
mx1 = (int) mylo[0]; 
mx2 = (int) myhi[0]; 
nopix = mx2 - mx1 + 1;
my1 = (int) mylo[1];
my2 = (int) myhi[1]; 
nolines = my2 - my1 + 1;
lopix[0] = mylo[0], lopix[1] = mylo[1], lopix[2] = mylo[2];
subnpix[2] = ((int)(myhi[2] - mylo[2])) + 1; 

worksiz = nolines * npix[0];		/* size of stripe to map in */
nval = worksiz * sizeof (float);
pntr = (char *) malloc((size_t)nval); 
if (pntr == (char *) 0) 
   (void) SCETER(32,"Could not allocate memory...");
gpntr = (float *) pntr;

n = (my1 * npix[0]) + 1;		/* + 1 for offset in SCFGET ... */
(void) SCFGET(imno,n,worksiz,&mm,pntr);
 
subsize = nolines * nopix;	/* size of subframe after extraction */
nval = subsize * sizeof(float);
sptr = (char *)malloc((size_t)nval);
if (sptr == (char *) 0) 
   (void) SCETER(32,"Could not allocate memory...");
rpntr = (float *) sptr;

nval = 0;
for (nr=0; nr<nolines; nr++)
   {
   fpntr = gpntr + nval + mx1;		/* point to startx in subframe */
   for (n=0; n<nopix; n++)
      {
      *rpntr ++ = *fpntr ++; 
      }
   nval += npix[0];
   }

SCFUNM(imno);
free(pntr);

end_of_it:
subnpix[0] = nopix;
subnpix[1] = nolines;
return sptr;
}

/*

*/

int main()

{
char   *pntra, *pntrxy;
char   outtab[84], infile[84], functype[24];
char   txtbuf[82], subfile[80], intbord[2];

int  meth, nval, mm, n, unit, null, maxpos, maxpos2;
int  xpix, ypix, zpix, outno, ioff, isub;
int  naxis, npix[3], imno, size, mapsize, pixoff;
int  *kpntr, *mpntr, pntroff, ii, plane, bigx, bigy, bigz;
int  tid, colno[4], iprint, worksiz, lopix[3], subnpix[3];

register int  nr;

float  offset, offset2, zval, zval1, zval2, rr[2];
float  *fpntr, *gpntr, *tpntr;
float  rxpix, rypix, rzpix;

double  dd;




(void) SCSPRO("positions");
(void) SCKGETC("IN_A",1,80,&nval,infile);	/* get input frame */
(void) SCKGETC("OUT_A",1,80,&nval,outtab);	/* get output table */
(void) SCKGETC("P4",1,8,&nval,txtbuf);	/* get output table */
if ((txtbuf[0] == 'Y') || (txtbuf[0] == 'y'))
   iprint = 1;
else
   iprint = 0;

tid = -99;
isub = 0;
meth = outno = -1;
(void) SCKWRI("OUTPUTI",&outno,1,1,&unit);	/* in case something fails... */

/* get additional info, 
   INPUTR holds (real) offsets or (int) no. of positions */

ioff = 1;		/* = 1 for real offsets, = 0 for no. of positions */
(void) SCKRDI("INPUTI",1,1,&nval,&ii,&unit,&null);	/* 1 or 2 values */
(void) SCKRDR("INPUTR",1,2,&nval,rr,&unit,&null);
offset = rr[0];
offset2 = rr[1];			/* maybe not used later on */
if (offset < 0.0) (void) SCETER(57,"invalid offset or no. of pos.");

/* get reference function or interval */

(void) SCKGETC("INPUTC",1,20,&nval,functype);

/* do we have a fixed interval? 
   [...], ]...], [...[, or ]...[  */

if ((functype[0] == ']') || (functype[0] == '['))
   {					/* here we process intervals */
   intbord[0] = intbord[1] = 'c';	/* default to closed interval */

   if (functype[0] == ']') intbord[0] = 'o';
   n = (int) strlen(functype) - 1;
   if (functype[n] == '[')
      intbord[1] = 'o';			/* open interval end */
   else if (functype[n] != ']')
     (void) SCETER(57,"bad interval syntax...");

   functype[n] = '\0';
   nval = CGN_CNVT(functype+1,2,2,&mm,rr,&dd);
   if ((nval != 2)||(rr[0] > rr[1]))
      (void) SCETER(58,"invalid interval values entered...");

   meth = 10;
   zval1 = rr[0];
   zval2 = rr[1];
   }

/* here we have the MIN,np  or MAX+rp entries */

else
   {
   CGN_UPSTR(functype);				/* convert to upper case */
   n = (int) strlen(functype);

   if (functype[n-1] == ',')
      {
      ioff = 0;			/* no. of positions, no offset values */
      functype[n-1] = '\0';
      maxpos = CGN_NINT(offset);
      if (ii == 2)
         {
         maxpos2 = CGN_NINT(offset2);
         if (maxpos2 < 0) 
            (void) SCETER(57,"invalid 2nd no. of pos.");
         }
      }
   else
      {
      if (ii == 2)
         {
         if (offset2 < 0.0) 
            (void) SCETER(57,"invalid 2nd offset");
         }
      }
   }

/* get maxsize of virtual memory for mapping frames */

(void) SCKRDI("MONITPAR",20,1,&nval,&mapsize,&unit,&null);
mapsize *= mapsize;				/* square image */

/* check for subframe */

isub = CGN_INDEXC(infile,'[');
if (isub > 0) 
   {
   (void) strcpy(subfile,infile+isub);
   infile[isub] = '\0';
   }

/* open file */

(void) SCFOPN(infile,D_R4_FORMAT,0,F_IMA_TYPE,&imno);
(void) SCDRDI(imno,"NAXIS",1,1,&nval,&naxis,&unit,&null);
if (naxis > 3) naxis = 3;
npix[0] = npix[1] = npix[2] = 1;
(void) SCDRDI(imno,"NPIX",1,naxis,&nval,npix,&unit,&null);
size = npix[0] * npix[1] * npix[2];

if (isub > 0) 
   {
   /* extract subframe and store already in memory */
   pntra = ext_subframe(imno,naxis,npix,subfile,lopix,subnpix);
   worksiz = subnpix[0] * subnpix[1] * subnpix[2];
   }
else
   {
   /* map all data at once so it will not work for really huge files 
      not fitting into virtual memory */
   worksiz = size;
   pixoff = 1;			/* remember, SCFGET begins with 1! */

   if (mapsize < worksiz)
      (void) SCETER(17," not implemented for such large frames ...");

   nval = worksiz * sizeof (float);
   pntra = (char *) malloc((size_t)nval);	/* for input frame; */
   if (pntra == (char *) 0) 
      (void) SCETER(32,"Could not allocate memory...");
   (void) SCFGET(imno,pixoff,worksiz,&mm,pntra);
   }
fpntr = (float *) pntra;

/* now allocate space for pixno buffer */
nval = worksiz * sizeof (int);
pntrxy = malloc((size_t)nval);	
if (pntrxy == (char *) 0) 
   (void) SCETER(35,"Could not allocate memory...");

/* and init pixel no.s to 1,2,3,...,worksiz  */
kpntr = (int *) pntrxy;
for (nr=1; nr<=worksiz; nr++) *kpntr++ = nr;
kpntr = (int *) pntrxy;		/* reset to start */


/* except for the interval, we need either meth,n or meth+-val */

if (meth < 10)
   {
   if (strncmp(functype,"MIN",3) == 0)
      {
      meth = 1;
      }
   else if (strncmp(functype,"MAX",3) == 0)
      {
      meth = 2;
      }
   else if (strncmp(functype,"MED",3) == 0)
      {
      meth = 3;
      }
   else
      (void) SCETER(52,"invalid option...");
   }

/* sort all data together with their pixel no's. */

hsort2(worksiz,fpntr,kpntr);


switch(meth)
   {
   case 1:
    {
    outno = maxpos + 1; 
    if (ioff == 1)			/* min + value */
       {
       tpntr = fpntr;
       zval = *tpntr + offset;
       outno = 0;

       for (nr=0; nr<worksiz; nr++)
          {
          if (*tpntr > zval) goto step_1a;
          tpntr++;
          outno++;
          }
       }
   step_1a:
    gpntr = fpntr;
    mpntr = kpntr;
    goto result;
    }

   case 2:
    {
    outno = maxpos + 1; 
    if (ioff == 1)
       {
       tpntr = fpntr+worksiz-1;		/* point to max */
       zval = *tpntr - offset;		/* max - offset */
       outno = 0;

       for (nr=0; nr<worksiz; nr++)
          {
          if (*tpntr < zval) goto step_2a;

          tpntr--;
          outno++;
          }
       }

   step_2a:
    pntroff = worksiz - outno;
    gpntr = fpntr + worksiz - outno;
    mpntr = kpntr + worksiz - outno;
    goto result;
    }

   case 3:
    {
    mm = (worksiz+1)/2;		/* index of median (starting at 1) */

    if (ioff == 1)
       {
       zval = *(fpntr + mm - 1);
       zval1 = zval - offset;		/* median - offset */
       if (ii == 1)
          zval2 = zval + offset;		/* median + offset */
       else
          zval2 = zval + offset2;		/* median + offset2 */

       tpntr = fpntr;
       outno = 0;
       
       for (nr=0; nr<worksiz; nr++)
          {
          if (*tpntr >= zval1)
             {
             if (*tpntr <= zval2)
                {
                if (outno == 0) pntroff = nr;	/* save pointer offset */
                outno++ ;
                }
             else
                goto step_3a;
             }
          tpntr++;
          }
       }
    else
       {
       if (ii == 1)
          outno = 2*maxpos + 1; 
       else
          outno = maxpos + maxpos2 + 1; 
       pntroff = mm - 1 - maxpos;	/* point to median - low offset */
       }

   step_3a:
    gpntr = fpntr + pntroff;
    mpntr = kpntr + pntroff;
    goto result;
    }

   case 10:
    {
    tpntr = fpntr;
    outno = 0;
       
    if ((intbord[0] == 'c') && (intbord[1] == 'c'))		/* [...] */
       {
       for (nr=0; nr<worksiz; nr++)
          {
          if (*tpntr >= zval1)
             {
             if (*tpntr <= zval2)
                {
                if (outno == 0) pntroff = nr;	/* save pointer offset */
                outno++ ;
                }
             else
                goto step_10a;
             }
          tpntr++;
          }
       }
    else if ((intbord[0] == 'o') && (intbord[1] == 'c'))	/* ]...] */
       {
       for (nr=0; nr<worksiz; nr++)
          {
          if (*tpntr > zval1)
             {
             if (*tpntr <= zval2)
                {
                if (outno == 0) pntroff = nr;	/* save pointer offset */
                outno++ ;
                }
             else
                goto step_10a;
             }
          tpntr++;
          }
       }
    else if ((intbord[0] == 'c') && (intbord[1] == 'o'))	/* [...[ */
       {
       for (nr=0; nr<worksiz; nr++)
          {
          if (*tpntr >= zval1)
             {
             if (*tpntr < zval2)
                {
                if (outno == 0) pntroff = nr;	/* save pointer offset */
                outno++ ;
                }
             else
                goto step_10a;
             }
          tpntr++;
          }
       }
    else							/* ]...[ */
       {
       for (nr=0; nr<worksiz; nr++)
          {
          if (*tpntr > zval1)
             {
             if (*tpntr < zval2)
                {
                if (outno == 0) pntroff = nr;	/* save pointer offset */
                outno++ ;
                }
             else
                goto step_10a;
             }
          tpntr++;
          }
       }

   step_10a:
    gpntr = fpntr + pntroff;
    mpntr = kpntr + pntroff;
    goto result;
    }

   default:
    {
    printf("not implemented yet...\n");
    exit;
    }
      }

result:
if (isub > 0)
   (void) sprintf(txtbuf,"image %s%s: %d pixels found in given interval\n", 
               infile,subfile,outno);
else
   (void) sprintf(txtbuf,"image %s: %d pixels found in given interval\n",
               infile,outno);
(void) SCTPUT(txtbuf);
if (outno == 0) goto end_of_it;

/* create the table with (naxis+1) cols and outno rows */

if (outtab[0] != '+')
   {
   (void) TCTINI(outtab,F_TRANS,F_O_MODE,(naxis+1),outno,&tid);

   (void) TCCINI(tid,D_R4_FORMAT,1,"G12.6"," ","VALUE",&colno[naxis]);
   (void) TCCINI(tid,D_R4_FORMAT,1,"F10.1"," ","X_PIX",&colno[0]);

   if (naxis > 1)
      (void) TCCINI(tid,D_R4_FORMAT,1,"F10.1"," ","Y_PIX",&colno[1]);
   if (naxis > 2)
      (void) TCCINI(tid,D_R4_FORMAT,1,"F10.1"," ","Z_PIX",&colno[2]);

   (void) SCKGETC("HISTORY",1,80,&nval,outtab);	
   (void) SCDWRC(tid,"HISTORY",1,outtab,1,strlen(outtab),&unit);
   }

if (naxis == 1)
   {
   (void) sprintf(txtbuf,"value     at  (xpx)");
   if (iprint == 1) (void) SCTPUT(txtbuf);

   for (nr=0; nr < outno; nr++)
      {
      n = nr + 1;
      if (tid != -99) (void) TCRWRR(tid,n,1,&colno[naxis],gpntr);
      nval = *mpntr++;

      xpix = nval;
      if (isub > 0)
         {
         bigx = lopix[0] + xpix;
         (void) sprintf(txtbuf,"%f  - (%d)\t\t (%d)",*gpntr++,xpix,bigx);
         }
      else
         (void) sprintf(txtbuf,"%f  - (%d)",*gpntr++,xpix);
      if (iprint == 1) (void) SCTPUT(txtbuf);

      if (tid != -99) 
         {
         rxpix = (float) xpix;
         (void) TCRWRR(tid,n,1,&colno[0],&rxpix);
         }
      }
   }
 
else if (naxis == 2)
   {
   (void) sprintf(txtbuf,"value     at  (xpx,ypx)");
   if (iprint == 1) (void) SCTPUT(txtbuf);

   for (nr=0; nr < outno; nr++)
      {
      n = nr + 1;
      if (tid != -99) (void) TCRWRR(tid,n,1,&colno[naxis],gpntr);
      nval = *mpntr++;

      mm = (nval-1) / npix[0];		/* get row no. */
      ypix = mm + 1;
      xpix = nval - (mm * npix[0]);

      if (isub > 0)
         {
         bigx = lopix[0] + xpix;
         bigy = lopix[1] + ypix;
         (void) sprintf(txtbuf,"%f  - (%d,%d)\t\t (%d,%d)",
                *gpntr++,xpix,ypix,bigx,bigy);
         }
      else
         (void) sprintf(txtbuf,"%f  - (%d,%d)",*gpntr++,xpix,ypix);
      if (iprint == 1) (void) SCTPUT(txtbuf);

      if (tid != -99) 
         {
         rxpix = (float) xpix;		/* real pixel no. for the table */
         rypix = (float) ypix;
         (void) TCRWRR(tid,n,1,&colno[0],&rxpix);
         (void) TCRWRR(tid,n,1,&colno[1],&rypix);
         }
      }
   }
else
   {
   (void) sprintf(txtbuf,"value     at  (xpx,ypx,zpx)");
   if (iprint == 1) (void) SCTPUT(txtbuf);

   plane = npix[0] * npix[1];		/* size of x-y plane */
   for (nr=0; nr < outno; nr++)
      {
      n = nr + 1;
      if (tid != -99) (void) TCRWRR(tid,n,1,&colno[naxis],gpntr);
      nval = *mpntr++;
      mm = (nval-1) / plane;
      zpix = mm + 1;			/* get plane no. */

      nval = nval - (mm * plane);
      mm = (nval-1) / npix[0];		/* get row no. */
      ypix = mm + 1;
      xpix = nval - (mm * npix[1]);

      if (isub > 0)
         {
         bigx = lopix[0] + xpix;
         bigy = lopix[1] + ypix;
         bigz = lopix[2] + zpix;
         (void) sprintf(txtbuf,"%f  - (%d,%d,%d)\t\t (%d,%d,%d)",
                *gpntr++,xpix,ypix,zpix,bigx,bigy,bigz);
         }
      else
         (void) sprintf(txtbuf,"%f  - (%d,%d,%d)",*gpntr++,xpix,ypix,zpix);
      if (iprint == 1) (void) SCTPUT(txtbuf);
 
      if (tid != -99) 
         {    
         rxpix = (float) xpix;		/* real pixel no. for the table */
         rypix = (float) ypix;
         rzpix = (float) zpix;
         (void) TCRWRR(tid,n,1,&colno[0],&rxpix);
         (void) TCRWRR(tid,n,1,&colno[1],&rypix);
         (void) TCRWRR(tid,n,1,&colno[2],&rzpix);
         }
      }
   }



end_of_it:
free(pntra);
free(pntrxy);
(void) SCKWRI("OUTPUTI",&outno,1,1,&unit);

(void) SCFCLO(imno);
if (tid != -99) (void) TCTCLO(tid);

(void) SCSEPI();
return 0;
}


/* here we park all diagnostic printouts in case we need 'em again... */

/* 
printf("interval: %s, intbord = %c, %c, zval1, zval2 = %f, %f\n",
functype,intbord[0],intbord[1],zval1,zval2);
*/

/*
printf("after sorting:\n");
printf("fpntr = %d, kpntr = %d, fpntr+size-1 = %d,kpntr+size-1 = %d\n",fpntr,kpntr,fpntr+size-1,kpntr+size-1);
printf("1st val = %f, 1st pixno = %d, last val = %f,last pixno = %d\n",*fpntr,*kpntr,*(fpntr+size-1),*(kpntr+size-1));
*/

/*
show_me(size,fpntr,kpntr);
*/

/*
printf("after sorting:\n");
show_me(size,fpntr,kpntr);
*/

 
