/*===========================================================================
  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
===========================================================================*/

/*+++++++++++++++++++++  CATAL.C  +++++++++++++++++++++++++++++++++++++++++++
.LANGUAGE  C
.IDENTIFICATION Module CATAL.C
.COMMENTS
Support all MIDAS catalog commands
.AUTHOR    K. Banse			ESO - Garching
.KEYWORDS:
  MIDAS catalogue
.PURPOSE:
  manage the MIDAS catalogues
.ALGORITHM:
  use the SCC catalog interfaces to handle the different functions
.INPUT/OUTPUT:
  the following keys are used:

  DEFAULT/C/1/1			DEFAULT(1:1) = Y, we have a directory file 
  					     = T, we have table input + must
					          build `directory.dat'
  ACTION/C/1/3			action to perform, CREATE, LIST, SEARCH or SHOW
  IN_A/C/1/60			cat. name
  P4/C/1/1			display flag for SEARCH
  INPUTC/C/1/60		        frame list
	
  the following keys are written
  OUT_A/C/1/20			matching frame for SEARCH
  OUTPUTI/I/11/1		no. of entries fo SHOW

.VERSION   [1.00]  880714: from FORTRAN version 3.50 as of 870910

 100616		last modif
-------------------------------------------------------------------------*/

#include <fileexts.h>
#include <fsydef.h>

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

/*

*/

int main()

