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

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.TYPE        Module
.NAME        tz0.c
.LANGUAGE    C
.AUTHOR      J.D.Ponz  IPG-ESO Garching, Francois Ochsenbein
.CATEGORY    table interface (Design 2.0) low level routines.
.COMMENTS    This module contains the lower level routines handling tables
		for NULL values.
		Note that the choice of NULL value for floating-point
		numbers is badly chosen as the maximal value for
		non-IEEE format, for compatibility with previous
		VAX definitions. The ~0 (i.e. all bits set) would
		have been a better choice, but...

.VERSION  3.0 	01-Jul-1990   Extracted from tz2
.VERSION  3.1 	19-Dec-1990: toNULL set ALL values to NULL.
.VERSION  3.2 	27-Feb-1991: Added TBL_cv2 (Convert between data types)
.VERSION  3.3   22-Sep-1992: treats correctly NULL values (i.e convex)

 090406		last modif
------------------------------------------------------------*/

#include <midas_def.h>		/* General MIDAS Symbols	*/
#include <computer.h>		/* Local computer definitions	*/
#include <tblsys.h>		/* Table System parameters	*/
#include <macrogen.h>		/* Include definition NINT	*/


/*=======================================================================
 *		Test for a null value (may depend on the version...)
 *=======================================================================*/

int TBL_isNULL (dtype, x)
/*+++++++
.PURPOSE Check a SINGLE value is null
.RETURNS 1 (isNULL) / 0 (is NOT null)
-------*/
	int	dtype;	/* IN: Table specific datatype		*/
	int	*x;	/* IN: Value to test			*/
{
	int	isnull;
	
  switch(TBL_ElementType(dtype)) {
    case TBL_D_A1:	isnull = *(char *)x == 0;	break;
    case TBL_D_A2:	isnull = *(short *)x == 0;	break;
    case TBL_D_A4:	isnull = *x == 0;	break;
    case TBL_D_I1:	isnull = isNULL1(x);	break;
    case TBL_D_I2:	isnull = isNULL2(x);	break;
    case TBL_D_I4:	isnull = isNULL4(x);	break;
    case TBL_D_R4: 	isnull = isNULLF(x);	break;
    case TBL_D_R8:	isnull = isNULLD(x);	break;
    default :   	isnull = 0;		break;
  }
  return (isnull);
}

/*=======================================================================
 *		Set a null value (may depend on the version...)
 *=======================================================================*/

int TBL_toNULL (dtype, x)
/*+++++++
.PURPOSE Writes NULL values.
.RETURNS Number of bytes modified.
-------*/
	int	dtype;	/* IN: Table specific datatype		*/
	char	*x;	/* OUT: where to set the NULL value	*/
{
	int	etype, esize, items, bytes;	
	char	*p;
	
  etype = TBL_ElementType(dtype);
  items = TBL_Items(dtype);
  esize = 1 << (etype & 3);	/* Element Size */
  bytes = esize * items;

  switch(etype)	{
    case TBL_D_A1: 
    case TBL_D_A2:
    case TBL_D_A4:
	oscfill(x, bytes, 0);
	break;
    case TBL_D_I1: 
	oscfill(x, bytes, NULL1);
	break;
    case TBL_D_I2:
	for (p = x; --items >= 0; p += esize)	toNULL2(p);
	break;
    case TBL_D_I4:
	for (p = x; --items >= 0; p += esize)	toNULL4(p);
	break;
    case TBL_D_R4:
	for (p = x; --items >= 0; p += esize)	toNULLF(p);
	break;
    case TBL_D_R8:
	for (p = x; --items >= 0; p += esize)	toNULLD(p);
	break;
  }
  return (bytes);
}

