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

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.IDENTIFIER  module WIMG
.LANGUAGE    C
.AUTHOR      K. Banse, IPG-ESO Garching
.KEYWORDS    memory, ImageDisplay & Virtual Display
.COMMENTS    contains WIMGA_C and WIMGB_C
.ENVIRONment MIDAS
             #include <midas_def.h>   Prototypes for MIDAS interfaces
             #include <idinumd.h>     Global variables for DISPLAY interfaces

.VERSIONS    1.00	940322	F->C, converted from WIMGA.FOR   RvH

 090702		last modif
------------------------------------------------------------*/

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

#define  _POSIX_SOURCE 1

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

#include <midas_def.h>
#include <proto_II.h>
#include <idinumd.h>

#define FOREVER    while(1)             /* infinite loop */

static int  inaux[6] = {-1,-1,-1,-1,-1,-1};

/*

*/

/*++++++++++++++++++++++++++++++
.IDENTIFIER  WIMGA_C
.PURPOSE     write a 2-D image into given memory board of Image Display
.ALGORITHM   set resolution to only low byte transfer
             if image is larger than the image memory size, a square around
             the given center pixels is loaded
             image is loaded into center of image memory

.INPUT/OUTPUT
  call as    
  WIMGA_C(ldspno,limch,imno,khelp,loaddir,npix,icen,cuts,scale,pntrD)

  input:
         int   ldspno  : display no.
         int   limch   : channel no.
         int   imno    : image no. of input image
         int   *khelp  : [0]    data type (as D_xx_FORMAT)
			 [1,2]  mapping sizes
			 [3]    subwindow flag (= 1, if so)
			 [4]    NFX, if SUBWDW > 0
			 [5,6]  NSX,NSY, if SUBWDW > 0
			 [7,8] Startpixel in frame, if SUBWDW > 0
                         [9]    SOURCE, 2 or 1 - overwrite or not
                         [10]   cube_flag, 0 - 2-dim display
                                           1 - 3-dim display in one channel
                                           2 - 3-dim display in all channels
                         [11,12] if cube_flag > 0: 1. plane and last plane
         float npix[2] : no. of pixels in x- and y-dir.
         int   icen[4] : fixpoint: screen pixels + frame pixels
         float cuts[2] : low + high cut in z-dir.
         int   scale[3]: scaling factors for image in x,y
    			 [0,1] if > 1: make image smaller
    			       if < 1: make image larger
			 [2] flag for averaging (=1) or not (=0)

.RETURNS     nothing
------------------------------*/

void WIMGA_C(ldspno,limch,imno,khelp,loaddir,npix,icen,cuts,scale )
int   ldspno, limch, imno, *khelp, loaddir, *npix, *icen, *scale;
float *cuts;

