/*===========================================================================
  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 Massachusetss 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        TZ8.C
.LANGUAGE    C
.AUTHOR      J.D.Ponz  IPG-ESO Garching
.CATEGORY    table interface, low level routines.
.KEYWORDS    Overflow mechanism.
.COMMENTS    This module contains the lower level routines handling tables.
             Column and row overflow mechanism in either record or transposed 
             formats.
	     
       TBL_ALLOCOL(tid, nc)
       TBL_ALLOROW(tid, nr)
       TBL_ADDROW(tid,irow,nr)
       TBL_DELROW(tid,irow,nr)
       
.VERSION 1.0 	25-Mar-1987   Definition JDP
.VERSION 1.1 	17-Jan-1989   Include record file organization
.VERSION 1.2 	25-May-1990   Correct bug in TBL_ALLROW MP
.VERSION 3.0 	01-Jul-1990   New Version with Arrays / Elementary IO
.VERSION 3.1 	03-Dec-1990 Check table number did not change.

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

#include <midas_def.h>		/* General MIDAS Symbols	*/
#include <tblsys.h>		/* Table System parameters	*/
#include <tbldef.h>		/* Symbols used for Tables	*/
#include <tblerr.h>		/* List of Table Errors		*/

#include <macrogen.h>		/* Classical macros		*/



/*=======================================================================
 *		Public Routines
 *=======================================================================*/

int TBL_ALLOCOL(tid, nc)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
		Allocate extra column(s) when no physical space
                is available. The routine restructures the table file.
.ALGORITHM	
                Save old table parameters,
                allocate new columns in an output table,
                copy all table data,
                copy table descriptors,
                close input and output tables,
                delete input table file,
                rename output table file,
                open this table again.
.RETURNS
		Status
-------------------------------------------------------------*/
	int tid	       /* IN:  table identifier */;
	int nc         /* IN:  number of words per record to be allocated */;
{ 
	TABLE 	*tp, *tn;
	int	status;
	int	new_tid, i, j, len, offset;
	char	*source, *dest;
	char	table_name[TBL_NAMLEN+1];



  source = '\0';
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));
  if (nc <= tp->acols)	
  	return (TBL_errf(ERR_TBLCOL, 
  	"expand columns to too small number %d, table: %s", nc, tp->phname));
  if ((tp->swise != F_TRANS))        
  if_not((source = TBL_RD (tp, 0, 4*tp->wsize)))	return(TBL_RDst()); 

  
  if (tp->usname) return(TBL_errf(ERR_TBLFUL, "can't expand view %s",
     tp->usname));
  else if (tp->tflags & TBL__READONLY) 
	return(TBL_errf(ERR_TBLFUL, "can't expand read-only table %s",
		tp->phname));

					/* display warning message */;
 /* TBL_errf(0, "expand to %d columns table: %s", nc, tp->phname); */

					/* allocate new table file; note that
					   mode = number of columns << 16 + mode
					*/
  if (!(nc&1))	nc++;			/* Odd number of Columns */
  i = MAX (tp->colitems, TBL_DALCOL) ;
  if (tp->swise == F_TRANS) i = (i << 16) | (F_O_MODE|F_ALL_FORCE);
  else i = (i << 16) | (F_O_MODE|F_MAP_FORCE|F_ALL_FORCE);
  if ((status = TCTINI(TBL_tmpname, tp->swise, i, nc, tp->arows, &new_tid)))
  	return(status);
  tn = TBL_ptr(new_tid);

					/* copy descriptors */;
  if ((status = SCDCOP(tp->imno, tn->imno, 1, " ")))
  	return(TBL_errf(status, "(in column expansion)"));

		/* Copy those descriptors that will be rewritten by TCTCLO */
  for (j = 0; j < tp->colitems; j++)	tn->dtypes[j] = tp->dtypes[j];
  for (j = 0; j < tp->colitems; j++)	tn->offset[j] = tp->offset[j];
  tn->cols = tp->cols;
  tn->rows = tp->rows;
  tn->kcol = tp->kcol;
  tn->scol = tp->scol;
  tn->swise = tp->swise;
  tn->version= tp->version;
  tn->selected = tp->selected;

					/* copy data 		*/
  len = tp->reclen;			/* Length of 1 record	*/
  dest = tn->addres;
  if (tp->swise == F_TRANS) {       
        offset = 0;
        i = 4*tp->wsize;
        while (i > 0) {
          len = MIN(TBL_EIO_LIMIT/2,i);
          source = TBL_RDF(tp,offset,len,0);
          dest  = TBL_RDF(tn,offset,len,1);
          oscopy (dest, source, len);
          i -= len;
          offset+=len;
          }
        }
  else {
	for (i = tp->arows; --i >= 0; source += len, dest += tn->reclen) 
		oscopy (dest, source, len);
  }
