/*===========================================================================
  Copyright (C) 1995-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      fitsrbt.c
.LAUGUAGE   C
.AUTHOR     P.Grosbol   ESO/IPG
.KEYWORDS   FITS binary table extension, decode, read
.COMMENT    read the binary table extension of FITS file
.VERSION    1.0  1989-Feb-24 : Creation,   PJG 
.VERSION    1.1  1990-Feb-04 : Change call-seq. for cv-routine, PJG 
.VERSION    2.0  1991-Mar-23 : Change call-seq. add TCA routines, PJG 
.VERSION    2.1  1991-Apr-17 : Correct for zero with columns, PJG 
.VERSION    2.2  1991-Sep-23 : Add C,M,P field types, PJG 
.VERSION    2.3  1992-Aug-12 : Correct count for scale-loop, PJG 
.VERSION    2.35 1992-Aug-12 : Read PCOUNT/Heap area, PJG 
.VERSION    2.3  1993-Oct-26 : Update to new SC/TC + prototypes, PJG 
.VERSION    2.4  1993-Nov-11 : Correction of count for X-format, PJG 
.VERSION    2.5  1996-Dec-13 : Correct NULL value for scaled integers, PJG 
.VERSION    2.7  1998-Apr-22 : Change BTABLE 'B' format to I2, PJG

 111201		last modif
---------------------------------------------------------------------*/

#include   <computer.h>
#include   <fitsfmt.h>
#include   <fitsdef.h>
#include   <fitsextvals.h>
#include   <fitskwt.h>
#include   <midas_def.h>
#include   <tblsys.h>             /* Table System parameters      */
#include   <tbldef.h>             /* Symbols used for Tables      */


typedef union {                /* aligned buffer for single entry */
                unsigned char  *b;
                char           *c;
                short          *s;
                int            *i;
                float          *f;
                double         *d;
              } BUF;

