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

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.IDENT       WRIMA
.LANGUAGE    C
.AUTHOR      K. Banse		IPG-ESO Garching
.KEYWORDS    ImageDisplay, memory board
.PURPOSE     write a frame into memory board(s) of the ImageDisplay
.ALGORITHM   a frame is scaled in x,y and z. the scaled image is
             then loaded into an 8 byte memory board of the ImageDisplay

.INPUT/OUTPUT
  the following keys are used:
  IN_A/C/1/80		specs of data frame to be displayed
  DAZHOLD/I/3/1		split mode, = 0 for single image
					    = 1 for 3/4 images
  DAZHOLD/I/8/1		refscale flag
  SIZIN/I/1/2			mapping sizes for input data + output bytes
  DEFAULT/C/1/6		default flags
  				(1) = 'Y', take scaling of image from
					   descr. DISPLAY_DATA(1,2)
				    = 'N', take scaling from key INPUTC
  				(2) = 'Y', take center of image from
	 			           descr. DISPLAY_DATA(3,4)
				    = 'N', take center from key INPUTC
  				(3) = 'U', UP: for loading bottom_up
				    = 'D', DOWN: for loading top_down
  				(4) = 'Y', take cuts of image from
					   descr. CUTS(1,2)
				    = 'N', take cuts from key INPUTR(1,2)
				    = 'P', get strategy for cut values from
					   keyword CSTUFF, if no cuts there yet
                                    = 'F'  get cuts values always using
                                           strategy given in keyword CSTUFF
  				(5) = 'O', if OVERWRITE option enabled,
                                          then SOURCE = 2
  				(6) = 'Y', use center pixels for positioning
					   image in channel memory
  				      'N', use fixpoint pixels for positioning
  CSTUFF/C/1/30		str with scaling factors, if DEFAULT(1:1) = 'N'
  CSTUFF/C/31/60		str with center coords, if DEFAULT(2:2) = 'N'
  CSTUFF/C/91/30		str with D/F,method , if DEFAULT(4:4) = D/F
  IMACUTS/R/1/2		(1,2) cut values, if DEFAULT(4:4) = 'N'
  FIXPT/R/1/4			if DEFAUL(6:6) = 'N', holds fixpoint pixels 
				for screen and frame pixels
				if used, center pixels are ignored
	 			store in descr. DISPLAY_DATA(7,8)
  MID$DISP/C/1/20		is either I_IMAGE_DISPLAY
				or F_name-of-display-file
				or N_NULL
  MID$SPEC/C/7/4		if = CUTS, we loop inside program
				with different cuts

.VERSIONS    1.00       940413  from WRIMA.FOR    RvH

 111130		last modif
------------------------------------------------------------*/

/* Define _POSIX_SOURCE to indicate that this is a POSIX program */

#define  _POSIX_SOURCE 1
 
#include <midas_def.h>
#include <idinumd.h>

#include <stdio.h>
 
/*

*/

int main()

