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

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.IDENT      fitsrdmui2.c
.LAUGUAGE   C
.AUTHOR     P.Grosbol/K.Banse   ESO/IPG
.KEYWORDS   FITS data matrix, decode, read
.VERSION    1.0  copied from fitsrdm.c
.COMMENT    read the prime data matrix of FITS file
            this is a stripped down version of fitsrdm.c
	    only for I2 and UI2 FITS data

.VERSION

 090706		last modif
---------------------------------------------------------------------*/

#include   <stdio.h>            /* computer specific constants    */

#include   <computer.h>            /* computer specific constants    */
#include   <fitsfmt.h>             /* general data definitions       */
#include   <fitsdef.h>             /* basic FITS definitions         */
#include   <fitsextvals.h>
#include   <midas_def.h>           /* MIDAS definitions              */

#define    MXFB              2880  /* max. size of scaling buffer    */
/*

*/

#ifdef __STDC__
int fitsrdmUI2(int mfd , BFDEF * bfdef , int size , int mfdt , char fmt,
            int Midas_flag)
#else
int fitsrdmUI2(mfd,bfdef,size,mfdt,fmt,Midas_flag)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE       Read prime data matrix in FITS
.RETURN        error code - 0: OK, -1: error
---------------------------------------------------------------------*/
int       mfd;                 /* IN: MIDAS file descriptor          */
BFDEF     *bfdef;              /* IN: pointer to FITS header parm's  */
int       size;                /* IN: size of data matrix (bytes)    */
int       mfdt;                /* IN: MIDAS file desc. Groups table  */
char      fmt;                 /* IN: data format Original/Float     */
int       Midas_flag;	       /* IN: = 0, `usual' mode
                                      = 1, `internal FITS access'  */