/*
   it is not required to initialize the data in the columns, this will
   be done when the columns are defined
*/

					/* rename table file */;
  if ((status = MID_RETNAM(tp->imno, table_name, sizeof(table_name))))
  	return(TBL_errf(status, "(in column expansion)"));
  if ((status = TCTCLO(tid)))	return(status);
  if ((status = TCTCLO(new_tid)))	return(status);
  if ((status = SCFDEL(table_name)))
  	return(TBL_errf(status, "(in column expansion)"));
  if ((status = SCFRNM(TBL_tmpname, table_name)))
  	return(TBL_errf(status, "(in column expansion)"));
 
  new_tid = tid;	/* Tell that we want to keep the Old Number */
  status = TCTOPN(table_name, F_IO_MODE, &new_tid);
  if ((status == ERR_NORMAL) && (new_tid != tid))
	SCTPUT("++++ Table Number Changed!");

  return (status);
}

int TBL_ALLOROW(tid, nr)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
		Allocate extra row(s) when no physical space
                is available. The routine restructures the table file.
.ALGORITHM	
                Save old table parameters,
                allocate new rows in an output table,
                copy all table data,
                copy table descriptors,
                close input and output tables,
                delete input table file,
                rename output table file,
                open this table again.
.RETURNS
		Status
-------------------------------------------------------------*/
	int tid	       /* IN:  table identifier */;
	int nr         /* IN:  number of rows to be allocated */;
{
	TABLE 	*tp, *tn;
	int	status;
	int	new_tid, i, j, len, dtype, new_rows;
	char	*source0, *source, *dest;
	char	table_name[TBL_NAMLEN+1];


  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));
  if_not(source0 = TBL_RD (tp, 0, 4*tp->wsize))
  	return(TBL_RDst()); 

  if (nr <= tp->arows)	
  	return (TBL_errf(ERR_TBLROW, 
  	"expand tow to too small value %d, table: %s", nr, tp->phname));

  if (tp->tflags & TBL__READONLY) 
	return(TBL_errf(ERR_TBLFUL, "can't expand read-only table %s",
		tp->phname));

					/* display warning message */;
/*  TBL_errf(0, "expand to %d rows table: %s", nr, tp->phname); */


					/* allocate new table file */;

  nr = ( (nr+7)>>3)<<3;		/* Multiple of 8 */
  i = MAX (tp->colitems, TBL_DALCOL) ;
  i = (i << 16) | (F_O_MODE|F_MAP_FORCE|F_ALL_FORCE);
  if ((status = TCTINI(TBL_tmpname, tp->swise, i, tp->acols, nr, &new_tid)))
  	return(status);
  tn = TBL_ptr(new_tid);

					/* copy descriptors */;
  if ((status = SCDCOP(tp->imno, tn->imno, 1, " ")))
  	return(TBL_errf(status, "(in row expansion)"));
		/* Copy those descriptors that will be rewritten by TCTCLO */
  for (j = 0; j < tp->colitems; j++)	tn->dtypes[j] = tp->dtypes[j];
  for (j = 0; j < tp->colitems; j++)	tn->offset[j] = tp->offset[j];
  tn->cols = tp->cols;
  tn->rows = tp->rows;
  tn->kcol = tp->kcol;
  tn->scol = tp->scol;
  tn->swise = tp->swise;
  tn->version= tp->version;

					/* copy data */;
  new_rows = tn->arows - tp->arows;
  if (tp->swise == F_TRANS) {
	for (j=0; j<= tp->cols; j++) {
		source = source0 + TBL_offset (tp, 1, j);
		dest   = tn->addres + TBL_offset (tn, 1, j);
		len    = tp->arows * (j ? tp->bytes[j-1] : sizeof(int));
  		oscopy (dest, source, len);
  		dest  += len;
  		if (j == 0)	
  			for (i = new_rows; --i >= 0; dest += sizeof(int))
  				*(int *)dest = 1;
  		else {
  			len    = ColumnWidth(tp, j);
			dtype  = ColumnType (tp, j);
  			for (i = new_rows; --i >= 0; dest += len)
	  			TBL_toNULL (dtype, dest);
  		}
	}
  }
  else 	{					/* Record organisation	*/
	source = source0;
	dest   = tn->addres;
	len = tp->reclen * tp->arows;
	oscopy (dest, source, len);
	i = tp->arows + 1;
	dest   = tn->addres + TBL_offset (tn, i, 0);
	* (int *)dest = 1;
	source = dest;
	for (j=1; j<= tp->cols; j++) {
		dest   = tn->addres + TBL_offset (tn, i, j);
		TBL_toNULL (ColumnType(tn, j), dest);
	}
	i++;
	dest = tn->addres + TBL_offset (tn, i, j);
	len  = tn->reclen;
	while (i++ < tn->arows)
		dest += oscopy (dest, source, len);
  }
						/* rename table file */;
  if ((status = MID_RETNAM(tp->imno, table_name, sizeof(table_name))))
  	return(TBL_errf(status, "(in row expansion)"));
  if ((status = TCTCLO(tid)))	return(status);
  if ((status = TCTCLO(new_tid)))	return(status);
  if ((status = SCFDEL(table_name)))
  	return(TBL_errf(status, "(in row expansion)"));
  if ((status = SCFRNM(TBL_tmpname, table_name)))
  	return(TBL_errf(status, "(in row expansion)"));
 
  new_tid = tid;	/* Tell that we want to keep the Old Number */
  status = TCTOPN(table_name, F_IO_MODE, &new_tid);
  if ((status == ERR_NORMAL) && (new_tid != tid))
	SCTPUT("++++ Table Number Changed!");

  return (status);
 }
 
