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

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.IDENTIFICATION: program ccdmosfit
.KEYWORDS:       bulk data frames, mosaicing, alignment
.PURPOSE:        Match the individual subraster elements in the input image.
                 In order to run this program the user should have created 
                 the output image and the database file with the CREATE/MOSAIC
                 command.
                 The actual algorithm (mo_offset) was developend by Mike Regan
                 of the Univ. of Maryland
.VERSION

 110930		last modif
-----------------------------------------------------------------------*/
/*
 * Define _POSIX_SOURCE to indicate
 * that this is a POSIX program
 */
#define _POSIX_SOURCE 1

/*
 * definition of the used functions
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ftoc.h>
#include <midas_def.h>
#include <computer.h>
#include <ccd_def.h>

/*
 * define some macros and constants
 */
#define NCOL       11
#define MAXIMS     80
#define MAXIMSONE  MAXIMS+1
#define MAXLEV     50                  /* maximum number of contour levels */
#define MAXPIX     512    /* max frame dimension (X,Y) accessed at once */
#define MAXSIZ     (MAXPIX * MAXPIX)

extern void MO_TBLRPAR(), MO_SHIFTS(), MO_FSHIFTS(), MO_SUBALIGN();
extern void sorti(), MO_ZERO(), MO_FITOFF();
extern int  MO_M2MATCH(), MO_LINKS(), MO_CLINKS(), MO_FLINKS(), MO_OFFSET();

/*
 ++++++++++++++++++++++++++++++++++++++++++++++++++
 * here starts the code of the function
 ---------------------------------------------------
*/

int main()