#endif
{
short          *ps;
unsigned short *pu;

int    dno, gno, pno, npix, n, fmm;
int    dn, pn, ndata, dfmt, pcnt, dsf, unit[4];
int    felem, mnvi, mxvi;
int    ifac, izero;
register int   k, ireg;
 
float          *pf, cuts[2];
register float   freg, fzero, fac, mnvd, mxvd;
 
double         d;
 
PDEF           *pp;
union { 
	float    f[2*MXFB];
	double     d[MXFB];
      } buf;
union { 
	unsigned char   *b;
	char            *c;
	short           *s;
	unsigned short  *u;
	int             *i;
	float           *f;
	double          *d;
      } p;






/* we only come here, if bfdef->bitpix = 16 (or -16) */

pp = (PDEF *) 0;
izero = dsf = dfmt = fmm = 0;
ndata = pno = dno = 0;
mnvi = mxvi = 0;
mnvd = mxvd = 0.0;

if (size > 0)
   {
   pno = bfdef->pcount; pcnt = 0;             /* initiate counters     */
   pp = bfdef->parm;
   gno = 0;
   dfmt = bfdef->bitpix;			/* -16 or 16 in this routine */
   ndata = size/(2*bfdef->gcount) - pno; dno = ndata;

   fac = (float) bfdef->bscale; fzero = (float) bfdef->bzero;
   if ((fac > 0.999999) && (fac < 1.00001))
      ifac = 1;				/* no need to multiply with 1.0 */
   else
      ifac = 0;
   if ((fzero < -0.000001) || (fzero > 0.00001))
      izero = 0;			/* we need to add the non-zero value */
   else
      izero = 1;
   felem = 1;
   fmm = (bfdef->mflag != 3);
   dsf = (bfdef->sflag || fmt=='F') ? -32 : dfmt;

   /*
   printf
   ("UI2: dfmt = %d, sflag = %d, fmm = %d, dsf = %d, pno = %d, dno = %d\n",
   dfmt,bfdef->sflag,fmm,dsf,pno,dno);
   printf("ifac = %d, fac = %f, izero = %d, fzero = %f\n",ifac,fac,izero,fzero);
   printf("Midas_flag = %d\n",Midas_flag);
   */
   }
else
   {
   fac = 1.0, ifac = 1;
   fzero = 0.0;
   }

while (0<size) 
   {                 /* read all data in prime matrix  */
   if ((n=dread(&p.c,FITSLR)) != FITSLR) 	/* read next data record  */
      {			
      if (size <= n) 
	 SCTPUT("Warning: incomplete FITS record read!");
      else 
         {
         int   unit;
         char  tbuf[80];

	 SCTPUT("Error: unexpected EOF");
         size /= 2; 
	 (void) sprintf(tbuf,"%d data values still missing",size);
         SCTPUT(tbuf);
	 if (0<=mfd) SCFCLO(mfd); mfd = -1;
         (void) SCKWRI("OUTPUTI",&size,16,1,&unit);	/* save value */
	 return NOFITS;
         }
      }

   if (size <= n) 
      {
      n = size;			/* last loop */
      size = 0;
      }
   else
      size -= n;		/* decrement remaining bytes      */
   npix = n/2; 
   if (!same_comp_i2) cvi2(p.s,npix,0); 

   do 
      {				/* scale all values if needed     */
      if (0<pno) 
         {			/* decode groups parameters       */
	 pn = (pno<npix) ? pno : npix;
	 pno -= pn; npix -= pn;
	 while (pn--) 
            {
	    d = pp->pscal * (*(p.s++)) + pp->pzero;
	    pcnt++; pp++;
            if (0<=mfdt) TCEWRD(mfdt,gno+1,pcnt,&d);
	    }
         }

      if (!pno && 0<dno && npix) 
         {				/* decode data values            */
	 dn = (dno<npix) ? dno : npix;
	 dno -= dn; npix -= dn;

         /* option = scale the data (unsigned int and int are equal) */
         /* format for minmax is float */

         if (bfdef->sflag) 			/* here: dsf = -32 */
            {		
            pf = buf.f; ps = p.s;
            if (fmm)
               {
               if (felem==1) mnvd = mxvd = (fac*(*ps)) + fzero;

               if (ifac == 0)
                  {
                  if (izero == 0)
                     {
                     for (k=0; k<dn; k++)
                        {
                        freg = fac*(*ps++) + fzero;
                        if (freg<mnvd)
                           mnvd = freg;
                        else if (mxvd<freg)
                           mxvd = freg;
                        *pf++ = freg;
                        }
                     }
                  else
                     {
                     for (k=0; k<dn; k++)
                        {
                        freg = fac*(*ps++) ;
                        if (freg<mnvd)
                           mnvd = freg;
                        else if (mxvd<freg)
                           mxvd = freg;
                        *pf++ = freg;
                        }
                     }
                  }
               else
                  {
                  if (izero == 0)
                     {
                     for (k=0; k<dn; k++)
                        {
                        freg = (*ps++) + fzero;
                        if (freg<mnvd)
                           mnvd = freg;
                        else if (mxvd<freg)
                           mxvd = freg;
                        *pf++ = freg;
                        }
                     }
                  else
                     {
                     for (k=0; k<dn; k++)
                        {
                        freg = (*ps++) ;
                        if (freg<mnvd)
                           mnvd = freg;
                        else if (mxvd<freg)
                           mxvd = freg;
                        *pf++ = freg;
                        }
                     }
                  }
               }
            else
               {
               if (ifac == 0)
                  {
                  if (izero == 0)
                     {
                     for (k=0; k<dn; k++) *pf++ = fac*(*ps++) + fzero;
                     }
                  else
                     {
                     for (k=0; k<dn; k++) *pf++ = fac*(*ps++);
                     }
                  }
	       else
                  {
                  if (izero == 0)
                     {
                     for (k=0; k<dn; k++) *pf++ = (*ps++) + fzero;
                     }
                  else
                     {
                     for (k=0; k<dn; k++) *pf++ = *ps++;
                     }
                  }
               }

            if (Midas_flag != 0)
	       MyPut(-32,felem,dn,(char *) buf.f);
            else
               (void) wrdisk(mfd,felem,dn,(char *) buf.f);   /* fast SCFPUT */
	    }

         /* option = convert data to float (unsingend int and int are equal) */
         /* format for minmax is float */

         else if (fmt == 'F') 
            { 	
            pf = buf.f; ps = p.s;
            if (fmm)
               {                        /* dsf = -32 */
               if (felem==1) mnvd = mxvd = (float) *ps;
               for (k=0; k<dn; k++) 
                  {
                  freg = (float) *ps++;
                  if (freg<mnvd)
                     mnvd = freg;
                  else if (mxvd<freg)
                     mxvd = freg;
                  *pf++ = freg;
                  }
               }
            else
               {
               for (k=0; k<dn; k++) *pf++ = (float) *ps++;
               }

            if (Midas_flag != 0)
	       MyPut(-32,felem,dn,(char *) buf.f);
	    else
               (void) wrdisk(mfd,felem,dn,(char *) buf.f);   /* fast SCFPUT */
	    }

         /* option = take data as is (unsigned int and int are different) */
         /* format for minmax is same as original format */

         else 		/* only case: -16, 16 for dfmt possible */
            {		
	    if (dfmt == (-16))
               {
               pu = p.u; ps = p.s;
               if (fmm)
                  {				/* here dsf = dfmt */
                  if (felem==1) mnvi = mxvi = *ps + 32768.0;

                  for (k=0; k<dn; k++) 
                     {
                     ireg = 32768 + (int) *ps++;
                     if (ireg < mnvi)
                        mnvi = ireg;
                     else if (mxvi<ireg)
                        mxvi = ireg;
                     *pu++ = ireg;
                     }
                  }
               else
                  {
	          for (k=0; k<dn; k++) *pu++ = (*ps++) + 32768;
                  }

               if (Midas_flag != 0)
	          MyPut(dfmt,felem,dn,(char *) p.u);
               else
                  (void) wrdisk(mfd,felem,dn,(char *) p.u);   /* fast SCFPUT */
	       }
            else		/* dfmt = 16 */
               {
	       ps = p.s; 
               if (fmm)
                  {                          /* here dsf = dfmt */
                  if (felem==1) mnvi = mxvi = *ps;

                  for (k=0; k<dn; k++)
                     {
                     ireg = (int) *ps++;
                     if (ireg<mnvi)
                        mnvi = ireg;
                     else if (mxvi<ireg)
                        mxvi = ireg;
                     }
                  }

               if (Midas_flag != 0)
                  MyPut(dfmt,felem,dn,(char *) p.s);
               else
                  (void) wrdisk(mfd,felem,dn,(char *) p.s);   /* fast SCFPUT */
	       }
	    }

         felem += dn;
         if (!dno) 
            {
            gno++;
            pno = bfdef->pcount; pcnt = 0;
            pp = bfdef->parm;
            dno = ndata;
            }
         }

      } while (npix && gno<bfdef->gcount);
   }


if (fmm) 
   {                         /* save computed min/max values  */
   if (dsf > -32) 
      {				/* handle also UI2 here */
      cuts[0] = (float) mnvi; cuts[1] = (float) mxvi;
      }
   else 
      {
      if (MAXFLOAT<mnvd) 
         mnvd = MAXFLOAT;
      else if (mnvd<MINFLOAT) 
         mnvd = MINFLOAT;
      if (MAXFLOAT<mxvd) 
         mxvd = MAXFLOAT;
      else if (mxvd<MINFLOAT) 
         mxvd = MINFLOAT;
      cuts[0] = mnvd; cuts[1] = mxvd;
      }
    SCDWRR(mfd,"LHCUTS",cuts,3,2,unit);

   }


if (Midas_flag == 0)
   {
   if (0<=mfd) (void) SCFCLO(mfd);		/* close data file  */
   if (0<=mfdt) 
      { 
      (void) TCSINI(mfdt);
      (void)  TCTCLO(mfdt);
      }
   mfd = -1; mfdt = -1;
   }

return 0;
}