int TBL_ADDROW(tid,irow,nr)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
		Add row(s)  
.ALGORITHM	
                Save old table parameters,
                allocate new rows in an output table,
                copy all table data,
                copy table descriptors,		
                close input and output tables,
                delete input table file,
                rename output table file,
                open this table again.
.RETURNS
		Status
-------------------------------------------------------------*/
  int        tid;   /* IN:  table identifier */
  int        irow;  /* IN: position at which rows should be created */ 
  int        nr;    /* IN:  number of rows to be created */

{
  char    *source0,*source,*dest;
  char    table_name[TBL_NAMLEN+1];
  TABLE   *tp,*tn;
  int     new_tid;
  int     dtype;
  int     newrow;
  int     i ,j , status, len;

  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))  
     {
     return(TBL_errs(tid, status,0));
     }
  if_not(source0 = TBL_RD (tp, 0, 4*tp->wsize))
        return(TBL_RDst());
  if (irow > tp->rows) 
     {
     return(ERR_TBLROW);
     }
  i =  MAX(tp->colitems,TBL_DALCOL);
  i = (i << 16) | (F_O_MODE|F_MAP_FORCE|F_ALL_FORCE);
    
/*  SCTPUT("Allocate new table file with newrow = rows + nr rows\n"); */
  newrow = ((tp->rows+nr+7)>>3)<<3;
 
/*  SCTPUT("Initialization of selection flag\n"); */
  status = TCTINI(TBL_tmpname, tp->swise, i, tp->acols, newrow, &new_tid);
  if (status != 0)
     return(status);
  tn = TBL_ptr(new_tid);
  
/*  SCTPUT("Copy descriptors from one frame to another\n"); */         
  status = SCDCOP(tp->imno, tn->imno, 1, " "); 
  if (status != 0)
      return(TBL_errf(status, "(in row expansion)"));
  for (j=0; j<tp->colitems; j++) 
  {
     tn->dtypes[j] = tp->dtypes[j];
  }   
  for (j=0; j<tp->colitems; j++) 
  {
     tn->offset[j] = tp->offset[j];
  }
  tn->cols = tp->cols;      /* no. of columns       */
  tn->rows = tp->rows + nr; /* no. of rows          */
  tn->kcol = tp->kcol;      /* Reference col        */   
  tn->scol = tp->scol;      /* sorted column number */
  tn->swise = tp->swise;
  tn->version = tp->version;
  
  tn->selected = tp->rows + nr; /* selected rows = all rows */
                                /* this was missing PN 12/98*/
  
/*  SCTPUT("Copy data\n"); */
  for (j=0; j<= tp->cols; j++) /* copy data */
  {
     source = source0 + TBL_offset(tp,1,j);
     dest = tn->addres + TBL_offset(tn,1,j);
     len = irow * (j ? tp->bytes[j-1] : sizeof(int));
     oscopy(dest,source,len);
     dest +=len;
     if (j == 0)
     { 
        for (i = nr; --i>=0; dest += sizeof(int))
	{
           *(int *)dest = 1;
	}
     }
     else 
     {
        len = ColumnWidth(tp,j);
        dtype  = ColumnType (tp, j);
        for (i = nr; --i >=0; dest +=len)
	{
           TBL_toNULL(dtype,dest);
	}  
     }
     source += irow  * (j ? tp->bytes[j-1] : sizeof(int));
     len = (tp->rows - irow) * (j ? tp->bytes[j-1] : sizeof(int));
     oscopy(dest,source,len);	
  }
  
