/*===========================================================================
  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      fitsmdb.c
.LAUGUAGE   C
.AUTHOR     P.Grosbol   ESO/IPG
.KEYWORDS   MIDAS descriptor buffer
.COMMENT    Define buffer for MIDAS descriptors
.VERSION    1.0  1991-Mar-19 : Creation,   PJG
.VERSION    1.1  1993-Feb-23 : Return pointer to structure,   PJG
.VERSION    1.2  1993-Jul-05 : Save keyword commends,   PJG
.VERSION    1.3  1993-Sep-27 : strlen() used for SCDWRC() instead of 72. CG.
.VERSION    1.4  1993-Oct-26 : Update to new SC + prototypes, PJG
.VERSION    1.5  1993-Dec-13 : Disable SC-error handling for descriptors, PJG
.VERSION    1.6  1994-Jan-11 : Check zero length desc. history, PJG
.VERSION    1.7  1996-Oct-22 : Correct length of descriptor names, PJG

 110215 	last modif

---------------------------------------------------------------------*/

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

#include   <fitsfmt.h>
#include   <fitsdef.h>
#include   <fileexts.h>

static     int first = 0;
static     int   nmdb;		/* no. of entries in keyword buffer */
static     int   max_nmdb;	/* current limit of mdb */
static     int   mdbsiz;	/* size of MDBUF */
static     MDBUF  *mdbptr;	/* pointer to MIDAS descriptor buffer */
static     MDBUF  *myptr;	/* working pointer */

/*

*/

MDBUF *mdb_init()
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE    initiate the MIDAS descriptor buffer
.RETURN     pointer to internal MIDAS descriptor buffer 
---------------------------------------------------------------------*/

{

(void) mdb_cont(0,0,(char *)0,(char *)0);


nmdb = 0;

if (first == 0)
   {				/* keep to single malloc in application */
   int  i;

   mdbsiz = sizeof(MDBUF);

   if (KEYALL.ORIGIN == -1)
      max_nmdb = 1024;			/* outside Midas */
   else if (FCT.PARM[0] > 500)		/* we count on many descriptors... */
      max_nmdb = 1024;			
   else
      max_nmdb = 60;

   i = max_nmdb * mdbsiz;
   mdbptr = (MDBUF *) malloc((size_t) (i));
   if (mdbptr == (MDBUF *) NULL)
      {
      (void)printf
      ("mdb_init: could not allocate %d entries for MDBUF",max_nmdb);
      ospexit(0);
      }
   first = 1;
   }

return mdbptr;
}
/*

*/

MDBUF *mdb_info(nsize)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE    provide current size of MIDAS descriptor buffer
.RETURN     pointer to internal MIDAS descriptor buffer 
	    this pointer may be different from the one returned before
	    by mdb_init(), if the internal buffer size has been increased!!
---------------------------------------------------------------------*/
int  *nsize;

{
*nsize = nmdb;		/* the next (free) index - since 1st index = 0
			   so that's the no. of entries in mdbuf ...  */
return mdbptr;
}

/*

*/

int mdb_put(kw,kwd)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE    put keyword values into MIDAS descriptor buffer
.RETURN     Status 0:OK, 1:error, keyword not stored
---------------------------------------------------------------------*/
KWORD   *kw;
KWDEF   *kwd;