int fitsrbt(mfd,bfdef,size,Midas_flag)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE       Read binary table extension in FITS
.RETURN        error code - 0: OK, -1: error
---------------------------------------------------------------------*/
int       mfd;                  /* IN: MIDAS file descriptor         */
BFDEF     *bfdef;               /* IN: pointer to FITS parm's        */
int       size;                 /* IN: size of data matrix (bytes)   */
int       Midas_flag;           /* IN: = 0, if from intape.c
				       = 1, if intl FITS tables      */
{
register  char   *pc;
char             *pb;
unsigned char    *pu;

register  int    nc, n, i;
int              nf, nor, nof, nr, nbr, mxfb, nfs;
int              *pi;
short            *ps;
int    xTCAWRI(), xTCAWRC(), xTCAWRR(), xTCAWRD();
float            *pf;

double           *pd;

register  FDEF   *fd;
BUF              buf;
TXDEF            *txdef;
void     *TCTTST();
TABLE    *mytp;


n = 0;
txdef = (TXDEF *) bfdef->extd;
nf = txdef->tfields;
fd = txdef->col;
nbr = bfdef->data[0].naxis;
mxfb = 0;
for (i=0; i<nf; i++, fd++) 
   {
   nfs = fd->trepn * fd->tncpf;
   switch (fd->tdfmt) 
      {
      case 'A' :
      case 'L' : fd->twdth = n = nfs; break;
      case 'X' : fd->twdth = (nfs) ? (nfs-1)/8 + 1 : 0;
                 n = 4*fd->twdth; break;
      case 'B' : fd->twdth = nfs; n = 4*nfs; break;
      case 'S' : fd->twdth = 2*nfs; n = 4*nfs; break;
      case 'I' :
      case 'E' :
      case 'P' :
      case 'C' : fd->twdth = n = 4*nfs; break;
      case 'D' :
      case 'M' : fd->twdth = n = 8*nfs; break;
      default  : SCTPUT("Warning: Invalid format type");
      }
      if (mxfb<n) mxfb = n;
   }

buf.c = (char *) osmmget(mxfb+1);      /* get buffer largest entry   */
if (!buf.c) 
   {
   SCTPUT("Error: cannot allocate line buffer");
   TCTCLO(mfd); mfd = -1;
   return -1;
   }
buf.c[mxfb] = '\0';

mytp = (TABLE *)TCTTST(mfd);
if ((i = CheckTable(mytp)))
   {
   SCTPUT("TBL_Error with table pointer...");
   TCTCLO(mfd); mfd = -1;
   return -11;
   }



n  = 0;                                /* bytes in read buffer       */
nr = bfdef->data[1].naxis;             /* no. of rows to read        */

for (nor=1; nor<=nr; nor++)
   {					/* read row by row            */
   if ((i = CheckRow(mytp,nor)))
      {
      SCTPUT("TBL_Error with table row...");
      TCTCLO(mfd); mfd = -1;
      return -12;
      }

   fd = txdef->col;
   for (nof=1; nof<=nf; nof++, fd++) 
      {					/* transfer entry by entry    */
      pc = buf.c; nc = fd->twdth;
      size -= nc;                        /* decrement remaining bytes  */
      if (!nc) continue;                 /* skip zero width columns     */

      while (n<nc)
         {                     /* field across record limit  */
	 nc -= n;
	 while (n--) *pc++ = *pb++;       /* copy bytes to entry buffer */
	 if ((n=dread(&pb,FITSLR))!=FITSLR) 
            {
	    if (!size) 
	       SCTPUT("Warning: incomplete FITS record read!");
	    else 
               {
	       SCTPUT("Error: unexpected EOF");
	       TCSINI(mfd);
	       TCTCLO(mfd); mfd = -1;
	       osmmfree(buf.c);               /* free line buffer and return */
	       return NOFITS;
	       }
	    }
         }
      n -= nc;
      while (nc--) *pc++ = *pb++;        /* copy bytes to entry buffer */

      nfs = fd->trepn * fd->tncpf;
      switch (fd->tdfmt) 
         {		               /* convert data if needed     */
	 case  'X' : nfs = (nfs) ? (nfs-1)/8+1 : 0;
                     pi = buf.i + nfs; pu = buf.b + nfs;
                     i = nfs;
	             while (i--) *(--pi) = *(--pu);
	             break;
	 case  'B' : pi = buf.i + nfs; pu = buf.b + nfs;
                     i = nfs;
	             while (i--) *(--pi) = *(--pu);
	             if (fd->nflag) 
                        {
		        i = nfs;
		        while (i--) 
                           {
			   if (*pi == fd->tnnul) toNULLINT(*pi); pi++;
		           }
		        }
	             break;
	 case  'S' : if (!same_comp_i2) cvi2(buf.s,nfs,0);

                     /* we cannot copy the I2 data to I4, because
		        xTCAWRI uses the int buffer as container for I2 data...
		     pi = buf.i + nfs; ps = buf.s + nfs;
                     i = nfs;
	             while (i--) *(--pi) = *(--ps);
	             if (fd->nflag) {
		       i = nfs;
		       while (i--) {
			 if (*pi == fd->tnnul) toNULLINT(*pi); pi++;
		         }
		       }   */

                     break;
	 case  'P' :			/* 'P' and 'I' are written twice... */
	 case  'I' : if (!same_comp_i4) cvi4(buf.i,nfs,0);
	             if (fd->nflag) {
		       i = nfs; pi = buf.i;
		       while (i--) {
			 if (*pi == fd->tnnul) toNULLINT(*pi); pi++;
		       }
		     }
                     xTCAWRI(mytp,mfd,nor,nof,nfs,buf.i);  
	             break;
	 case  'C' :
	 case  'E' : cvr4(buf.f,nfs,0); break;
	 case  'M' :
	 case  'D' : cvr8(buf.d,nfs,0); break;
         }

      switch (fd->tdfmt) 
         {	         /* scale and store data in table   */
	 case  'L' : 
	 case  'A' : if (*buf.c) xTCAWRC(mytp,mfd,nor,nof,nfs,buf.c);
	             break;
         case  'S' : xTCAWRI(mytp,mfd,nor,nof,nfs,buf.i);  /* buf.i = buf.s */
                     break; 
         case  'X' :
	 case  'B' :
         case  'I' : if (fd->sflag) 
                        {
	                i = nfs; pf = buf.f; pi = buf.i;
		        while (i--) 
                           { 
			   if (!isNULLINT(*pi))
			      *pf = fd->tscal * (*pi) + fd->tzero;
			   else
			      toNULLFLOAT(*pf);
			   pi++; pf++;
		           }
                        xTCAWRR(mytp,mfd,nor,nof,nfs,buf.f);
		        }
	             else 
                        xTCAWRI(mytp,mfd,nor,nof,nfs,buf.i);
	             break;
	 case  'P' : xTCAWRI(mytp,mfd,nor,nof,nfs,buf.i);
	             break;
	 case  'C' :
	 case  'E' : if (fd->sflag) 
                        {
                        i = nfs; pf = buf.f;
		        while (i--) 
                           { 
			   if (!isNULLFLOAT(*pf))
			      *pf = fd->tscal * (*pf) + fd->tzero;
			   pf++;
		           }
		        }
                     xTCAWRR(mytp,mfd,nor,nof,nfs,buf.f);
                     break;
	 case  'M' :
	 case  'D' : if (fd->sflag) 
                        {
	                i = nfs; pd = buf.d;
		        while (i--) 
                           { 
			   if (!isNULLDOUBLE(*pd))
			      *pd = fd->tscal * (*pd) + fd->tzero;
			   pd++;
		           }
		        }
                     xTCAWRD(mytp,mfd,nor,nof,nfs,buf.d);
                     break;
         }
      }
   }

while (0<size)
   {                       /* read PCOUNT bytes from heap */
   if (n<1) 
      {
      if ((n=dread(&pb,FITSLR))!=FITSLR) 
         {
	 if (size<=n)
	    SCTPUT("Warning: incomplete FITS record read!");
	 else 
            {
	    SCTPUT("Error: unexpected EOF");
            TCSINI(mfd);
	    TCTCLO(mfd); mfd = -1;
	    osmmfree(buf.c);             /* free line buffer and return */
	    return NOFITS;
	    }
	 }
      }
   nc = (size<n) ? size : n;
   size -= nc;                        /* decrement remaining bytes    */
   n = 0;
   while (nc--) *pb++;                /* here store 'n' bytes of heap */
   }

osmmfree(buf.c);                      /* free line buffer and return  */
if ((0 <= mfd) && (Midas_flag == 0))
   TCTCLO(mfd);               /* close MIDAS table file (no TCSINI!) */

mfd = -1;
return 0;
}