{
int   bufind, incr, imx, imy, ilx, ily, insiz, intake, felem,
      iav, msizei, msizeo, nlines, outmul, outsiz, ifact,
      rmaind, scsave, insav, subwdw, trsize, zin, zinsiz;
int   dattyp, plane_off, plcount, kcen[2], kcuts[2], outaux[2];
register int ii, jj, ix, iy, kk;
static int  ffelem, ntx, nty, nfx, nfy, once=1;

float factor, ranmax, sum, faux[3];

char          *pntrW;
unsigned char *pntrD;



/* allocate buffer space */
 
imx = khelp[2] * sizeof(unsigned char);
pntrW = (char *) 0;
pntrD = (unsigned char *) malloc((size_t) imx);

ranmax  = QLUTSZ - 1.0;
*inaux  = dattyp = khelp[0];		/* get data type */
msizei  = khelp[1];
msizeo  = khelp[2];
subwdw  = khelp[3];			/* if = 1, it's a subwindow... */
*outaux = QLUTSZ - 1;
trsize = npix[0]*npix[1];

if (scale[2] != 0) dattyp = D_R4_FORMAT;	/* averaging uses real data */

alloc_data:
switch (dattyp)
   {
   case D_R4_FORMAT:
      imx = msizei * sizeof(float);
      pntrW = malloc((size_t) imx);
      break;
   case D_I4_FORMAT:
      imx = msizei * sizeof(int);
      pntrW = malloc((size_t) imx);
      break;
   case D_I2_FORMAT:
      imx = msizei * sizeof(short int);
      pntrW = malloc((size_t) imx);
      break;
   case D_I1_FORMAT:
      imx = msizei * sizeof(unsigned char);
      pntrW = malloc((size_t) imx);
      break;
   case D_UI2_FORMAT:
      imx = msizei * sizeof(unsigned short int);
      pntrW = malloc((size_t) imx);
      break;
   default:
      SCETER(1,"FATAL error in WIMGA_C: unknown data type" );
      break;
   }

if (subwdw == 0) 
   {
   if (once == 1)
      {		/* if complete window, save size of image loaded previously */
      imx = SSPX;                         /* old SSPX */
      imy = SSPY;
      ilx = SSPX + NSX;
      ily = SSPY + NSY;

      /* set up values for image display size X-, Y-registers */

      *kcen     = *icen;
      *(kcen+1) = *(icen+2);
      SIZER_C(QMSZX,npix[0],scale[0],scale[2],kcen,
              &NSX,&SSPX,&nfx,&SFPX);

      *kcen     = *(icen+1);
      *(kcen+1) = *(icen+3);
      SIZER_C(QMSZY,npix[1],scale[1],scale[2],
              kcen,&NSY,&SSPY,&nfy,&SFPY);

      ntx = NSX;
      nty = NSY;
      ffelem = SFPX + ((*npix) * (SFPY-1));

      /* test if we have to clear channel first */

      if ( SOURCE == 1 )
         {
         if ( DZDRAW || (imx < SSPX) || (imy < SSPY) ||
              (ilx > (SSPX+ntx)) || (ily > (SSPY+nty)) ) 
            (void) IIMCMY_C( ldspno, &limch, 1, 0 );
         }
      once = 0;
      }

   DZDRAW = 0;                         /* always clear draw flag */

   /* set up transfer window (load size regs. + CMRs) */

   (void) IIMSTW_C(ldspno,limch,loaddir,ntx,nty,QMDEP,SSPX,SSPY);
   plane_off = 0;
   }

else                                     /* Subwindow */
   {
   nfx = khelp[4];
   ntx = khelp[5];
   nty = khelp[6];
   khelp[10] = 0;
   if (ZPLANE != 0)
      plane_off = (ZPLANE-1)*trsize;
   else
      plane_off = 0;
   imx = khelp[8] - 1;
   ffelem = khelp[7] + ((*npix) * imx);
   imy = npix[0] * (npix[1] - imx);
   if (msizei > imy) msizei = imy;
   }
plcount = 1;


/* scale image */

if ((cuts[1] - cuts[0]) < 10.e-25)     
   {
   *faux = 1.0;
   *cuts = 0.;
   }
else
   *faux = ranmax / (cuts[1] - cuts[0]);

faux[1] = cuts[0];
faux[2] = cuts[1];

inaux[3] = abs( *scale );                 /* scaling factor */
inaux[4] = 1;
if (inaux[5] < 0)
   {
   int  uni, nulo;			/* read only once */

   (void) SCKRDI("DAZDEVR",5,1,&iav,&inaux[5],&uni,&nulo);
   }


if ( *khelp == D_I1_FORMAT )           
   {
   kcuts[0] = CGN_NINT( cuts[0] );
   kcuts[1] = CGN_NINT( cuts[1] );
   if ( kcuts[0] >= 0 && kcuts[1] <= *outaux ) inaux[4] = 0;
   }


if (khelp[10] > 0)			/* check 3-dim stuff */
   {
   plane_off = (khelp[11]-1) * trsize;
   plcount = khelp[12]-khelp[11]+1;
   }


/* start in ima_memory */

plane_loop:
felem = ffelem + plane_off;
imx  = imy = 0;                           /* with respect to transfer window */
bufind = felem;


/* compute internal buffer sizes depending on scaling */

if ( scale[1] < 0 )
   {
   outmul = 1;                  /* 1 input line => multiple output lines */
   scsave = 1;
   incr = npix[0];
   }
else
   {
   outmul = msizeo / ntx;               /* no. of lines in out buffer */
   if (outmul < 1)			/* should not happen... */
      SCETER(41,"FATAL error in WIMGA_C: bad output buffer");
   if (outmul > nty) outmul = nty;
   scsave = scale[1];
   incr = npix[0] * scale[1];
   }
if (scale[2] != 0) SOURCE = 3;		/* we average really */

if ( scale[0] < 0 )
   inaux[2] = nfx;                      /* no. of input data to work on */
else
   inaux[2] = ntx;                      /* no. of input data to work on */


FOREVER                                /* we should fill at least once */
   {
   intake = *npix * outmul * scsave;
   if (intake > trsize) intake = trsize;
   if ( intake > msizei )
      {
      if ( --outmul <= 0 )         /* if we omit lines, no problem... */
         {
         if ( scsave > 1 && scale[2] == 0 )
            {
            outmul = 1;
            intake = *npix * scsave;   /* all lines together */
            insiz  = intake;
            ifact = 1;
            outsiz = ntx;              /* just 1 line */
            nlines = nty ;
            rmaind = 0;
            }
         else
            {
            free (pntrW);
            msizei = intake;
            goto alloc_data;
            }
         break;                          /* we have filled it! */
         }
      }
   else
      {
      ifact  = msizei / intake;            /* size of in buffer */
      insiz = ifact * intake;
      outsiz = outmul * ntx;               /* size of out buffer */
      nlines = nty / outmul;
      rmaind = nty - nlines * outmul;
      break;                               /* we have filled it! */
      }
   }


/* branch on scaling factor */

if ( scale[0] == 1 && scale[1] == 1 )     /* No Scaling */
   {
   for ( ii = 0; ii < nlines; ii++ )
      {
      if ( felem + intake > bufind )     
         {
         (void) SCFGET( imno, felem, insiz, &iav, pntrW );
         bufind += iav;
         inaux[1] = 0;                  /* input offset */
         }

      /* split depending on *npix */

      outaux[1] = 0;                      /* output offset */
      if ( *npix <= ntx )     
         {
         inaux[2] = outsiz;
         I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
         inaux[1] += outsiz;
         }
      else
         {
         for ( jj = 0; jj < outmul; jj++ )
            {
            I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
            inaux[1]  += incr;
            outaux[1] += ntx;
            }
         }

      (void) IIMWMY_C( ldspno, limch, pntrD, outsiz, QMDEP, 4, imx, imy );
      imy   += outmul;
      felem += intake;
      }

   if ( rmaind > 0 )     
      {
      outsiz = rmaind * ntx;
      intake = rmaind * *npix;

      /* we do the FOR loop once more... */    

      if ( felem + intake > bufind )
         {
         (void) SCFGET( imno, felem, insiz, &iav, pntrW );
         inaux[1] = 0;
         }
      outaux[1] = 0;
      if ( *npix <= ntx )     
         {
         inaux[2] = outsiz;
         I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
         inaux[1] += outsiz;
         }
      else
         {
         for (jj=0; jj<rmaind; jj++)
            {
            I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
            inaux[1]  += incr;
            outaux[1] += ntx;
            }
         }
      (void) IIMWMY_C( ldspno, limch, pntrD, outsiz, QMDEP, 4, imx, imy );
      }
   }


/* here for spatial scaling/sampling */

else    
   {
   if ( scale[1] > 0 )    
      {
      zin = *npix * (1 + (outmul-1)*scsave);	/* avoid last omitted lines */
      zinsiz = *npix * (1 + (outmul*ifact - 1)*scsave);

      if ( *scale < 0 )     
         {
         for ( ii = 0; ii < nlines; ii++)
            {
            if ( felem + zin > bufind )     
               {
               (void) SCFGET( imno, felem, zinsiz, &iav, pntrW );
               bufind += insiz;
               inaux[1] = 0;
               }
            outaux[1] = 0;

            for ( jj = 0; jj < outmul; jj++)
               { K1PACK_C( pntrW, inaux, faux, pntrD, outaux );
               inaux[1]  += incr;
               outaux[1] += ntx;
               }

            (void) IIMWMY_C(ldspno,limch,pntrD,outsiz,QMDEP,4,imx,imy);
            imy  += outmul ;
            felem += intake;
            }

         if ( rmaind > 0 )     
            {
            outsiz = rmaind * ntx;
            intake = *npix * rmaind * scale[1];
            zin    = intake - incr + *npix;
            zinsiz = insiz - incr + *npix;

            /* we do the FOR loop once more... */    

            if ( felem + zin > bufind )    
               {
               (void)  SCFGET( imno, felem, zinsiz, &iav, pntrW );
               inaux[1] = 0;
               }
            outaux[1] = 0;

            for ( jj = 0; jj < rmaind; jj++)
               { 
               K1PACK_C( pntrW, inaux, faux, pntrD, outaux );
               inaux[1]  += incr;
               outaux[1] += ntx;
               }

            (void) IIMWMY_C(ldspno,limch,pntrD,outsiz,QMDEP,4,imx,imy);
            }
         }

      else                              /* scale in X larger than zero */
         {
         if ( scale[2] == 0 )              /* just scaling */
            {
            for ( ii = 0; ii < nlines; ii++ )
               {
               if ( felem + zin > bufind )     
                  {
                  (void)SCFGET(imno,felem,zinsiz,&iav,pntrW);
                  bufind += insiz;
                  inaux[1] = 0;
                  }
               outaux[1] = 0;

               for ( jj = 0; jj < outmul; jj++ )
                  {
                  I1PACK_C( pntrW, inaux, faux, pntrD, outaux);
                  inaux[1]  += incr;
                  outaux[1] += ntx;
                  }

               (void) IIMWMY_C(ldspno,limch,pntrD,outsiz,QMDEP,4,imx,imy);
               imy  += outmul ;
               felem += intake;
               }

            if ( rmaind > 0 )     
               {
               outsiz = rmaind * ntx;
               intake = *npix * rmaind * scale[1];
               zin = *npix + intake - incr;

               if ( felem + zin > bufind )     
                  {
                  (void) SCFGET(imno,felem,zin,&iav,pntrW);
                  inaux[1] = 0;
                  }
               outaux[1] = 0;

               for ( jj = 0; jj < rmaind; jj++ )
                  { I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
                  inaux[1]  += incr;
                  outaux[1] += ntx;
                  }

               (void) IIMWMY_C(ldspno,limch,pntrD,outsiz,QMDEP,4,imx,imy);
               }
            }

         else                                   /* we really average */
            {
            float *data, *tdata, *work;


            /* create work space */

            data = (float *) pntrW;
            work = (float *) malloc((size_t) (ntx * sizeof(float)));

            factor = 1. / (*scale * scale[1]);		/* scaling factor */

            if ( nlines > 0 ) 
               {
               inaux[3] = 1;        /* we don't scale anymore... */
               inaux[4] = 0;
               }

            for (ii=0; ii<nlines; ii++)
               { 
               if (felem + intake > bufind)     
                  {
                  (void) SCFGET(imno,felem,insiz,&iav,pntrW);
                  data = (float *) pntrW;
                  bufind += insiz;
                  inaux[1] = 0;
                  }
               outaux[1] = 0;

               if (scale[2] == 1)
                  {
                  for (jj=0; jj<outmul; jj++)
                     {
                     for (kk=0; kk<ntx; kk++) *work++ = 0.0;
                     work -= ntx;

                     tdata = data + inaux[1];
                     for (iy=0; iy<scale[1]; iy++)
                        {
                        for (kk=0; kk<ntx; kk++)
                           {
                           sum = 0.0;
                           for (ix=0; ix<*scale; ix++) sum += *tdata++;
                           *work++ += sum;
                           }
                        work -= ntx;
                        tdata += *npix - (*scale * ntx); /* move up one line */
                        }

                     /* scale the accum. col.sums */
  
                     for (kk=0; kk<ntx; kk++) *work++ *= factor;
                     work -= ntx;

                     insav = inaux[1];         /* save inaux[1] */
                     inaux[1] = 0;
                     I1PACK_C((char *) work,inaux,faux,pntrD,outaux);
                     inaux[1] = insav + incr;
                     outaux[1] += ntx;
                     }
                  }

               else
                  {
                  float  rr;

                  for (jj=0; jj<outmul; jj++)
                     {
                     tdata = data + inaux[1];
                     for (kk=0; kk<ntx; kk++)
                        {
                        *work++ = *tdata;
                        tdata += *scale;
                        }
                     work -= ntx;
                     tdata = data + inaux[1];

                     if (scale[2] == 2)                 /* Minimum */
                        {
                        for (iy=0; iy<scale[1]; iy++)
                           {
                           for (kk=0; kk<ntx; kk++)
                              {
                              sum = *work;
                              for (ix=0; ix<*scale; ix++)
                                 {
                                 rr = *tdata++;
                                 if (sum > rr) sum = rr;
                                 }
                              *work++ = sum;
                              }
                           work -= ntx;
                           tdata += *npix - (*scale * ntx);
                           }
                        }
                     else                               /* Maximum */
                        {
                        for (iy=0; iy<scale[1]; iy++)
                           {
                           for (kk=0; kk<ntx; kk++)
                              {
                              sum = *work;
                              for (ix=0; ix<*scale; ix++)
                                 {
                                 rr = *tdata++;
                                 if (sum < rr) sum = rr;
                                 }
                              *work++ = sum;
                              }
                           work -= ntx;
                           tdata += *npix - (*scale * ntx);
                           }
                        }

                     insav = inaux[1];         /* save inaux[1] */
                     inaux[1] = 0;
                     I1PACK_C((char *) work,inaux,faux,pntrD,outaux);
                     inaux[1] = insav + incr;
                     outaux[1] += ntx;
                     }
                  }

               (void) IIMWMY_C(ldspno,limch,pntrD,outsiz,QMDEP,4,imx,imy);
               imy += outmul;
               felem += intake;
               }

            if ( rmaind > 0 )     
               {
               outsiz = rmaind * ntx;
               intake = *npix * rmaind * scale[1];

               /* we do the FOR loop once more... */    

               if ( felem + intake > bufind )     
                  {
                  (void) SCFGET(imno,felem,insiz,&iav,pntrW);
                  data = (float *) pntrW;
                  inaux[1] = 0;
                  }
               outaux[1] = 0;

               if (scale[2] == 1)
                  {
                  for (jj=0; jj<rmaind; jj++)
                     {
                     for (kk=0; kk<ntx; kk++) *work++ = 0.0;
                     work -= ntx;

                     tdata = data + inaux[1];
                     for (iy=0; iy<scale[1]; iy++)
                        {
                        for (kk=0; kk<ntx; kk++)
                           {
                           sum = 0.0;
                           for ( ix = 0; ix < *scale; ix++ ) sum += *tdata++;
                           *work++ += sum;
                           }
                        work -= ntx;
                        tdata += *npix - (*scale * ntx);
                        }
                     for (kk=0; kk<ntx; kk++) *work++ *= factor;
                     work -= ntx;

                     insav = inaux[1];          /* save inaux[1] */
                     inaux[1] = 0;
                     I1PACK_C((char *) work,inaux,faux,pntrD,outaux);
                     inaux[1] = insav + incr;
                     outaux[1] += ntx;
                     }
                  }
               else
                  {
                  float  rr;
                  for (jj=0; jj<rmaind; jj++)
                     {
                     tdata = data + inaux[1];
                     for (kk=0; kk<ntx; kk++)
                        {
                        *work++ = *tdata;
                        tdata += *scale;
                        }
                     work -= ntx;
                     tdata = data + inaux[1];

                     if (scale[2] == 2)                 /* Minimum */
                        {
                        for (iy=0; iy<scale[1]; iy++)
                           {
                           for (kk=0; kk<ntx; kk++)
                              {
                              sum = *work;
                              for (ix=0; ix<*scale; ix++)
                                 {
                                 rr = *tdata++;
                                 if (sum > rr) sum = rr;
                                 }
                              *work++ = sum;
                              }
                           work -= ntx;
                           tdata += *npix - (*scale * ntx);
                           }
                        }
                     else                               /* Maximum */
                        {
                        for (iy=0; iy<scale[1]; iy++)
                           {
                           for (kk=0; kk<ntx; kk++)
                              {
                              sum = *work;
                              for (ix=0; ix<*scale; ix++)
                                 {
                                 rr = *tdata++;
                                 if (sum < rr) sum = rr;
                                 }
                              *work++ = sum;
                              }
                           work -= ntx;
                           tdata += *npix - (*scale * ntx);
                           }
                        }

                     insav = inaux[1];         /* save inaux[1] */
                     inaux[1] = 0;
                     I1PACK_C((char *) work,inaux,faux,pntrD,outaux);
                     inaux[1] = insav + incr;
                     outaux[1] += ntx;
                     }
                  }

               (void) IIMWMY_C(ldspno,limch,pntrD,outsiz,QMDEP,4,imx,imy);
               }

            (void) free((char *)work);
            }
         }
      }

/* here with y-scale < 0 (replicate y-lines) */

   else  
      {
      outaux[1] = 0;

      for ( ii = 0; ii < nlines && imy < nty; ii++ )
         {
         if ( felem + nfx > bufind )     
            {
            (void) SCFGET( imno, felem, insiz, &iav, pntrW );
            bufind += iav;
            inaux[1] = 0;
            }

         if ( *scale < 0 )     
            K1PACK_C( pntrW, inaux, faux, pntrD, outaux );
         else
            I1PACK_C( pntrW, inaux, faux, pntrD, outaux );

         for (jj=0; jj<- scale[1]; jj++)
            {
            (void) IIMWMY_C(ldspno,limch,pntrD,outsiz,QMDEP,4,imx,imy);
            if (++imy >= nty) goto end_of_it;
            }

         felem += intake;              /* intake = npix[0] */
         inaux[1] += incr;
         }
      }
   }



/* common end section: */

end_of_it:
if ( subwdw != 0 )
   (void) IIMSMV_C(ldspno,&limch,1,1);

else
   {
   plcount --;
   if (plcount > 0)
      {
      plane_off += trsize;                      /* move to next plane */
      (void) IIMSMV_C(ldspno,&limch,1,1);
      goto plane_loop;
      }
   }

(void) free(pntrW);
(void) free((char *) pntrD);


/* reset transfer window to all of the memory */

if ( subwdw != 2 )
   (void) IIMSTW_C( ldspno, limch, loaddir, QMSZX, QMSZY, QMDEP, 0, 0 );
}