{
int   fid, ity, oty, iflag, iav, nulo;
int   out[3], fno;
int   n, jj, ll, clen, begin, kcount, stat;
int   cimno, uni;
int   *ipntr;
int   idum;
unsigned int  nbytes;
register int nr;

char	action[4];
char	ident[80], def[2];
char	catfile[84], output[84];
char	cbuf[80];
char    *adr0, *adr1, *adr2, *cpntr, *fpntr;

static char  badguy[] = "+-*^()$";
static char  blank[] = "     ";				/* 5 blanks (+ \0) */

void sortit();



(void) SCSPRO("catal");
	
(void) SCKRDC("ACTION",1,1,3,&iav,action,&uni,&nulo);     /* what to do */
action[3] = '\0';
CGN_UPSTR(action);
stat = SCKRDC("DEFAULT",1,1,2,&iav,def,&uni,&nulo);	     /* dirfile flag */
	
/* read name of catalog (length = CATALINFO(11))  */

(void) SCKGETC("IN_A",1,80,&iav,catfile);

(void) SCKRDI("INPUTI",1,3,&iav,out,&uni,&nulo);    /* get type_no + range */
ity = out[0];

  
/*********************************************************
            CREATE/xCATAL catalog
*********************************************************/

	
if (strcmp(action,"CRE") == 0)
   {
   register int  mr;

   if (def[0] == 'Y') 
      iflag = 1;
   else if (def[0] == 'T') 
      iflag = 2;
   else
      iflag = 0;

   for (nr=0; nr<(int)strlen(catfile); nr++)	/* check for bad chars. */
      {
      for (mr=0; mr<7; mr++)
         {
         if (badguy[mr] == catfile[nr])
            {
            (void) sprintf(output,"Invalid char: `%c' in catalog name %s",
                    badguy[mr],catfile);
            SCETER(11,output);
            }
         }
      }

   if (iflag == 2)		/* we read a table + build `directory.dat' */
      {
      char  *cpntr;

      stat = SCKGETC("IN_B",1,60,&iav,ident);		/* table,column spec */
      n = CGN_INDEXS(ident,",:");
      if (n < 1)
         n = CGN_INDEXS(ident,",#");
      ident [n] = '\0';
      n ++;					/* n must be > 0 ... */
      
      cimno = -1;
      stat = TCTOPN(ident,F_I_MODE,&cimno);
      stat = TCCSER(cimno,&ident[n],&fno);
      if (fno < 0)
         {
         (void) sprintf(output,"Could not find column  %s",&ident[n]);
         SCETER(10,output);
         }

      stat = TCIGET(cimno,&iav,&clen,&iav,&iav,&iav);
      stat = TCBGET(cimno,fno,&jj,&iav,&iav);
      if (jj != D_C_FORMAT)
         SCETER(11,"column not of type CHARACTER...");

      fid = osaopen("dirfile.ascii",WRITE);
      if (fid < 0) 
         SCETER(3,"Could not create `dirfile.ascii' ...");

      for (nr=1; nr<=clen; nr++)
         {
         stat = TCSGET(cimno,nr,&jj);	/* check selection flag */
         if (jj)
            {
            stat = TCEMAP(cimno,nr,fno,&cpntr,&jj);
            if (!jj) 
               osawrite(fid,cpntr,(int)strlen(cpntr));	/* write, if != NULL */
            }
         }

      osaclose(fid);
      TCTCLO(cimno);
      iflag = 1;
      }


   (void) SCKGETC("P3",1,60,&iav,ident);
   stat = SCCCRA(catfile,ity,iflag,ident);

   stat = SCKRDI("OUTPUTI",10,1,&iav,out,&uni,&nulo);
   
   if (out[0] > 1)
      (void) strcpy(ident,"entries");
   else
      (void) strcpy(ident,"entry");

   if (ity == F_TBL_TYPE)
      (void) sprintf(output,"Table catalog %s with %d %s created...",
             catfile,out[0],ident);
   else if (ity == F_FIT_TYPE)
      (void) sprintf(output,"Fit file catalog %s with %d %s created...",
             catfile,out[0],ident);
   else if (ity == F_IMA_TYPE)
      (void) sprintf(output,"Image catalog %s with %d %s created...",
             catfile,out[0],ident);
   else
      (void) sprintf(output,"ASCII file catalog %s with %d %s created...",
             catfile,out[0],ident);
   SCTPUT(output);
   }

else
   {
   stat = MID_COPN(catfile,&jj,&cimno);
   if (stat != ERR_NORMAL)
      {
      (void) sprintf(output,"Could not open catalog file %s",catfile);
      SCETER(1,output);
      }

   oty = jj;
   if (oty != ity) 
      SCETER(4,"Command qualifier and catalog type do not match...");


/*********************************************************
            SHOW/xCATAL catal disp_option
*********************************************************/
	
   if (strcmp(action,"SHO") == 0)
      {
      stat = SCCSHO(catfile,out,&out[1]);
      stat = SCKWRI("OUTPUTI",out,1,2,&uni);	/* save in key OUTPUTI(1,2) */

      fid = osaopen(catfile,READ);
      (void) osaread(fid,cbuf,80);
      jj = CGN_INDEXC(cbuf,',') + 2;
      if (jj < 3)
         (void) strcpy(cbuf,"IDENT");
      else
         CGN_strcpy(cbuf,cbuf+jj); 
      (void) osaclose(fid);

      stat = SCKGETC("P2",1,2,&iav,output);		/* get display flag */
      if ( (output[0] == 'D') || (output[0] == 'd') )
         {
         if (ity == F_TBL_TYPE)
            (void) sprintf(output,"Table Catalog: %s ",catfile);
         else if (ity == F_FIT_TYPE)
            (void) sprintf(output,"FitFile Catalog: %s ",catfile);
         else if (ity == F_IMA_TYPE)
            (void) sprintf(output,"Image Catalog: %s ",catfile);
         else
            (void) sprintf(output,"ASCII File Catalog: %s ",catfile);
   
         SCTPUT(output);
   
         (void) sprintf(output,"descriptor used for `Ident' is: %s",cbuf);
         SCTPUT(output);
   
         (void) 
         sprintf(output,"No. of entries = %d, last entry = %d",out[0],out[1]);
         SCTPUT(output);
         }
      }

  
/*********************************************************
            READ,PRINT/xCATAL catal range 
*********************************************************/
	
   else if ((strcmp(action,"REA") == 0) ||
            (strcmp(action,"PRI") == 0) )
      {
      if ((out[1] < 1) || (out[2] < 1) || (out[2] < out[1]))
         SCETER(2,"invalid catalog entry range ...");

      stat = SCKGETC("P3",1,5,&iav,cbuf);
      CGN_UPSTR(cbuf);
      if (strncmp(cbuf,"BRIEF",5) == 0)
         stat = outcat(catfile,1,&out[1]);	/* just filenames */
      else
         stat = SCCLIS(catfile,&out[1]);	/* full display */
      }
	
  
/*********************************************************
            SORT/xCATAL catal ident  
*********************************************************/

   else if (strcmp(action,"SOR") == 0) 
      {
      if (ity == F_ASC_TYPE)
         SCETER(13,"Sorting not supported for ASCII catalogs...");

      stat = SCCSHO(catfile,out,&out[1]);	/* get no. of entries */
      if (out[0] < 2)
         {
         if (out[0] < 1)
            (void) printf("No entries in catalog %s ...\n",catfile);
         else
            (void) printf(
             "Only 1 entry in catalog %s - nothing to sort ...\n",catfile);
         goto end_of_it;
         }

      ll = out[0] + 1;	      /* for the sorting we need 1 elem more */
      clen = 60;			/* filenames max. 60 chars */
      nbytes = ll*clen;
      adr0 = malloc((size_t)nbytes);		/* space for file names */
      fpntr = adr0+clen;		/* point to actual 2. elem */

      jj = CATIDENT_LEN;
      nbytes = (ll*jj)+4;		/* + 4   because of trailing `\0' in
					         Ident field of catalog-rec. */
      adr1 = malloc((size_t)nbytes);		/* space for idents */
      cpntr = adr1+jj;

      nbytes = ll*sizeof(int);
      adr2 = malloc((size_t)nbytes);		/* space for entry numbers */
      ipntr = ((int *) adr2) + 1;

      idum = 0; 			/* to start the catalog search */
      for (nr=0; nr<out[0]; nr++)
         {
         stat = SCCGET(catfile,1,fpntr,cpntr,&idum);
         fpntr += clen;
         cpntr += jj;
         *ipntr ++ = (nr+1);
         } 

      cpntr = adr1;
      ipntr = (int *) adr2;		/* pass address of elem 0 */

      sortit(cpntr,jj,ipntr,out[0]);


      /* now we create a temporary catalog `midtemp.cat'  */

      (void) MID_COPN(catfile,&ity,&jj);	/* get internal catal-id */
      stat = SCCCRA("midtemp.cat",ity,0,CATAL[jj].DESCR);      /* no dirfile */
      fpntr = adr0;				/* ipntr begins with 1 not 0 */
      ipntr = (int *) adr2 + 1;
      for (nr=0; nr<out[0]; nr++)
         {
         begin = *ipntr ++;
         begin *= clen;				/* move through filenames */
         (void) strcpy(cbuf,fpntr+begin);
         stat = SCCADD("midtemp.cat",cbuf,blank);
         }


      /* close + delete original catalog, close temp. catatlog */

      (void) MID_CCLO(jj);			/* close orig. catalog */
      (void) MID_CKLO("midtemp.cat");		/* and close temp. catalog */

#if vms
      stat = osfrename("midtemp.cat",catfile);
#else
      stat = osfdelete(catfile);
      if (stat == 0)
         stat = osfrename("midtemp.cat",catfile);
#endif
      if (stat != 0)
         {
         (void) sprintf(output,"Could not rename midtemp.cat to %s ",catfile);
         SCTPUT(output);
         SCTPUT("Sorted catalog stored in midtemp.cat ... ");
         }
      }
  
/*********************************************************
            SEARCH/xCATAL catal string
*********************************************************/

   else if (strcmp(action,"SEA") == 0) 
      {
      if (ity == F_ASC_TYPE)
         SCETER(13,"Searching not supported for ASCII catalogs...");

      stat = SCKGETC("INPUTC",1,60,&iav,output);
      if (output[0] == ' ') SCETER(11,"invalid (empty) search string ...");

      stat = SCKRDC("P3",1,1,2,&iav,action,&uni,&nulo);    /* display flag */
      stat = SCCSHO(catfile,out,&out[1]);
      if (out[0] < 1)
         {
         (void) printf(" No entries in catalog %s ...\r\n",catfile);
         goto end_of_it;
         }

      idum = 0; 			/* to start the catalog search */

      if ((action[1] == 'E') || (action[1] == 'e'))
         {					/* we go from the end down */
         for (nr=0; nr<out[1]; nr++)
            {
            iflag = out[1] - nr;			/* we go top down */
            stat = SCCGET(catfile,1,cbuf,ident,&iflag);
            if (iflag != -1)
               {
               kcount = CGN_INDEXS(ident,output);
               if (kcount >= 0)
                  {
                  if ((*action == 'D') || (*action == 'd'))
                     {
                     (void) sprintf(output,"first match for frame: %s",cbuf);
                     SCTPUT(output);
                     }
                  (void) SCKWRC("OUT_A",1,cbuf,1,60,&uni);
                  goto end_of_it;
                  }
               else
                  {
                  idum ++;		/* count no. of valid returns */
                  if (idum>= out[0]) break;
                  }
               }
            }
         }

      else
         {				 /* we go from the beginning up */
         for (nr=0; nr<out[0]; nr++)
            {
            stat = SCCGET(catfile,1,cbuf,ident,&idum);
            kcount = CGN_INDEXS(ident,output);
            if (kcount >= 0)
               {
               if ((*action == 'D') || (*action == 'd'))
                  {
                  (void) sprintf(output,"first match for frame: %s",cbuf);
                  SCTPUT(output);
                  }
               (void) SCKWRC("OUT_A",1,cbuf,1,60,&uni);	
               goto end_of_it;
               }
            }
         }

      memset((void *)cbuf,32,(size_t)60);		/* ' ' = 32 */
      (void) SCKWRC("OUT_A",1,cbuf,1,60,&uni);		/* save in key OUT_A */
      } 
   }

	
/*  that's it folks...  */

end_of_it:
  return SCSEPI();
}

