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

/*+++++++++++++++++++++ Module midfcta +++++++++++++++++++++++++++++++++++++++
.LANGUAGE   C
.IDENTIFICATION  midfcta.c
.AUTHOR   Klaus Banse
.KEYWORDS Midas utility routines.
.ENVIRONMENT VMS and UNIX
.COMMENTS
holds MID_INITFR, MID_FCTIN

.VERSION  

 100222		last modif
------------------------------------------------------------------------*/
 
#include <fileexts.h>
#include <osyparms.h>
#include <computer.h>
#include <stdlib.h>
#include <string.h>
#include <osparms.h>
 

#define   BIT_0   0x1

#define FILE_MASK 0     /* CG. 920529: Set to 0. osfcreate() makes default */
/*

*/
 
int MID_INITFR(name,dattype,filtype,sizze,optio,entrx)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.KEYWORDS
frame control table, initialisation
.PURPOSE
create + initialize a new frame
.ALGORITHM
create a new bulk data frame
set up the 1. virtual block as frame control block, FCB
reserve the next 44 blocks as LDB's for the standard descriptors
data starts from virtual block 46 on (first block = #1)
.RETURNS
status:	I*4		return status
-----------------------------------------------------*/
 
char   *name;	  /* IN : translated frame name with type */
int dattype;      /* IN : type of data, I*1, I*2, I*4, R*4  */
int filtype;      /* IN : type of frame */
size_t sizze;	  /* IN : no. of pixels in frame 
			  if < 0, we only want to create the file header */
int *optio;	  /* IN : optio[0] = 1 for cloning, else 0
			  optio[1] = imno of source image (if optio[0] = 1) */
int *entrx;       /* OUT: FCT entry number (= index) */
 
{
int   n, mm, status, iochan;
int   savftype, dscdsiz, myentry, source_entry;
int   dummy_data;

unsigned int  nvb;
unsigned int  ext_size, data_bytes;
register int  nr;

long int  *lptr, oshtime();

size_t  kldb[2], nrldb, data_start;
size_t  alq, nblock, reqbytes;
size_t  *sptr;

static int swapshort = SWAPSHORT;
static int swapint = SWAPINT;
static int floatfmt = FLOATFMT;

struct FCB_STRUCT  *fcbp, *source_fcbp;

struct FCT_STRUCT  *fctpntr, *source_fctpntr;

static char Midvers[] = "VERS_120";		/* as of 090401 */




 
/* calculate no. of blocks needed for data */
 
data_bytes = get_byte(dattype);
dummy_data = 0;

if (sizze < 1) 				/* that means F_H_MODE ... */
   {
   savftype = filtype;
   filtype = -99;
   sizze = 0;				/* just to underline... */
   nblock = 0;				/* no data yet */
   }

else
   {
   nblock = (size_t) data_bytes * sizze;	/* check for overflow... */
   if (unlikely(nblock > KIWORDS[OFF_AUX+19])) /* AUX_MODE(20) = max int */
      {
      status = ERR_OUTLIM;
      goto end_of_it;
      }

   savftype = -1;
   mm = OUR_BLOCK_SIZE - 1;

   if (filtype < 11) 				/* binary Midas format */
      nblock += mm;
   else 					/* intl FITS files */
      nblock = data_bytes + mm;
   
   nblock /= OUR_BLOCK_SIZE;
   }


/*  calculate size of descr. directory and no. of LDBs needed for it  */

mm = (FCT.PARM[0] + 1) * YENTRY_SIZE;	/* total size: with dscdir */
ext_size = 6000;

nvb = ((mm - 1)/ext_size) + 1;			/* no. of extensions needed */
dscdsiz = (nvb * ext_size) + 12;		/* size of descr_dir and 
					its atom header (which is = 3 ints) */
kldb[0] = ((dscdsiz - 1)/LDB_DATA) + 1;	/* LDBs needed for dscdir */
n = (FCT.PARM[0]*12) + FCT.PARM[1];	/* 12 bytes atom header per descr */
kldb[1] = ((n - 1)/LDB_DATA) + 1;		/* LDBs needed for dsc data */


/*  calculate initial no. of LDBs needed for descr. data  */

if (*optio == 0)
   {
   source_entry = -1;
   source_fctpntr = NULL;
   source_fcbp = NULL;
   data_start = 0;
   nrldb = kldb[0] + kldb[1];
   }

else			/* cloning possible from VERSION_105 on */   
   {
   source_entry = *(optio+1);		/* get imno of source frame */
   source_fctpntr = FCT.ENTRIES + source_entry;
   source_fcbp = source_fctpntr->FZP;


   nvb = source_fcbp->LEXBDF;
   data_start = source_fcbp->D1BLOCK;

   /* check, if descriptors already extended over data block */

   if (nvb > data_start)
      {
      if ((data_bytes != get_byte(source_fctpntr->FORMAT)) ||
          (sizze != source_fctpntr->SIZE))
         {				/* need same no. of data blocks */
         status = ERR_NOCLON;		/* for cloning */
         goto end_of_it;
         }

      if (source_fcbp->FITSINF1 > 0) /* internal FITS file, no data yet */
         {
         n = source_fcbp->LEXBDF - 2;
         kldb[0] =  n/4;
         kldb[1] =  0;
         dummy_data = 1;
         data_start = source_fcbp->LEXBDF + 1;
         }
      else
         {
         kldb[0] = source_fcbp->INLDB[0];
         kldb[1] = source_fcbp->INLDB[1];
         }
      }
   
   nrldb = source_fcbp->NOLDB;         /* use same no. of LDBs */
   }

alq = 1 + (4*nrldb) + dummy_data + nblock;	/* 1 FCB + nrldb LDBs + data */
						/* an LDB = 4 blocks */

/*
printf("MID_INITFR: *optio = %d, sizze = %d, kldb[0,1] = %d, %d\n",
       *optio,sizze,kldb[0],kldb[1]);
printf("INITFR: nrldb = %d, dummy_data = %d, nblock = %d\n",
       nrldb,dummy_data,nblock);
*/

 
/* check, that no such file is already in FCT + create frame */
 
n = MID_FINDFR(name);
if (n >= 0) return (-99);	/* tell SCFCRE that file should be closed */

/*
printf("INITFR: dscdsiz = %d, ext_size = %d, noext = %d, alq = %ld\n",
dscdsiz,ext_size,nvb,alq);
*/

/* create file on disk */

myentry = *entrx;


if (filtype > 10) 			/* is it a memory file? */
   {
   status = MID_VMEM(1,(int) alq,&iochan);	/* allocate memory for file */
   if (status != ERR_NORMAL) goto end_of_it;

   /* do what MID_ACCFRM would do */

   myentry = MID_CREFRE(name,0);	/* create one more entry */

   if (myentry < 0) 
      {
      status = ERR_FILNAM;
      goto end_of_it;
      }

   fctpntr = FCT.ENTRIES + myentry;
   fctpntr->COMPRESS = 0;
   fctpntr->IOCHAN = iochan;
#if vms
   fctpntr->FILEIDA = iochan;
   fctpntr->FILEIDB = iochan;
#else
   fctpntr->FILEID = iochan;
#endif
   fctpntr->CATALOG[1] = 'N';

   fcbp = fctpntr->FZP;
   memset((void * )fcbp,32,(size_t)512);		/* init FCB to ' ' */

   nvb = (int) alq;			/* now, nvb = total no. of blocks */
   goto type_switch;
   }

else
   {

#if vms

   FSY_CREBDF(name,(int)strlen(name),(int) alq,&nvb,&status); 
   if ( !(status & BIT_0) )
      {
      MID_ERROR("FSY","MID_INITFR: ",status,0);
      status = ERR_FRMNAC;
      goto end_of_it;
      }

#else

   reqbytes = alq * (size_t) OUR_BLOCK_SIZE;
   mm = osfcreate(name,reqbytes,FILE_MASK);
   if (mm != 1)
      {
      MID_ERROR("FSY","MID_INITFR: ",mm,0);
      status = ERR_FRMNAC;
      goto end_of_it;
      }

   nvb = (unsigned int) alq;

#endif
   }

 
/* use MID_ACCFRM to open file again + get FCB in  */

status = MID_ACCFRM(name,2,&myentry,&n);
if (status != ERR_NORMAL) goto end_of_it;
 
fctpntr = FCT.ENTRIES + myentry;
iochan = fctpntr->IOCHAN;
fcbp = fctpntr->FZP;
memset((void * )fcbp,32,(size_t)512);		/* init FCB to ' ' */

 
/*   fill FCB.BDTYPE with type of frame  */
 
type_switch:
fcbp->FITSINF1 = 0;
fcbp->FITSINF2 = 0;
fcbp->NOLDB = nrldb;				/* save no. of LDBs */
fctpntr->ACCESS = 'O';				/* set to write access */
sptr = (size_t *) fcbp->XNDVAL;
*sptr = sizze;                          /* fill FCB.XNDVAL */
fcbp->NDVAL = (unsigned int) sizze;	/* and FCB.NDVAL as well */
 
switch(filtype)
   {
 case F_IMA_TYPE:
   (void)strcpy(fcbp->BDTYPE,"IMAGE  ");
   break;
   
 case F_TBL_TYPE:
   (void)strcpy(fcbp->BDTYPE,"TABLE  ");
   break;
   
 case F_FIT_TYPE:
   (void)strcpy(fcbp->BDTYPE,"FITFILE");
   break;
   
 case F_FIMA_TYPE:				/* FITS files */
   (void)strcpy(fcbp->BDTYPE,"IMAGE-F");
   fcbp->NDVAL = 1;
   *sptr = (size_t) 1;
   fcbp->FITSINF1 = (unsigned int) sizze;
   sptr = (size_t *) fcbp->XFITSINF1;
   *sptr = sizze;                          /* fill FCB.XFITSINF1 */
   fctpntr->ACCESS = 'I';			/* not really a new file */
   break;
   
 case F_FTBL_TYPE:
   (void)strcpy(fcbp->BDTYPE,"TABLE-F");
   fcbp->NDVAL = 1;
   *sptr = (size_t) 1;
   fcbp->FITSINF1 = (unsigned int) sizze;
   sptr = (size_t *) fcbp->XFITSINF1;
   *sptr = sizze;                          /* fill FCB.XFITSINF1 */
   fctpntr->ACCESS = 'I';			/* not really a new file */
   break;
   
 case F_FFIT_TYPE:
   (void)strcpy(fcbp->BDTYPE,"FITFI-F");
   fcbp->NDVAL = 1;
   *sptr = (size_t) 1;
   fcbp->FITSINF1 = (unsigned int) sizze;
   sptr = (size_t *) fcbp->XFITSINF1;
   *sptr = sizze;                          /* fill FCB.XFITSINF1 */
   fctpntr->ACCESS = 'I';			/* not really a new file */
   break;
   
 case -99:
   if (savftype == F_IMA_TYPE)
      (void)strcpy(fcbp->BDTYPE,"IMAGE  ");
   else 
      (void)strcpy(fcbp->BDTYPE,"TABLE  ");
   fcbp->NDVAL = 0;
   *sptr = (size_t) 0;
   break;
   
 default:	
   status = ERR_INPINV;
   goto end_of_it;
   }
 
 
/*  fill frame control block 
 
for (nr=22; nr<28; nr++) fcbp->CREATE[nr] = ' '; */

OSY_ASCTIM(fcbp->CREATE);		/* get current time  (26 chars.) */
lptr = (long int *) fcbp->CRETIM;
*lptr =  oshtime();

fcbp->DSCFLAG = 'Y';			/* indicate new descr. stuff */
(void)strncpy(fcbp->VERSION,Midvers,8);

fcbp->PROT = 0;
fcbp->INCARN = 1;
fcbp->INLDB[0] = kldb[0];
fcbp->INLDB[1] = kldb[1];
fcbp->DBEGIN = dscdsiz;			/* inital size of descr. directory */
fcbp->NOBYT = data_bytes;
fcbp->DFORMAT = dattype;
			      /* no. of data values (pixels) per page/block */
fcbp->PIXPBL = OUR_BLOCK_SIZE / data_bytes;
fcbp->DLBLOCK = (int) alq;

if (sizze == (size_t)0)		/* no data (yet) */
   fcbp->D1BLOCK = -1;		/* no start block of data (yet) */
else
   {
   if (source_entry == -1)
      fcbp->D1BLOCK =			/* 1st block after LDB area */
         1 + (4*(fcbp->INLDB[0]+fcbp->INLDB[1])) + 1;
   else
      fcbp->D1BLOCK = data_start;
   }

fcbp->PTRLDB = 2;			/* point to first LDB  (= VBN 2) */
if (source_entry == -1)
   fcbp->LEXBDF = (unsigned int) alq;	/* log. file ext. -> last data block*/
else
   fcbp->LEXBDF = source_fcbp->LEXBDF;

/* physical file extension (cluster fact.of disk) */

fcbp->PEXBDF = (unsigned int) nvb;
fcbp->NEXT = 0;				/* we only have 1 FCB */
 

/* fill updated values into FCT  */

fctpntr->SIZE = sizze;
fctpntr->NOBYTE = fcbp->NOBYT;
fctpntr->FORMAT = fctpntr->DATTYP = fcbp->DFORMAT;
fctpntr->PIXPBL = fcbp->PIXPBL;
fctpntr->STBLOK = fcbp->D1BLOCK;
fctpntr->CATALOG[0] = fcbp->BDTYPE[0];

if (swapshort == 12)
   fcbp->SWPSHORT = '=';
else if (swapshort == 21)
   fcbp->SWPSHORT = 's';
else
   {
   status = ERR_INSBAD;
   goto end_of_it;			/* do this check only once */
   }

if (swapint == 1234)
   fcbp->SWPINT = '=';
else if (swapint == 4321)
   fcbp->SWPINT = 's';
else if (swapint == 2143)
   fcbp->SWPINT = 'h';
else 					/* if (swapint == 3412) */
   fcbp->SWPINT = 'w';
   
if (floatfmt == IEEEFLOAT)
   fcbp->FLOTFMT = '=';

#if vms
else if (floatfmt == VAXFLOAT)
   fcbp->FLOTFMT = 'V';
else if (floatfmt == VAXGFLOAT)
   fcbp->FLOTFMT = 'G';
#endif

else 					/* if (floatfmt == HPFLOAT) */
   fcbp->FLOTFMT = 'H';


*entrx = myentry;


/* set the 6 basic info values for easy reading of data files  */
 
for (nr=0; nr<4; nr++) fcbp->DATAINFO[nr] = 0;
fcbp->DATAINFO[4] = fcbp->DFORMAT;
fcbp->DATAINFO[5] = (fcbp->D1BLOCK - 1) * OUR_BLOCK_SIZE;

if (source_entry == (-1))
   status = MID_INITDS(fcbp,iochan);
else
   status =  MID_CLONEDS(fcbp,iochan,source_fctpntr);

if (status == ERR_NORMAL) 
   status = OSY_WVB(fctpntr->IOCHAN,(char *)fcbp,OUR_BLOCK_SIZE,1);

if (status == ERR_NORMAL) return status;

 
/*  prepare error messages for higher level routines  */
 
end_of_it:
MID_ERROR("MIDAS","MID_INITFR:",status,0);
return status;
}
/*

*/

int MID_TDCLON(source_entry,dattype,sizze)
/*++++++++++++++++++++++++++++++++++++++++++++++++++
.KEYWORDS
  internal descriptor structure
.PURPOSE
  test, if descr. cloning is possible or not
.RETURN
 = 0, if no 
 = 1, if cloning of descriptors is possible
--------------------------------------------------*/
 
int  source_entry;	/* IN: entry of source image */
int  dattype;		/* IN: data format for new image */
int  sizze;		/* IN: no. of pixels of new image */
 
{
int  data_bytes;

struct FCB_STRUCT  *source_fcbp;

struct FCT_STRUCT  *source_fctpntr;



 

source_fctpntr = FCT.ENTRIES + source_entry;
source_fcbp = source_fctpntr->FZP;


/* if descriptors already wrapped around data, 
   the no. of data blocks must be the same for the new image as for the 
   source image => the original data format must be the same */


if (source_fcbp->LEXBDF > source_fcbp->D1BLOCK)
   {
   data_bytes = get_byte(dattype);	/* bytes per pixel of new frame */
   if ((data_bytes != get_byte(source_fctpntr->FORMAT)) ||
       (sizze != source_fctpntr->SIZE))
      return 0;				/* no descr. cloning possible */
   }

return 1;			/* Yes. we can clone the descriptors */
}

                               /* keep diagnostic printout for later usage...
                               printf("TDCLON: source logext, datstart = %d, 
                               %d\n",source_fcbp->LEXBDF,
                               source_fcbp->D1BLOCK);

                               printf("        source size, b/p = %d, %d 
                               new size, b/p = %d, %d\n",
                               source_fctpntr->SIZE,
                               get_byte(source_fctpntr->FORMAT),sizze,
                               get_byte(dattype));
                               */
/*

*/

int MID_FCTIN(fctnos)
/*++++++++++++++++++++++++++++++++++++++++++++++++++
.KEYWORDS
  frame control table
.PURPOSE
  create the FCT structures for `fctsize' entries
.ALGORITHM
  use malloc + free
.RETURNS
--------------------------------------------------*/
 
int fctnos;	/* IN : no. of entries for extension \
                                if -1, create new structure */
 
{
int  mm, fctsize;
register int  nr, mr;

char    *cptr;
static char  *oldpntr;

struct FCT_STRUCT  *fctpntr, *fctpntro;




/* do not forget to synchronize with $MID_INCLUDE/fctext.h !!! */

if (fctnos == -1)
   {
   fctnos = FCT_MAXENT;			/* use initial value */
   fctsize = (int) (sizeof(struct FCT_STRUCT) * fctnos) + 4; 
   cptr = malloc((size_t)fctsize);
   if (cptr == NULL)
      {
      (void)printf("could not allocate %d bytes for FCT table\n\r",fctsize);
      ospexit(0);
      }

   FCT.ENTRIES = (struct FCT_STRUCT *) cptr;

   fctpntr = FCT.ENTRIES;		/* clear FCT entries */
   for (nr=0; nr<fctnos; nr++)
      {
      fctpntr->NAME[0] = ' ';
      fctpntr->NAME[1] = '\0';
      fctpntr ++;
      }
   }

else
   {
   mm = FCT.MAXENT;		/* save old stuff for the moment */
   fctpntro = FCT.ENTRIES;

   fctsize = (int) (sizeof(struct FCT_STRUCT) * fctnos) + 4; 
   cptr = malloc((size_t)fctsize);
   if (cptr == NULL)
      {
      (void)printf("could not allocate %d bytes for FCT table\n\r",fctsize);
      ospexit(0);
      }

   FCT.ENTRIES = (struct FCT_STRUCT *) cptr;

   fctpntr = FCT.ENTRIES;		/* clear FCT entries */
   for (nr=0; nr<fctnos; nr++)
      {
      fctpntr->NAME[0] = ' ';
      fctpntr ++;
      }


   /*  now copy old entries over */

   fctpntr = FCT.ENTRIES;			/* reset pointer to begin */
   for (nr=0; nr<mm; nr++)
      {
      if (fctpntro->NAME[0] != ' ')
         {
         fctpntr->NAMLEN = fctpntro->NAMLEN;
         fctpntr->IOCHAN = fctpntro->IOCHAN;
#if vms
         fctpntr->FILEIDA = fctpntro->FILEIDA;
         fctpntr->FILEIDB = fctpntro->FILEIDB;
#else
         fctpntr->FILEID = fctpntro->FILEID;
#endif
         for (mr=0; mr<4; mr++)
            fctpntr->KAUX[mr] = fctpntro->KAUX[mr];
         fctpntr->SIZE = fctpntro->SIZE;
         fctpntr->PROT = fctpntro->PROT;
         fctpntr->COMPRESS = fctpntro->COMPRESS;
         fctpntr->NOBYTE = fctpntro->NOBYTE;
         fctpntr->FORMAT = fctpntro->FORMAT;
         fctpntr->PIXPBL = fctpntro->PIXPBL;
         fctpntr->STBLOK = fctpntro->STBLOK;
         fctpntr->DATTYP = fctpntro->DATTYP;
         fctpntr->FILTYP = fctpntro->FILTYP;
         fctpntr->FITSEXT = fctpntro->FITSEXT;
         fctpntr->LINK[0] = fctpntro->LINK[0];
         fctpntr->LINK[1] = fctpntro->LINK[1];
         fctpntr->CR_FLAG = fctpntro->CR_FLAG;
         fctpntr->O_NAMLEN = fctpntro->O_NAMLEN;
         (void)strcpy(fctpntr->NAME,fctpntro->NAME);
#if vms
         (void)strcpy(fctpntr->DEVICE,fctpntro->DEVICE);
#endif
         for (mr=0; mr<4; mr++)
            fctpntr->BDADDR[mr] = fctpntro->BDADDR[mr];
         fctpntr->PNTR = fctpntro->PNTR;
         for (mr=0; mr<3; mr++)
            fctpntr->FITSADDR[mr] = fctpntro->FITSADDR[mr];
         fctpntr->CATALOG[0] = fctpntro->CATALOG[0];
         fctpntr->CATALOG[1] = fctpntro->CATALOG[1];
         fctpntr->ACCESS = fctpntro->ACCESS;
         fctpntr->FZP = fctpntro->FZP;
         }
      fctpntr ++;
      fctpntro ++;
      }

   free(oldpntr);
   }


FCT.MAXENT = fctnos;
oldpntr = cptr;				/* save old char. pointer */
return 0;
}