/*

*/

/*++++++++++++++++++++++++++++
.IDENTIFIER  WIMGB_C
.PURPOSE     write a 2-dimensional image into a frame serving as 
             Virtual Display
.ALGORITHM   the output frame has a depth of 1 byte

.INPUT/OUTPUT
  call as    WIMGB_C( imno,khelp,pntrW,npix,cuts,scale,pntrD,outno,aux )

  input:
         int   imno    : image no. of input image
         int   *khelp  : [0]    data type (as D_xx_FORMAT)
                         [1,2]  mapping sizes
         float npix[2] : no. of pixels in x- and y-dir.
         float cuts[2] : low + high cut in z-dir.
         int   scale[3]: scaling factors for image in x,y
                          [0,1] if > 1: make image smaller
                                if < 1: make image larger
                          [2]   flag for averaging (=1) or not (=0)
         int   outno   : image no. of output image
         int   *aux    : image + display sizes

.RETURNS     nothing
------------------------------*/

void WIMGB_C( imno, khelp, npix, cuts, scale, outno, aux )
int      imno, outno, *khelp, *aux, *npix, *scale;
float    *cuts;

{
register int ii, jj, ix, iy, kk;

int   bufind, incr, insiz, intake, felem, nlines, outmul, outoff;
int   outsiz, rmaind, scsave, insav, trsize, zin, zinsiz, ntx, nty;
int   ifact, iav, imx, imy, msizei;
int   dattyp, inaux[6], kcuts[2], outaux[2];

float factor, ranmax, sum, faux[3];

char          *pntrW;
unsigned char *pntrD;




imx = khelp[2] * sizeof(unsigned char);
pntrW = (char *) 0;
pntrD = (unsigned char *) malloc((size_t) imx);

ranmax  = 255;
*outaux = 255;
*inaux  = dattyp = khelp[0];		/* get data type */
msizei  = khelp[1];
trsize = npix[0]*npix[1];

if (scale[2] != 0) dattyp = D_R4_FORMAT;        /* averaging uses real data */

alloc_data:
switch (dattyp)
   {
   case D_R4_FORMAT:
      imx = msizei * sizeof(float);
      pntrW = malloc((size_t) imx);
      break;
   case D_I4_FORMAT:
      imx = msizei * sizeof(int);
      pntrW = malloc((size_t) imx);
      break;
   case D_I2_FORMAT:
      imx = msizei * sizeof(short int);
      pntrW = malloc((size_t) imx);
      break;
   case D_I1_FORMAT:
      imx = msizei * sizeof(unsigned char);
      pntrW = malloc((size_t) imx);
      break;
   case D_UI2_FORMAT:
      imx = msizei * sizeof(unsigned short int);
      pntrW = malloc((size_t) imx);
      break;
   default:
      SCETER(1,"FATAL error in WIMGB_C: unknown data type" );
      break;
   }

ntx  = aux[0];
nty  = aux[5];


/* scale image */

if ( cuts[1] - cuts[0] < 10.e-25 )     
   {
   *faux = 1.0;
   *cuts = 0.;
   }
else
   *faux = ranmax / (cuts[1] - cuts[0]);

faux[1] = cuts[0];
faux[2] = cuts[1];


inaux[2] = aux[2];                        /* no. of input data to work on */
inaux[3] = abs( *scale );                 /* scaling factor */
inaux[4] = 1;
inaux[5] = 0;

if (dattyp == D_I1_FORMAT ) 
   {
   kcuts[0] = CGN_NINT( cuts[0] );
   kcuts[1] = CGN_NINT( cuts[1] );
   if ( kcuts[0] >= 0 && kcuts[1] <= *outaux ) inaux[4] = 0;
   }


/* init pointer LINE and start in ima_memory */

outoff = 1;
bufind = felem = aux[3] + (aux[8]-1) * (*npix);


/* compute internal buffer sizes depending on scaling */

if ( scale[1] < 0 )
   {
   outmul = 1;                  /* 1 input line => multiple output lines */
   scsave = 1;
   incr = npix[0];
   }
else
   {
   outmul = khelp[2] / ntx;            /* no. of lines in out buffer */
   if (outmul < 1)                      /* should not happen... */
      SCETER(41,"FATAL error in WIMGB_C: bad output buffer" );
   if (outmul > nty) outmul = nty;
   scsave = scale[1];
   incr = npix[0] * scale[1];
   }
trsize = npix[0]*npix[1];

if ( scale[0] > 0 )
   inaux[2] = ntx;                      /* no. of input data to work on */


FOREVER                                /* we should fill at least once */
   {
   intake = *npix * outmul * scsave;
   if (intake > trsize) intake = trsize;
   if (intake > msizei)
      {
      if (--outmul <= 0)         /* if we omit lines, no problem... */
         {
         if ((scsave > 1) && (scale[2] == 0))
            {
            outmul = 1;
            intake = *npix * scsave;           /* all lines together */
            insiz  = intake;
            ifact = 1;
            outsiz = ntx;                      /* just 1 line */
            nlines = nty ;
            rmaind = 0;
            }
         else
            {
            free (pntrW);
            msizei = intake;
            goto alloc_data;
            }
         break;                                  /* we have filled it! */
         }
      }
   else
      {
      ifact = msizei / intake; 
      insiz = intake * ifact;			 /* size of in buffer */
      outsiz = outmul * ntx;                     /* size of out buffer */
      nlines = nty / outmul;
      rmaind = nty - nlines * outmul;
      break;                                     /* we have filled it! */
      }
   }

/* branch on scaling factor */

if ( scale[0] == 1 && scale[1] == 1 )     /* No Scaling */
   {
   for ( ii = 0; ii < nlines; ii++ )
      {
      if ( felem + intake > bufind )     
         {
         (void) SCFGET( imno, felem, insiz, &iav, pntrW );
         bufind += iav;
         inaux[1] = 0;                  /* input offset */
         }

      /* split depending on NPIX[0] */

      outaux[1] = 0;                      /* output offset */
      if ( *npix <= ntx )
         {
         inaux[2]  = outsiz;
         I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
         inaux[1] += outsiz;
         }
      else
         {
         for ( jj = 0; jj < outmul; jj++ )
            {
            I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
            inaux[1]  += incr;
            outaux[1] += ntx;
            }
         }

      (void) SCFPUT( outno, outoff, outsiz,(char *) pntrD );
      outoff += outsiz;
      felem += intake;
      }

   if ( rmaind > 0 )
      {
      outsiz = rmaind * ntx;
      intake = rmaind * npix[1];

      /* we do the FOR loop once more... */    

      if ( felem + intake > bufind )     
         {
         (void) SCFGET( imno, felem, insiz, &iav, pntrW );
         inaux[1] = 0;                                  /* input offset */
         }

      outaux[1] = 0;                                      /* output offset */
      if ( *npix <= ntx )
         {
         inaux[2]  = outsiz;
         I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
         inaux[1] += outsiz;
         }
      else
         {
         for ( jj = 0; jj < rmaind; jj++ )
            {
            I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
            inaux[1]  += *npix;
            outaux[1] += ntx;
            }
         }

      (void) SCFPUT( outno, outoff, outsiz,(char *) pntrD );
      }
   }


/* here for spatial scaling/sampling */

else 
   {
   if ( scale[1] > 0 )    

   /* here with y-scale > 0         (omit y-lines - or average over them) */

      {
      zin = *npix * (1 + (outmul-1)*scsave);    /* avoid last omitted lines */
      zinsiz = *npix * (1 + (outmul*ifact - 1)*scsave);

      if ( *scale < 0 )     
         {
         for ( ii = 0; ii < nlines; ii++)
            {
            if ( felem + zin > bufind )     
               {
               (void) SCFGET( imno, felem, zinsiz, &iav, pntrW );
               bufind += insiz;
               inaux[1] = 0;
               }

            outaux[1] = 0;

            for ( jj = 0; jj < outmul; jj++)
               {
               K1PACK_C( pntrW, inaux, faux, pntrD, outaux );
               inaux[1]  += incr;
               outaux[1] += ntx;
               }

            (void) SCFPUT( outno, outoff, outsiz,(char *) pntrD );
            outoff += outsiz;
            felem += intake;
            }

         if ( rmaind > 0 )     
            {
            outsiz = rmaind * ntx;
            intake = rmaind * *npix * scale[1];
            zin    = intake - incr + *npix;
            zinsiz = insiz - incr + *npix;

            /* we do the FOR loop once more...  */

            if ( felem + zin > bufind )     
               {
               (void) SCFGET( imno, felem, zinsiz, &iav, pntrW );
               inaux[1] = 0;
               }
            outaux[1] = 0;

            for ( jj = 0; jj < rmaind; jj++)
               {
               K1PACK_C( pntrW, inaux, faux, pntrD, outaux );
               inaux[1]  += incr;
               outaux[1] += ntx;
               }

            (void) SCFPUT( outno, outoff, outsiz,(char *) pntrD );
            }
         }

      else                                /* scale in X larger than zero */
         {
         if ( scale[2] == 0 )                          /* just scaling */
            {
            for ( ii = 0; ii < nlines; ii++ )
               {
               if ( felem + zin > bufind )     
                  {
                  (void)SCFGET(imno,felem,zinsiz,&iav,pntrW);
                  bufind += insiz;
                  inaux[1] = 0;
                  }
               outaux[1] = 0;

               for ( jj = 0; jj < outmul; jj++ )
                  {
                  I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
                  inaux[1]  += incr;
                  outaux[1] += ntx;
                  }

               (void) SCFPUT( outno, outoff, outsiz,(char *) pntrD );
               outoff += outsiz;
               felem += intake;
               }

            if ( rmaind > 0 )     
               {
               outsiz = rmaind * ntx;
               intake = rmaind * *npix * scale[1];
               zin = intake - incr + *npix ;

               if ( felem + zin > bufind )     
                  {
                  (void)SCFGET(imno,felem,zinsiz,&iav,pntrW);
                  inaux[1] = 0;
                  }
               outaux[1] = 0;

               for ( jj = 0; jj < rmaind; jj++ )
                  {
                  I1PACK_C( pntrW, inaux, faux, pntrD, outaux );
                  inaux[1]  += incr;
                  outaux[1] += ntx;
                  }

               (void) SCFPUT( outno, outoff, outsiz,(char *) pntrD );
               }
            }

         else                                     /* we really average */
            {
            float *data, *tdata, *work;

 
            /* create work space */

            data = (float *) pntrW;
            work = (float *) malloc((size_t)(ntx * sizeof(float)));

            /* scaling factor */

            factor = 1. / (scale[0] * scale[1]);

            if ( nlines > 0 ) 
               {
               inaux[3] = 1;        /* we don't scale anymore... */
               inaux[4] = 0;
               }
            for (ii=0; ii<nlines; ii++)
               {
               if (felem + intake > bufind)
                  {
                  (void) SCFGET(imno,felem,insiz,&iav,pntrW);
                  data = (float *) pntrW;
                  bufind += insiz;
                  inaux[1] = 0;
                  }
               outaux[1] = 0;

               if (scale[2] == 1)
                  {
                  for (jj=0; jj<outmul; jj++)
                     {
                     for (kk=0; kk<ntx; kk++) *work++ = 0.0;
                     work -= ntx;

                     tdata = data + inaux[1];
                     for (iy=0; iy<scale[1]; iy++)
                        {
                        for (kk=0; kk<ntx; kk++)
                           {
                           sum = 0.0;
                           for (ix=0; ix<*scale; ix++) sum += *tdata++;
                           *work++ += sum;
                           }
                        work -= ntx;
                        tdata += *npix - (*scale * ntx); /* move up one line */
                        }

                     /* scale the accum. col.sums */
 
                     for (kk=0; kk<ntx; kk++) *work++ *= factor;
                     work -= ntx;

                     insav = inaux[1];         /* save inaux[1] */
                     inaux[1] = 0;
                     I1PACK_C((char *) work,inaux,faux,pntrD,outaux);
                     inaux[1] = insav + incr;
                     outaux[1] += ntx;
                     }
                  }

               else
                  {
                  float  rr;

                  for (jj=0; jj<outmul; jj++)
                     {
                     tdata = data + inaux[1];
                     for (kk=0; kk<ntx; kk++)
                        {
                        *work++ = *tdata;
                        tdata += *scale;
                        }
                     work -= ntx;
                     tdata = data + inaux[1];

                     if (scale[2] == 2)                 /* Minimum */
                        {
                        for (iy=0; iy<scale[1]; iy++)
                           {
                           for (kk=0; kk<ntx; kk++)
                              {
                              sum = *work;
                              for (ix=0; ix<*scale; ix++)
                                 {
                                 rr = *tdata++;
                                 if (sum > rr) sum = rr;
                                 }
                              *work++ = sum;
                              }
                           work -= ntx;
                           tdata += *npix - (*scale * ntx);
                           }
                        }
                     else                               /* Maximum */
                        {
                        for (iy=0; iy<scale[1]; iy++)
                           {
                           for (kk=0; kk<ntx; kk++)
                              {
                              sum = *work;
                              for (ix=0; ix<*scale; ix++)
                                 {
                                 rr = *tdata++;
                                 if (sum < rr) sum = rr;
                                 }
                              *work++ = sum;
                              }
                           work -= ntx;
                           tdata += *npix - (*scale * ntx);
                           }
                        }

                     insav = inaux[1];         /* save inaux[1] */
                     inaux[1] = 0;
                     I1PACK_C((char *) work,inaux,faux,pntrD,outaux);
                     inaux[1] = insav + incr;
                     outaux[1] += ntx;
                     }
                  }

               (void) SCFPUT(outno,outoff,outsiz,(char *) pntrD);
               outoff += outsiz;
               felem += intake;
               }

            if ( rmaind > 0 )
               {
               outsiz = rmaind * ntx;
               intake = *npix * rmaind * scale[1];

               if ( felem + intake > bufind )
                  {
                  (void) SCFGET(imno,felem,insiz,&iav,pntrW);
                  data = (float *) pntrW;
                  inaux[1] = 0;
                  }
               outaux[1] = 0;

               if (scale[2] == 1)
                  {
                  for (jj=0; jj<rmaind; jj++)
                     {
                     for (kk=0; kk<ntx; kk++) *work++ = 0.0;
                     work -= ntx;

                     tdata = data + inaux[1];
                     for (iy=0; iy<scale[1]; iy++)
                        {
                        for (kk=0; kk<ntx; kk++)
                           {
                           sum = 0.0;
                           for ( ix = 0; ix < *scale; ix++ ) sum += *tdata++;
                           *work++ += sum;
                           }
                        work -= ntx;
                        tdata += *npix - (*scale * ntx);
                        }
                     for (kk=0; kk<ntx; kk++) *work++ *= factor;
                     work -= ntx;

                     insav = inaux[1];          /* save inaux[1] */
                     inaux[1] = 0;
                     I1PACK_C((char *) work,inaux,faux,pntrD,outaux);
                     inaux[1] = insav + incr;
                     outaux[1] += ntx;
                     }
                  }
               else
                  {
                  float  rr;
                  for (jj=0; jj<rmaind; jj++)
                     {
                     tdata = data + inaux[1];
                     for (kk=0; kk<ntx; kk++)
                        {
                        *work++ = *tdata;
                        tdata += *scale;
                        }
                     work -= ntx;
                     tdata = data + inaux[1];

                     if (scale[2] == 2)                 /* Minimum */
                        {
                        for (iy=0; iy<scale[1]; iy++)
                           {
                           for (kk=0; kk<ntx; kk++)
                              {
                              sum = *work;
                              for (ix=0; ix<*scale; ix++)
                                 {
                                 rr = *tdata++;
                                 if (sum > rr) sum = rr;
                                 }
                              *work++ = sum;
                              }
                           work -= ntx;
                           tdata += *npix - (*scale * ntx);
                           }
                        }
                     else                               /* Maximum */
                        {
                        for (iy=0; iy<scale[1]; iy++)
                           {
                              for (kk=0; kk<ntx; kk++)
                              {
                              sum = *work;
                              for (ix=0; ix<*scale; ix++)
                                 {
                                 rr = *tdata++;
                                 if (sum < rr) sum = rr;
                                 }
                              *work++ = sum;
                              }
                           work -= ntx;
                           tdata += *npix - (*scale * ntx);
                           }
                        }

                     insav = inaux[1];         /* save inaux[1] */
                     inaux[1] = 0;
                     I1PACK_C((char *) work,inaux,faux,pntrD,outaux);
                     inaux[1] = insav + incr;
                     outaux[1] += ntx;
                     }
                  }
               (void) SCFPUT( outno, outoff, outsiz,(char *) pntrD );
               }

            (void) free((char *)work);
            }
         }
      }


/* here with y-scale < 0 (replicate y-lines) */
     
   else                  
      {
      imy = 0;
      outaux[1] = 0;
      
      for ( ii = 0; ii < nlines; ii++ )
         {
         if ( felem + aux[2] > bufind )     
            {
            (void) SCFGET( imno, felem, insiz, &iav, pntrW );
            bufind += iav;
            inaux[1] = 0;
            }
         if ( *scale < 0 )     
            K1PACK_C( pntrW, inaux, faux, pntrD, outaux);
         else
            I1PACK_C( pntrW, inaux, faux, pntrD, outaux);

         for (jj=0; jj<-scale[1]; jj++)
            {
            (void) SCFPUT( outno, outoff, outsiz,(char *) pntrD );
            outoff += outsiz;
            if (++imy >= nty) goto end_of_it;
            }

         felem += intake;              /* intake = npix[0] */
         inaux[1] += incr;
         }

      }
   }

end_of_it:
(void) free( pntrW );
(void) free( (char *) pntrD );
}