/*

*/

void sortit(field,flen,ika,ndim)

/*
 
  ndim  = dimension of array ika for sorting
  but we pass the arrays with 1 element in front, so that the algorithm
  sorts from [1] -> [ndim]
  this is a version of the Heapsort algorithm 
  adapted for character based catalog entries. 

*/
  
char  *field;
int   flen, *ika, ndim;

{
int  kka, m, ir, j, i, ioff, koff;
  

m = ndim/2 + 1;
ir = ndim;

while (1)
   {
   if (m > 1)			/* still hiring */
      kka = ika[--m];
   else			/* in retirement + promotion phase */
      {
      kka = ika[ir];	/* clear a space at end of array ika */
      ika[ir] = ika[1];	/* retire the top of the heap into it */
      if (--ir == 1)	/* done with last promotion */
         {
         ika[1] = kka;	/* the least competent guy of all... */
         return;		/* that's it folks  */
         }
      }
     
/* in hiring as well as in promotion phase */
/* here set up to sift down kka to its right level */

   i = m;	
   j = m << 1;				/* in FORTRAN: j = m + m */
  
   while (j <= ir)	
      {
      if (j < ir)
         {
         ioff = ika[j] * flen;
         koff = ika[j+1] * flen;	 /* compare to the better underling */
         if (strcmp((field+ioff),(field+koff)) < 0) j++;
         }
   
      ioff = kka *flen;
      koff = ika[j] *flen;
      if (strcmp((field+ioff),(field+koff)) < 0) 		/* demote kka */
         {
         ika[i] = ika[j];
         i = j;
         j = j << 1;			/* in FORTRAN: j = j + j */
         }
      else
         j = ir + 1;
 
      }

   ika[i] = kka;		/* put kka into its slot */
   }

}