/* SCTPUT("Rename table file\n");*/
  status = MID_RETNAM(tp->imno, table_name, sizeof(table_name));
  if (status != 0)
        return(TBL_errf(status, "(in row expansion)")); 
  /*close old and new table*/
  if ((status = TCTCLO(tid)))     return(status);
  if ((status = TCTCLO(new_tid))) return(status);
  if ((status = SCFDEL(table_name)))
        return(TBL_errf(status, "(in row expansion)"));
  if ((status = SCFRNM(TBL_tmpname, table_name)))
        return(TBL_errf(status, "(in row expansion)"));

  new_tid = tid;        /* Tell that we want to keep the Old Number */
  status = TCTOPN(table_name, F_IO_MODE, &new_tid);
  if ((status == ERR_NORMAL) && (new_tid != tid))
  {
        SCTPUT("++++ Table Number Changed!");
  }
  return (status); /*end of TBL_ADDROW*/
 }
/*-----------------------------------------------------------------*/



int TBL_DELROW(tid,irow,nr)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
		Delete row(s)  
.ALGORITHM	
                Save old table parameters,
                allocate new rows in an output table,
                copy all table data,
                copy table descriptors,		
                close input and output tables,
                delete input table file,
                rename output table file,
                open this table again.
.RETURNS
		Status
-------------------------------------------------------------*/
  int        tid;      /* table id                                */
  int        irow;     /* row number where rows should be deleted */
  int        nr;       /* number of rows to be deleted            */
{
  char        *source0,*source,*dest;
  char    table_name[TBL_NAMLEN+1];
  TABLE       *tp,*tn;
  int        new_tid, newrow;
  int         i ,j , status, len;


  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))  return(TBL_errs(tid, status,0));
  for (i=irow; i<irow+nr; i++) if (i > tp->rows) return(ERR_TBLROW);
  if_not(source0 = TBL_RD (tp, 0, 4*tp->wsize))
        return(TBL_RDst());
  i =  MAX(tp->colitems,TBL_DALCOL);
  i = (i << 16) | (F_O_MODE|F_MAP_FORCE|F_ALL_FORCE);

/*  SCTPUT("Allocate new table file with newrow = rows - nr rows\n"); */  
  newrow = ((tp->rows-nr+7)>>3)<<3;
  
  if ((status = TCTINI(TBL_tmpname, tp->swise, i, tp->acols, newrow, 
                 	&new_tid)))
     return(status);
  tn = TBL_ptr(new_tid);
  if ((status = SCDCOP(tp->imno, tn->imno, 1, " ")))
      return(TBL_errf(status, "(in row expansion)"));
  for (j=0; j<tp->colitems; j++) tn->dtypes[j] = tp->dtypes[j];
  for (j=0; j<tp->colitems; j++) tn->offset[j] = tp->offset[j];
  
  tn->cols = tp->cols;
  tn->rows = tp->rows - nr;
  tn->kcol = tp->kcol;
  tn->scol = tp->scol;
  tn->swise = tp->swise;
  tn->version = tp->version;
  tn->selected = tn->rows;  /* no. of selected rows equals no. of rows */
  
  for (j=0; j<= tp->cols; j++) /* copy data */
  {
          source = source0 + TBL_offset(tp,1,j);
          dest = tn->addres + TBL_offset(tn,1,j);
          len = (irow -1) * (j ? tp->bytes[j-1] : sizeof(int));
          oscopy(dest,source,len);
          dest +=len;
          source += (irow +nr-1) * (j ? tp->bytes[j-1] : sizeof(int));
          len = (tp->rows - irow - nr + 1) * 
                (j ? tp->bytes[j-1] : sizeof(int));
          oscopy(dest,source,len);	
  }
  if ((status = MID_RETNAM(tp->imno, table_name, sizeof(table_name))))
        return(TBL_errf(status, "(in row expansion)")); 
  if ((status = TCTCLO(tid)))     return(status);
  if ((status = TCTCLO(new_tid))) return(status);
  if ((status = SCFDEL(table_name)))
        return(TBL_errf(status, "(in row expansion)"));
  if ((status = SCFRNM(TBL_tmpname, table_name)))
        return(TBL_errf(status, "(in row expansion)"));

  new_tid = tid;        /* Tell that we want to keep the Old Number */
  status = TCTOPN(table_name, F_IO_MODE, &new_tid);
  if ((status == ERR_NORMAL) && (new_tid != tid))
        SCTPUT("++++ Table Number Changed!");

  return (status);
 }