{
int          uni;
int          imnoi, imnom, imnoc;
int          tdb;
int          sizec;
int          naxis;
int          npix[3], npixc[3];

int          allcoldb, allrowdb;
int          colo[3];
int          iaux, i;
int          imsize[2], nimcol, nimrow;
int          iav;
int          minpix;
int          nimages;
int          npair;
int          nshift;
int          nrsub[2];
int          ncoldb, nrowdb, nsortdb;
int          nulo;
int          nranges, ranges[100];
int          stat;
int          tr_area[4];
int          xyref[2];
int          verbose;
int          match;
int          interp;
int          inull;

float        data[3];
float        usrnul;
float        rnull;

double       step[3], start[3];
double       aostep;
double       dnull;
 
char         *pntri, *pntrc;
char         *cbuff;
char         cunit[61];
char         framei[82], framem[82], framec[62];
char         tabdb[61];
char         ident[72];
char         line[81];
char         med_area[40], im_area[41], matchlist[41];
char         output[64];

static char  x_colo[]     = "X_offpix";
static char  y_colo[]     = "Y_offpix";
static char  i_colo[]     = "Offset";

/* 
 set up MIDAS environment + enable automatic error abort 
 */

SCSPRO("mosfit");

/*
 Get the table null value
 */
TCMNUL(&inull, &rnull, &dnull);
MO_NULL = 0.0;

/* 
 Get input frame list, tables and output frame
 --------------------------------------------
 */
stat  = SCKGETC("CCDIN",1,80,&iav,framei);             /* input mosaic frame */
stat  = SCIGET(framei,D_R4_FORMAT, F_IO_MODE, F_IMA_TYPE, MO_DIM2, &naxis, 
                      npix, start, step, ident, cunit, &pntri, &imnoi);

stat  = SCKGETC("CCDMSK",1,80,&iav,framem);                    /* input mask */
if (strncmp(framem,"none",4) == 0)	                         /* set flag */
   imnom = -1;
else
   stat  = SCFOPN(framem,D_R4_FORMAT,0,F_IMA_TYPE,&imnom);

/* 
 Get database, open it and get info
 Store the table descriptor into the MO variables
 */
stat = SCKGETC("TBLDB",1,60,&iav,tabdb);                   /* database table */
(void) TCTOPN(tabdb, F_IO_MODE, &tdb);
(void) TCIGET(tdb, &ncoldb, &nrowdb, &nsortdb, &allcoldb, &allrowdb);
TCCSER(tdb, x_colo, &colo[0]);
TCCSER(tdb, y_colo, &colo[1]);
TCCSER(tdb, i_colo, &colo[2]);
MO_TBLRPAR(tdb, im_area, med_area);                    /* read the desciptor */
nimages = MO_NXSUB * MO_NYSUB;

/*
 Get the output file 
 */
stat = SCKGETC("ccdout",1,60,&iav,framec);              /* final output file */

/* 
 get the image section 
 */
stat = SCKRDI("TR_SEC",1,4,&iav,tr_area,&uni,&nulo);      /* section include */

/*
 Column and row number of reference raster
 */
stat   = SCKRDI("NRSUB",1,2,&iav,nrsub,&uni,&nulo);   
MO_NXRSUB = nrsub[0];
MO_NYRSUB = nrsub[1];
if (MO_NXRSUB == 0  || MO_NXRSUB < 1 || MO_NXRSUB > MO_NXSUB)
   MO_NXRSUB = (MO_NXSUB + 1) / 2;
if (MO_NYRSUB == 0  || MO_NYRSUB < 1 || MO_NYRSUB > MO_NYSUB)
   MO_NYRSUB = (MO_NYSUB + 1) / 2;

/*
 Get the x and y offset of the reference subraster
 */
stat   = SCKRDI("XYREF",1,2,&iav,xyref,&uni,&nulo);   
MO_XREF = xyref[0];
MO_YREF = xyref[1];

/* 
 get the matching subrasters
 */
stat = SCKGETC("EXCLUDE",1,40,&iav,matchlist);      /* subraster match list */
CGN_UPCOPY(matchlist,matchlist,40);                         /* upper case -> */
if (strncmp(matchlist,"NONE",4) == 0)	   
   nranges = 0;
else
   {
   cbuff  = (char *) ranges;
   if ( USRINP( 'i', matchlist, 100, cbuff, &nranges ) != 0 )
      SCETER(20,"*** FATAL: Error in subraster matching list");
   if (nranges > 1) sorti(nranges,ranges);
   }

/*
 Get the minimum number of pixels
 */
stat   = SCKRDI("MINPIX", 1, 1, &iav, &minpix, &uni, &nulo);   

/* 
 Get the size of the output
 */
stat   = SCKRDI("OSIZE",1,2,&iav,imsize,&uni,&nulo);    /* size of output */
nimcol = imsize[0];
nimrow = imsize[1];
if ( nimcol != 0 && nimcol > 0 && nimcol >= npix[0])
   npixc[0] = nimcol;
else 
   npixc[0] = npix[0];

if ( nimrow != 0 && nimrow > 0 && nimrow >= npix[1])
   npixc[1] = nimrow;
else 
   npixc[1] = npix[1];

/* 
 Get Null value for the output frame
 */
stat = SCKGETC("BLANK",1,20,&iav,output);
if ((output[0] == '+') && (output[1] == '\0'))
   iaux = 1;                                    /*  use `last' value as Null */
else
  {
  iav = CGN_CNVT(output,2,1,npixc,&usrnul,&aostep);
  if (iav < 1)
     SCETER(19,"*** FATAL: Invalid Null value ... ");
  MO_BLANK = usrnul;
  }

/*
 get the interpolation
 */
stat = SCKGETC("INTERPOL",1,40,&iav,output);           /* section to include */
CGN_UPSTR(output);		                    /* convert to upper case */
if (strncmp(output,"NEA",3) == 0)	                         /* set flag */
   interp = MO_BINEAREST;
else if (strncmp(output,"LIN",3) == 0)
   interp = MO_BILINEAR;
else if (strncmp(output,"POLY3",5) == 0) 
   interp = MO_BIPOLY3;
else if (strncmp(output,"POLY5",5) == 0) 
   interp = MO_BIPOLY5;
else if (strncmp(output,"SPLINE3",7) == 0)
   interp = MO_BISPLINE3;
else 
   interp = 999;

/*
 Get the output mode 
 */
stat = SCKGETC("VERBOSE",1,3,&iav,output);         /* Get the verbose option */
CGN_UPSTR(output);		                    /* convert to upper case */
if (strcmp(output,"YES") == 0)		                         /* set flag */
   {
   verbose = 1;
   strcpy(MO_DEFAULT,"NYFXN");
   }
else
   {
   verbose = 0;
   strcpy(MO_DEFAULT,"NYFNN");
   }

/* 
 Allocate memory for output frame and zero it
 */
sizec   = npixc[0]*npixc[1];
stat    = SCFCRE(framec,D_R4_FORMAT,F_O_MODE,F_IMA_TYPE,sizec,&imnoc);
stat    = SCFMAP(imnoc, F_O_MODE, 1, sizec, &iav, &pntrc);
if (stat != 0)                                   /* get pointer output frame */
   SCETER(66,"*** FATAL: Could not allocate virtual memory ...");  
stat    = SCDWRI(imnoc,"NAXIS",&naxis,1,1,&uni);
stat    = SCDWRI(imnoc,"NPIX",npix,1,naxis,&uni);
stat    = SCDWRD(imnoc,"START",start,1,naxis,&uni);
stat    = SCDWRD(imnoc,"STEP",step,1,naxis,&uni);
stat    = SCDCOP(imnoi, imnoc, 4, "CUNIT");
sprintf(ident,"Match of subrasters in input frame %s", framei);
stat    = SCDWRC(imnoc,"IDENT",1,ident,1,72,&uni);

MO_ZERO(pntrc, npixc, MO_BLANK);
(void) SCFPUT(imnoc, 1, npixc[0]*npixc[1], pntrc);

/*
 Here we do the real work, that is reading and writing the data
 First, allocate size of one full strip with noutcols
 */
SCTPUT(" ");
sprintf(line,"Input frame:    %s", framei);
SCTPUT(line);
sprintf(line,"Database table: %s", tabdb);
SCTPUT(line);
sprintf(line,"Output frame:   %s",framec);
SCTPUT(line);
sprintf(line,"Number of subrasters (x,y): %d,%d", MO_NXSUB, MO_NYSUB);
SCTPUT(line);

/* 
  Now we have all parameter input available; time to go to work now
 */
if (colo[0] < 0 || colo[1] < 0 )
   SCETER(4,"*** FATAL: X and/or Y offset column(s) not found");

MO_FLINKS(tdb, colo, MO_DELTAX, MO_DELTAY, MO_DELTAI, nimages, &nshift);
if (nshift < nimages) 
   SCETER(4,"*** FATAL: Fewer shifts than subrasters");
else
   MO_FSHIFTS(imnoi, imnoc, MO_DELTAX, MO_DELTAY,
                            MO_IC1, MO_IC2, MO_IL1, MO_IL2,
                            MO_OC1, MO_OC2, MO_OL1, MO_OL2);
/*
 Get the shift in all overlapping regions
 */
match = 1;
MO_OFFSET(imnoi, imnom, tdb, MO_OC1, MO_OL1, &npair, MO_REOFF, MO_COUNT, 
          MO_IREF, MO_JREF, minpix, verbose); 

/*
 Fit the shifts in the overlapping regions
 */
MO_FITOFF(nrowdb, npair, MO_REOFF, MO_COUNT, MO_IREF, MO_JREF, 
          nranges, ranges, MO_DELTAI);

/*
 Do the corrections and align
 */
MO_SUBALIGN(imnoi, pntri, imnoc, pntrc, tr_area,
            MO_IC1, MO_IC2, MO_IL1, MO_IL2,
            MO_OC1, MO_OC2, MO_OL1, MO_OL2,
            MO_DELTAX, MO_DELTAY, MO_DELTAI,
            match, interp, verbose);

/*
 Store the data in the data base file and close files. Finally exit
 */
(void) SCFPUT(imnoc, 1, npixc[0]*npixc[1], pntrc);

for (i = 0; i < nrowdb; i++) 
   {
   data[0] = MO_DELTAX[i];
   data[1] = MO_DELTAY[i];
   data[2] = MO_DELTAI[i];
   stat = TCRWRR(tdb, i+1, 3, colo, data);
   }

(void) TCTCLO(tdb);
return SCSEPI();
}