/*=======================================================================*/
int TBL_cv2(x1, dtyp1, x2, dtyp2)
/*+++++++
.PURPOSE Convert vector of datatype1 into datatype2
.RETURNS Status as number of overflows, i.e. number of values
	that are out of range
.REMARKS Lengths are assumed to be identical (actually taken from dtyp1)
-------*/
	char	*x1;	/* IN:  Input values to convert			*/
	int	dtyp1;	/* IN:  Table specific datatype of input array	*/
	char	*x2;	/* OUT: Output values (converted)		*/
	int	dtyp2;	/* IN:  Table specific datatype of output array	*/
{
	int	blen1, blen2, etyp1, etyp2, items, k, isnull, over;
	int	aLong;
	double	aReal;
	
aReal = 0.0;
aLong = 0;
k = 0;

  etyp1 = TBL_ElementType(dtyp1);	etyp2 = TBL_ElementType(dtyp2);
  blen1 = 1 << (etyp1 & 3);		blen2 = 1 << (etyp2 & 3);
  items = dtyp1 & TBL_D_MASK;
  over  = 0;			/* Number of Overflows */

		/* k set to 0=I4, 1=double */
  for (; --items >= 0; x1 += blen1, x2 += blen2) {
	isnull = 0;
	switch(etyp1) {
	  case TBL_D_A1: aLong = *(unsigned char *)x1;	
		k = 0;	isnull = 0;			    break;
	  case TBL_D_A2: aLong = *(unsigned short *)x1;	
		k = 0;	isnull = 0;			    break;
	  case TBL_D_A4: aReal = *(unsigned int *)x1;
		k = 1;	isnull = 0;			    break;
	  case TBL_D_I1: isnull = isNULL1(x1);
		k = 0; 	if (!isnull) aLong = *x1;	    break;
	  case TBL_D_I2: isnull = isNULL2(x1);
		k = 0;  if (!isnull) aLong = *(short *)x1;  break;
	  case TBL_D_I4: isnull = isNULL4(x1);
		k = 0; 	if (!isnull) aLong = *(int *)x1;    break;
	  case TBL_D_R4: isnull = isNULLF(x1);
		k = 1; 	if (!isnull) aReal = *(float *)x1;  break;
	  case TBL_D_R8: isnull = isNULLD(x1);
		k = 1; 	if (!isnull) aReal = *(double *)x1; break;
  	}
	if (isnull) switch(etyp2) {
	  case TBL_D_A1: *x2 = 0;			break;
	  case TBL_D_A2: *(short *)x2 = 0;		break;
	  case TBL_D_A4: *(int *)x2  = 0;		break;
	  case TBL_D_I1: toNULL1(x2);			break;
	  case TBL_D_I2: toNULL2(x2);			break;
	  case TBL_D_I4: toNULL4(x2);			break;
	  case TBL_D_R4: toNULLF(x2);			break;
	  case TBL_D_R8: toNULLD(x2);			break;
	} 
	else if (k) switch(etyp2) {		/* From aReal */
	  case TBL_D_A1: 
		if ((aReal < 0) || (aReal > 0xff))	
			*(char *)x2 = 0xff, over++;
		else	*x2 = NINT(aReal);			break;
	  case TBL_D_A2: 
		if ((aReal < 0) || (aReal > 0xffff))	
			*(short *)x2 = 0xffff, over++;
		else	*(unsigned short*)x2 = NINT(aReal);	break;
	  case TBL_D_A4: 
		if ((aReal < 0) || (aReal > (unsigned)0xffffffff))	
			*(int *)x2 = 0xffffffff;
		else	*(unsigned int *)x2 = NINT(aReal);	break;
	  case TBL_D_I1: 
		if ((aReal <= NULL1) || (aReal > 127))	
			toNULL1(x2), over++;
		else	*x2 = NINT(aReal);			break;
	  case TBL_D_I2: 
		if ((aReal < MINSHORT) || (aReal > MAXSHORT))	
			toNULL2(x2), over++;
		else	*(short *)x2 = NINT(aReal);		break;
	  case TBL_D_I4: 
		if ((aReal < -MAXINT) || (aReal > MAXINT))	
			toNULL4(x2), over++;
		else	*(int *)x2 = NINT(aReal);		break;
	  case TBL_D_R4: 
		if ((aReal < -MAXFLOAT)||(aReal > MAXFLOAT))
			toNULLF(x2), over++;
		else	*(float  *)x2 = aReal;			break;
	  case TBL_D_R8: *(double*)x2 = aReal;			break;
	} 
	else switch(etyp2) {			/* From aLong */
	  case TBL_D_A1: 
		if ((aLong < 0) || (aLong > 0xff))	
			*(char *)x2 = 0xff, over++;
		else	*x2 = aLong;			break;
	  case TBL_D_A2: 
		if ((aLong < 0) || (aLong > 0xffff))	
			*(short *)x2 = 0xffff, over++;
		else	*(unsigned short*)x2 = aLong;	break;
	  case TBL_D_A4: 
		if (aLong < 0) 
			*(int *)x2 = 0xffffffff;
		else	*(unsigned int *)x2 = aLong;	break;
	  case TBL_D_I1: 
		if ((aLong <= NULL1) || (aLong > 127))	
			toNULL1(x2), over++;
		else	*x2 = aLong;			break;
	  case TBL_D_I2: 
		if ((aLong < MINSHORT) || (aLong > MAXSHORT))	
			toNULL2(x2), over++;
		else	*(short *)x2 = aLong;		break;
	  case TBL_D_I4: *(int *)x2 = aLong;		break;
	  case TBL_D_R4: *(float *)x2 = aLong;	break;
	  case TBL_D_R8: *(double*)x2 = aLong;	break;
	}
  }

  return (over);
}
/*=======================================================================*/

	/* This Routine is just here to allow a conversion from
	   New Format (3D) to Old. Delete it afterwards...
	*/

/*=======================================================================*/
int TBL_toMAX(dtype, x)
/*+++++++
.PURPOSE Writes a SINGLE MAX value
.RETURNS Number of bytes modified.
-------*/
	int	dtype;	/* IN: Table specific datatype		*/
	char	*x;	/* OUT: where to set the MAX  value	*/
{
	int	bytes;	/* Returned value	*/
	int	etype;	/* Returned value	*/
	
  etype = TBL_ElementType(dtype);
  bytes = 1 << (etype & 3);

  switch(etype)	{
    case TBL_D_A1: 	*x = 0xff;			break;
    case TBL_D_I1: 	*x = 127;			break;
    case TBL_D_A2:   	*(short *)x  = 0xffff;		break;
    case TBL_D_I2:   	*(short *)x  = 0x7fff;		break;
    case TBL_D_A4:   	*(int *)x   = 0xffffffff;	break;
    case TBL_D_I4:   	*(int *)x   = 0x7fffffff;	break;
    case TBL_D_R8: 	*(double *)x = MAXDOUBLE; 	break;
    case TBL_D_R4: 	*(float *)x  = MAXFLOAT;	break;
  }
  return (bytes);
}