{
register int ii;

int    actvals, dattyp, ec, ed, el, m, imno, knul, naxis, num, unit, 
       dsplfl, idum[5], icent[4], npix[3], 
       savcha, actcha, chan_flag;

float  rdum, rdisp[8];

double ddum, start[3], step[3];

char   opened[2], defaul[8], cbuff[64], str_cuts[32], 
       str_scale[32], str_centr[64], name_str[84], name[84], snglc;


/* initialized variables */

char *err_mean    = "For averaging, both scale values have to be < 0",
     *err_scaling = "Invalid syntax in scaling factors...",
     *err_center  = "Invalid syntax in center coordinates...",
     *err_cuts    = "Invalid cut values...";

static int   dis_no=0, log_no=0, con_alw=1;        /* variable for SCECNT */
static int   scale[3] = {0,0,0};
static int   disp[9]  = { -1, -1, -1, -1, -1, -1, -1, -1, -1 };
static float cuts[4];



(void) SCSPRO("WRIMA");
savcha = 0, m = 1;
(void) SCPSET(F_FITS_PARM,&m);		/* don't read in ESO.xyz keywords */

/* test if we load into display or file */

(void) SCKGETC("MID$DISP",1,1,&actvals,opened);
(void) SCKGETC("P2",1,20,&actvals,cbuff);	/* channel to load into */
chan_flag = 0;

if ( *opened == 'i' || *opened == 'I' )
   {
   dsplfl = 1;
   DCOPEN(1);

   savcha = QIMCH;			/* if alpha channel convert to no. */
   if (cbuff[0] == '+')
      actcha = QIMCH;
   else if ( (cbuff[0] == 'O') || (cbuff[0] == 'o') )
      actcha = QOVCH;
   else 
      {
      m = CGN_CNVT(cbuff,1,1,&actcha,&rdum,&ddum);
      if (m != 1)					/* cbuff = charstr */
         {
         actcha = -1;
         if ((cbuff[0] == 'r') || (cbuff[0] == 'R'))
            actcha = 0;
         else if ((cbuff[0] == 'g') || (cbuff[0] == 'G'))
            actcha = 1;
         else if ((cbuff[0] == 'b') || (cbuff[0] == 'B'))
            actcha = 2;
         }
      if ((actcha < 0) || (actcha > QLSTCH))
         {
         (void) sprintf(name,"invalid image channel (= %s) ...",cbuff);
         SCETER(5,name);
         }
      m = CGN_INDEXS(cbuff,",.");	/* look for 0,... */
      if (m > 0) chan_flag = 1;
      }
   QIMCH = actcha;
   }
else if ( *opened == 'n' || *opened == 'N' )
   return SCSEPI();			/* Null device */
else
   dsplfl = 0;				/* we load into a file */


/* get name of frame to be displayed */

(void) SCKGETC("IN_A",1,80,&actvals,name_str);
num = CGN_INDEXC(name_str,']');         /* look for name[...] first */
if (num > 0)
   {
   if (name_str[num+1] == ',')
      m = num + 1;
   else
      m = 0;
   }
else
   m = CGN_INDEXC(name_str,',');         /* look for name,f_plane,l_plane */

if (m > 0) 
   {
   char  tmpbuf[84];

   (void) strncpy(tmpbuf,name_str,m);	/* so we don't modify name_str */
   tmpbuf[m] = '\0';
   (void) CGN_APPNDTYP(tmpbuf,0);
   (void) CGN_FRAME(tmpbuf,1,name,0);
   }
else
   {
   (void) CGN_APPNDTYP(name_str,0);
   (void) CGN_FRAME(name_str,1,name,0);
   }

/* open frame (now in 'name') and get info (5 integers ) */

(void) SCFINF(name,4,idum);   
if ((dattyp = idum[1]) == D_R8_FORMAT) dattyp = D_R4_FORMAT;

(void) SCFOPN(name,dattyp,0,F_IMA_TYPE,&imno);

if (idum[4] != F_IMA_TYPE) SCETER(3,"frame is not an image...");

(void) SCDRDI(imno,"NAXIS",1,1,&actvals,&naxis,&unit,&knul);
if (naxis > 3) naxis = 3;
(void) SCDRDI(imno,"NPIX",1,naxis,&actvals,npix,&unit,&knul);
(void) SCDRDD(imno,"START",1,naxis,&actvals,start,&unit,&knul);
(void) SCDRDD(imno,"STEP",1,naxis,&actvals,step,&unit,&knul);


/* get default settings */

(void) SCKGETC("DEFAULT",1,6,&actvals,defaul);
(void) CGN_UPSTR(defaul);


/* get cut values + display values (not necessarily there...) */

SCECNT("GET",&ec,&el,&ed);
SCECNT("PUT",&con_alw,&log_no,&dis_no);

cuts[0] = cuts[1] = cuts[2] = cuts[3] = 0.0;		/* init first */
*str_cuts = '\0';
(void) SCDRDR(imno,"LHCUTS",1,4,&actvals,cuts,&unit,&knul);

if (defaul[3] == 'D') 
   {
   (void) SCKGETC("CSTUFF",93,28,&actvals,str_cuts);
   CGN_UPSTR(str_cuts);			/* only in case it's needed */
   }
else if (defaul[3] == 'F')
   {
   (void) SCKGETC("CSTUFF",93,28,&actvals,str_cuts);
   CGN_UPSTR(str_cuts);
   cuts[0] = cuts[1] = 0.0;		/* force recalculation of Cuts */
   cuts[2] = cuts[3] = 0.0;
   }
else if (defaul[3] == 'N')                            /* use explicit cuts */
   {
   (void) SCKRDR("IMACUTS",1,2,&actvals,cuts,&unit,&knul);
   if (cuts[0] >= cuts[1]) (void) strcpy(str_cuts,"MINMAX");
   }


/* Look for integer descr. DISPLAY_DATA  */

if (SCDRDI(imno,"DISPLAY_DATA",1,9,&actvals,disp,&unit,&knul) != 0)
   {
   disp[0] = 1;                /* if nothing there, init DISPLAY_DATA */
   disp[1] = 1;
   disp[2] = npix[0]/2 + 1;
   disp[3] = npix[1]/2 + 1;
   disp[4] = 0;
   }

else if ((actvals == 9)  && (disp[5] > -1))     
   {
   if ((defaul[1] == 'Y') && (defaul[5] == 'Y')) 
      defaul[5] = 'F';           /* no fixpoint entered, use old fixpoint */
   }


/* reset error handling */

SCECNT("PUT",&ec,&el,&ed) ;


/* determine scaling factors */

if (*defaul == 'N')                        /* take scaling from key CSTUFF */
   {
   (void) SCKGETC("CSTUFF",1,30,&actvals,str_scale);
   m = CGN_INDEXC(str_scale,',');  

   if ((*str_scale == 'F') || (*str_scale == 'f'))	/* scale=Full */
      {
      if ((npix[0] <= QMSZX) && (npix[1] <= QMSZY))
         {
         scale[0] = QMSZX/(npix[0]-1) + 1;
         scale[1] = QMSZY/(npix[1]-1) + 1;
         if (scale[0] > scale[1]) scale[0] = scale[1];
         if (scale[1] > scale[0]) scale[1] = scale[0];
         goto sign_switch;
         }

      scale[0] = - ((npix[0]-1)/QMSZX + 1);
      scale[1] = - ((npix[1]-1)/QMSZY + 1);
      if (scale[0] < scale[1]) scale[0] = scale[1];
      if (scale[1] < scale[0]) scale[1] = scale[0];

      if (m > 0)
         {
         snglc = *(str_scale+m+1);
         if ((snglc == 'a') || (snglc == 'A'))			/* Average */
            scale[2] = 1;
         else if ((snglc == 'm') || (snglc == 'M'))		/* Max, Min */
            {
            snglc = *(str_scale+m+2);
            if ((snglc == 'i') || (snglc == 'I'))		/* Minimum */
               scale[2] = 2;
            else
               scale[2] = 3;					/* Maximum */
            }
         }
      }

   else
      {
      if ((num = CGN_CNVT(str_scale,1,1,scale,&rdum,&ddum)) <= 0)
         SCETER(2,err_scaling); 

      if (m <= 0)
         scale[1] = *scale;
      else
         {
         m ++;
         snglc = *(str_scale+m);
         if ((snglc == 'a') || (snglc == 'A'))                 /* Average */
            {
            scale[1] = *scale;
            scale[2] = 1;
            }
         else if ((snglc == 'm') || (snglc == 'M'))             /* Max, Min */
            {
            scale[1] = *scale;
            snglc = *(str_scale+m+1);
            if ((snglc == 'i') || (snglc == 'I'))               /* Minimum */
               scale[2] = 2;
            else
               scale[2] = 3;                                    /* Maximum */
            }
         else
            {
            (void) strcpy(cbuff,&str_scale[m]);
            num = CGN_CNVT(cbuff,1,1,scale+1,&rdum,&ddum);
            if (num < 1) SCETER(2,err_scaling);

            m = CGN_INDEXC(cbuff,',');
            if (m > 0) 
               {
               snglc = *(cbuff+m+1);
               if ((snglc == 'm') || (snglc == 'M'))             /* Max, Min */
                  {
                  snglc = *(cbuff+m+2);
                  if ((snglc == 'i') || (snglc == 'I'))
                      scale[2] = 2;				/* Minimum */
                  else
                     scale[2] = 3;				/* Maximum */
                  }
               else if ((snglc == 'a') || (snglc == 'A'))	/* Average */
                  scale[2] = 1;
               }
            }
         }
      }

  sign_switch:
   scale[0] = -scale[0];		/* remember the sign switch... */
   scale[1] = -scale[1];
   if ( scale[0] == -1 || scale[0] == 0 ) scale[0] = 1;
   if ( scale[1] == -1 || scale[1] == 0 ) scale[1] = 1;

   disp[0] = scale[0];
   disp[1] = scale[1];
   disp[4] = scale[2];                     /* indicate averaging */
   }

else
   {
   scale[0] = disp[0];
   scale[1] = disp[1];
   scale[2] = disp[4];                    /* average/omit option (scaling) */
   }
if ((scale[2] != 0) && ((scale[1] < 1) || (*scale < 1))) SCETER(4,err_mean);


/* Get central pixel no.s */

if (defaul[1] == 'N')      
   {
   (void) SCKGETC("CSTUFF",31,60,&actvals,str_centr);
   num = CGN_INDEXC(str_centr,',');

   if (num < 1)
      {
      if ((*str_centr == 'C') || (*str_centr == 'c'))     
         {
         if (scale[0] > 1)
            {
            ii = (npix[0]+scale[0]-1)/scale[0];  /* no. of sampled pixels */
            m = ii/2 + 1;			/* sample center pixel */
            disp[2] = (m-1)*scale[0] + 1;	/* so center is sampled */
            }
         else
            disp[2] = (npix[0]/2) + 1;
         if (scale[1] > 1)
            {
            ii = (npix[1]+scale[1]-1)/scale[1];  /* no. of sampled pixels */
            m = ii/2 + 1;			/* sample center pixel */
            disp[3] = (m-1)*scale[1] + 1;	/* so center is sampled */
            }
         else
            disp[3] = (npix[1]/2) + 1;
         }
      else
         SCETER(2,err_center);
      }

   else         /*  C,yyy  or  xxx,C  or  C,C  or  xxx,yyy  */
      {
      int  ca, cb;

      ca = 0; cb = 0;
      if ((*str_centr == 'C') || (*str_centr == 'c'))
         {
         ca = 1;
         if (scale[0] > 1)
            {
            ii = (npix[0]+scale[0]-1)/scale[0];  /* no. of sampled pixels */
            m = ii/2 + 1;			/* sample center pixel */
            disp[2] = (m-1)*scale[0] + 1;	/* so center is sampled */
            }
         else
            disp[2] = (npix[0]/2) + 1;
         }

      snglc = str_centr[++num];			/* skip the ',' */
 
      if ((snglc == 'C') || (snglc == 'c'))
         {
         cb = 1;
         if (scale[1] > 1)
            {
            ii = (npix[1]+scale[1]-1)/scale[1];  /* no. of sampled pixels */
            m = ii/2 + 1;			/* sample center pixel */
            disp[3] = (m-1)*scale[1] + 1;	/* so center is sampled */
            }
         else
            disp[3] = (npix[1]/2) + 1;
         }

      if ((ca != 1) || (cb != 1))
         {
         int  sublo[3], subhi[3], kk;

         if (Convcoo(0,imno,str_centr,2,&kk,sublo,subhi) != 0)
            SCETER(2,err_center);
         if (ca == 0) disp[2] = sublo[0] + 1; 	/* we count 1, ..., npix */
         if (cb == 0) disp[3] = sublo[1] + 1;
         }
      }
   }


/* but don't forget to look for fixpoint pixels (new or previous ones) */

if (defaul[5] != 'Y')
   {
   if (defaul[5] == 'N') 
      {
      int kk;
      char ww[104];

      (void) SCKRDR("FIXPT",1,4,&actvals,rdisp,&unit,&knul);
      disp[5] = CGN_NINT(rdisp[0]);		/* frame pixels */
      disp[6] = CGN_NINT(rdisp[1]);
      (void) SCKGETC("P7",1,100,&actvals,ww);	/* need for float check */
      kk = CGN_INDEXC(ww,',');			/* skip over frame pixels */
      ww[kk] = '_';
      kk = CGN_INDEXC(ww,',') + 1;
      m =  CGN_INDEXC(&ww[kk],'.');
      if (m > 0)			/* we have normalized coords */
         {
         disp[7] = CGN_NINT(rdisp[2]*(QDSZX-1));
         disp[8] = CGN_NINT(rdisp[3]*(QDSZY-1));
         }
      else
         {
         disp[7] = CGN_NINT(rdisp[2]);
         disp[8] = CGN_NINT(rdisp[3]);
         }
      }
   icent[0] = disp[5];
   icent[1] = disp[6];
   icent[2] = disp[7];
   icent[3] = disp[8];
   }

else                                       /* o.k. we take the center option */
   { 
   disp[5] = disp[6] = disp[7] = disp[8] = -1;     /* invalidate fixpoint 
                                                      pixels:  disp[5,6,7,8] */
   *icent = disp[2];
   if ( *icent < 1 || *icent > *npix ) *icent = (*npix/2) + 1;
   icent[1] = disp[3];
   if ((icent[1] < 1) || (icent[1] > npix[1])) icent[1] = (npix[1]/2) + 1;
   

   /* default screen center pixels will be set in DCLOAD
      e.g. for display => QMSZX/2 and QMSZY/2           */   

   icent[2] = -1;
   icent[3] = -1;
   }


if (defaul[2] == 'D')     
   LOADDR = 99;
else
   LOADDR = 0;

if (defaul[4] == 'O')     
   SOURCE = 2;
else
   SOURCE = 1;


/* if cuts equal or specific CUTS strategy required, do it via MYCUTS_C */

if (cuts[0] >= cuts[1])
   {
   if ((cuts[2] < cuts[3]) && (*str_cuts == '\0'))
      {
      cuts[0] = cuts[2];
      cuts[1] = cuts[3];
      }
   else
      {
      int  toto;

      if ((*str_cuts == '\0') || (*str_cuts == ' '))
         (void) strcpy(str_cuts,"3SIGMA");

      (void) SCKRDI("MONITPAR",20,1,&actvals,&num,&unit,&knul);
      num = num * num;			/* default mapping size */
      toto = npix[0] * npix[1];		/* that's sloppy for 3-dim ... */
      if (dattyp != D_R4_FORMAT)
         {
         (void) SCFCLO(imno);
         (void) SCFOPN(name,D_R4_FORMAT,0,F_IMA_TYPE,&imno);
         MYCUTS_C(str_cuts,1,imno,toto,num,cuts);
         (void) SCFCLO(imno);
         (void) SCFOPN(name,dattyp,0,F_IMA_TYPE,&imno);
         }
      else
         MYCUTS_C(str_cuts,1,imno,toto,num,cuts);
      }

   if (cuts[0] >= cuts[1]) SCETER(1,err_cuts);
   }


/* load image into display or into file */

DCLOAD(imno,name_str,dattyp,icent,cuts,scale,chan_flag);

/*
Now display everything in the Image Display if either we
loaded into currently displayed channel or split_screen mode
*/

if (dsplfl == 1)
   {
   int  splmod;

   (void) SCKRDI("DAZHOLD",3,1,&actvals,&splmod,&unit,&knul);

   if ((savcha == QIMCH) || (QRGBFL == 1) || (splmod != 0))
      {
      (void) Cdazvis(QDSPNO,QIMCH,2,1);

      /* check if we loop on CUTS */

      (void) SCKGETC("MID$SPEC",1,10,&actvals,cbuff);
      if (strncmp(cbuff,"CUTS_L",6) == 0)	/* test for: CUTS_LOOP */
         {
cuts_loop:
         (void) SCTDIS("Enter new cuts or X: ",1);
         (void) scanf("%s",cbuff);
         if ((*cbuff != 'x') && (*cbuff != 'X'))
            {
            num = CGN_CNVT(cbuff,2,2,idum,cuts,&ddum);
            if (num <= 0)
               SCTPUT("Invalid syntax ...");
            else
               {
               DCLOAD(imno,name_str,dattyp,icent,cuts,scale,chan_flag);
               (void) Cdazvis(QDSPNO,QIMCH,2,1);
               }
            goto cuts_loop;
            }
         }
      }

   if (savcha != QIMCH)			/* reset to original channel */
      {
      QIMCH = savcha;
      (void) DCGICH(QIMCH);
      }

   DCCLOS(QDSPNO);
   }


/* update descriptors LHCUTS + DISPLAY_DATA 
   if we can't too bad, but no abort!               */

SCECNT("PUT",&con_alw, &log_no,&dis_no);
(void) SCDWRR(imno,"LHCUTS",cuts,1,4,&unit);
(void) SCDWRI(imno,"DISPLAY_DATA",disp,1,9,&unit);
SCECNT("PUT",&ec,&el,&ed);

return SCSEPI();
}