{
int  i, retstat;

char *pc, *ps;




/* if needed, we allocate more space */

if (nmdb >= max_nmdb) 
   {
   int  nsize;
   void  *doof;

   nsize = 2 * max_nmdb * mdbsiz;
   doof = realloc((void *)mdbptr,(size_t)nsize);
   if (doof == (void *)NULL)
      {
      (void)printf
      ("mdb_put: could not reallocate %d bytes for MDBUF",nsize);
      return 1;
      }
   mdbptr = doof;			/* update pointer */
   max_nmdb *= 2;
   }


/* save keyword in buffer */

myptr = mdbptr + nmdb;			/* point to free entry */

myptr->ioff = -1;		/* init to no_comment */
myptr->buf[0] = '\0';
retstat = 0;

ps = myptr->desc;
pc = kwd->desc;
strncpy(ps, pc, MXMDN);

myptr->type = kwd->type;
myptr->idx = kwd->idx;

ps = myptr->buf;
switch (kwd->type) 
   {
   case 'S' : pc = kw->val.pc;
              i = 0;
              while ((*ps++ = *pc++)) i++;
              break;
   case 'L' :
   case 'I' : myptr->val.i = kw->val.i; 
              break;
   case 'R' :
   case 'D' : myptr->val.d[0] = kw->val.d[0];
              myptr->val.d[1] = kw->val.d[1];
              break;
   default  : retstat = 1;
   }

if (kw->pcom)
   {                       /* copy keyword comment    */
   pc = kw->pcom; 
   if (kwd->type == 'S')
      myptr->ioff = i + 1;		/* `i' was length of data string */
   else
      myptr->ioff = 0;

   i = 0;
   while ((*ps++ = *pc++)) i++;	/* ps already positioned comme il faut */
   if (i < 1) myptr->ioff = -1;		/* comment had length = 0 */
   }

nmdb++;			/* increase counter */

return retstat;
}
/*

*/

int mdb_cont(mfd,flag,descr,data)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE    process the CONTINUE keyword in FITS
.RETURN     status  SC error code
---------------------------------------------------------------------*/
int    mfd;		/* IN: MIDAS file no.           */
int    flag;		/* IN: = 0 init lbigbuf
				 = 1 for string with '&'
				 = 2 for CONTINUE	*/
char  *descr;
char  *data;

{
int   unit[4], lastidx;
int   i, k, koff, err, ival, cont_flag, clen;
int   ec, ed, el;
static int  lbigbuf;


char  *dscptr, *cptr, lastchar;
static char bigbuf[1024], lastdsc[24];


/*
printf("mdb_cont: flag = %d\n",flag);
*/


if (flag < 1)
   {
   if ((flag < 0) && (lbigbuf > 0))	/* still descr. waiting... */
      return -1;

   lbigbuf = 0;
   return 0;
   }



ec = ERRO_CONT;
el = ERRO_LOG;
ed = ERRO_DISP;
ERRO_CONT = 1;			/* disable SC-error handling   */
ERRO_LOG = ERRO_DISP = 0;


err = 0;

clen = (int)strlen(data);
k = clen - 1;                          /* index of last char. */
lastchar = *(data+k);

/*
printf("data(size %d):\n%s>\n",clen,data);
printf("lbigbuf = %d, lastchar = %c\n",lbigbuf, lastchar);
*/


if (flag == 2)
   {			/* CONTINUE keyword found */
   if (lbigbuf > 0)
      {                       
      if ((lbigbuf + clen) > 1023)
         {
         SCTPUT
         ("overflow: max. descr. length = 1024 - we cut here...");
         lastchar = ' ';
         }
      else
         {
         lbigbuf --;		/* overwrite the trailing '&' */
         (void) strcpy(bigbuf+lbigbuf,data);
         lbigbuf += clen;	/* point to after '&' */
         }

      if (lastchar == '&')
         {	/* for CONTINUE '...&' => no need to write descr, yet */
/*
         printf("with last char = &, so just copy, lbigbuf = %d, clen = %d\n",
                      lbigbuf,clen);
*/
         }
      else
         {                     /* finally write the descr. */
         *(bigbuf + lbigbuf) = '\0';      /* remove trailing & */
         clen = (int)strlen(bigbuf);
         err = SCDWRC(mfd,lastdsc,1,bigbuf,1,clen,unit);
         lbigbuf = 0;		/* rest length of bigbuf */
/*
         printf("wrote buffer(%d chars) to descr. %s\n%s\n",
                clen,lastdsc,bigbuf);
*/
         }
      }
   else
      {                        /* no continuation => write as COMMENT */
      SCTPUT("keyword CONTINUE => COMMENT");
      err = SCDWRC(mfd,"COMMENT",1,data,-1,clen,unit);
      lbigbuf = 0;
      }
   }

else if (flag == 1)	 	/* descr with '&' as last char. found */
   {
   if (lbigbuf > 0)		/* already char. descr. waiting... */
      err = SCDWRC(mfd,lastdsc,1,bigbuf,1,(int)strlen(bigbuf),unit);
      
   (void) strcpy(bigbuf,data);
   lbigbuf = clen;			/* point to after '&' */
   (void) strcpy(lastdsc,descr);
/*
   printf("descr %s with last char '%c' found: %s\n", lastdsc,lastchar);
*/
   }

else
   {
if (lbigbuf > 0)
      {				/* already char. descr. waiting... */
      err = SCDWRC(mfd,lastdsc,1,bigbuf,1,(int)strlen(bigbuf),unit);
      lbigbuf = 0;
      }
   else
      err = ERR_INPINV;
   }

ERRO_CONT = ec;              /* reset */
ERRO_LOG = el;
ERRO_DISP = ed;              /* instead of SCECNT("PUT",...) */
return err;
}

/*

*/

int mdb_get(mfd)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE    get values from MIDAS descriptor buffer and store them
            in file
.RETURN     status  SC error code
---------------------------------------------------------------------*/
int    mfd;               /* IN: MIDAS file descriptor               */

{
int   unit[4], lastidx;
int   i, k, kk, err, ival, cont_flag, clen;
int   ec, ed, el;
int  SCDWRL();


float fval;

char  *dscptr, *lastdsc, lastchar, *cptr, bigbuf[1024];


ec = ERRO_CONT;
el = ERRO_LOG;
ed = ERRO_DISP;
ERRO_CONT = 1;			/* disable SC-error handling   */
ERRO_LOG = ERRO_DISP = 0;
		/* instead of: n = 1; i = 0; SCECNT("PUT",&n,&i,&i); */


err = 0;
myptr = mdbptr;

for (i=0; i<nmdb; i++) 
   {						/* read MD-buffer      */
   dscptr = myptr->desc;

   switch (myptr->type)
      {
      case 'S':
         cptr = myptr->buf;		
         k = (int)strlen(cptr) - 1;	/* index of last char. */

         if (strcmp(dscptr,"CONTINUE") == 0)
            {
            kk = k;
            while (*(cptr+kk) == ' ') 		/* cut off trailing blanks */
               {
               if (kk < 1) 		/* all blanks, keep original length */
                  goto do_CONT; 
               kk --;
               }
            *(cptr+kk+1) = '\0';

           do_CONT:
            mdb_cont(mfd,2,"CONTINUE",cptr);
            }
         else
            {			
            lastchar = *(cptr+k);
            if (lastchar == '&')
               mdb_cont(mfd,1,myptr->desc,cptr);
            else
               err = SCDWRC(mfd,dscptr,1,cptr,myptr->idx,k+1,unit);
            }
         break;

      case 'L':
         ival = myptr->val.i;
         err = SCDWRL(mfd,dscptr,&ival,myptr->idx,1,unit);
         break;

      case 'I':
         ival = myptr->val.i;
         err = SCDWRI(mfd,dscptr,&ival,myptr->idx,1,unit);
         break;

      case 'R': 
         fval = myptr->val.d[0];
         err = SCDWRR(mfd,dscptr,&fval,myptr->idx,1,unit);
         break;

      case 'D':
         err = SCDWRD(mfd,dscptr,myptr->val.d,myptr->idx,1,unit);
         break;
      }

   if ((myptr->ioff > -1) && (0 < myptr->idx))
      {
      cptr = myptr->buf+myptr->ioff;
      SCDWRH(mfd,dscptr,cptr,-1,(int)strlen(cptr));
      }

   myptr ++;
   }
 
nmdb = 0;				/* reset MDBUF */

ERRO_CONT = ec;              /* reset */
ERRO_LOG = el;
ERRO_DISP = ed;              /* instead of SCECNT("PUT",...) */
return err;
}



