/* mirror.c

	Copyright (c) Kapteyn Laboratorium Groningen 1991, 1993
	All Rights Reserved.

#>            mirror.dc1

Program:      MIRROR

Purpose:      Mirrors a two-dimensional image in x, y or both. It can
              also rotate the image over +90 or -90 degrees.

Category:     MANIPULATION

File:         mirror.c

Author:       K.G. Begeman

Keywords:

    INSET=    Set and subsets to mirror/rotate. The subsets must be
              two-dimensional. Maximum number of subsets is 2048.

*** BOX=      Box to mirror [whole subset].

    OPTION=   Enter mirror option. 1 Mirrors image around y axis, 2 around
              x axis and 3 around the centre op the box. Option 4 rotates
              the box +90 degrees and options 5 rotates the box -90 degrees.

    OUTSET=   Set and subsets for the mirror images. The output subsets will
              have the size as specified with BOX.

Updates:      Nov  7, 1991: KGB Document created.
              Apr 22, 1993: KGB Bug repaired, output set possible.
              Mar 17, 1994: KGB Rotate option implemented.
              May  3, 1994: KGB Commandline documentation corrected.
              Feb  1, 2000: JPT Increased number of subsets.
#<

*/

#include	"stdio.h"
#include	"stdlib.h"
#include	"gipsyc.h"
#include	"cmain.h"
#include	"error.h"
#include	"finis.h"
#include	"gdsasn.h"
#include	"gdsbox.h"
#include	"gdscss.h"
#include	"gdsc_fill.h"
#include	"gdsinp.h"
#include	"gdsi_read.h"
#include	"gdsi_write.h"
#include	"gdsout.h"
#include	"init.h"
#include	"status.h"
#include	"userint.h"

#define	CLASS		1
#define	CLASS_DIM	2
#define	KEY_BOX		tofchar("BOX=")
#define	KEY_INSET	tofchar("INSET=")
#define	KEY_OPTION	tofchar("OPTION=")
#define	KEY_OUTSET	tofchar("OUTSET=")
#define	MAXAXES		10
#define	MAXSETNAMELEN	80
#define	MAXSUBSETS	2048
#define	MES_BOX		tofchar(" ")
#define	MES_INSET	tofchar("Set and subsets to mirror/rotate")
#define	MES_OPTION	tofchar("Mirror? 1: y, 2: x 3: x+y, Rotate? 4: +90, 5: -90")
#define	MES_OUTSET	tofchar(" ")

static	char	setbi[MAXSETNAMELEN];
static	char	setbo[MAXSETNAMELEN];
static	fchar	seti = { setbi, MAXSETNAMELEN };
static	fchar	seto = { setbo, MAXSETNAMELEN };
static	fint	axpermi[MAXAXES];
static	fint	axpermo[MAXAXES];
static	fint	axsizei[MAXAXES];
static	fint	axsizeo[MAXAXES];
static	fint	bloi[CLASS_DIM];
static	fint	bloo[CLASS_DIM];
static	fint	bupi[CLASS_DIM];
static	fint	bupo[CLASS_DIM];
static	fint	subseti[MAXSUBSETS];
static	fint	subseto[MAXSUBSETS];

MAIN_PROGRAM_ENTRY
{
   fint		indata = 1;
   fint		ns;
   fint		nsub;
   fint		option;
   fint		xsize = 0;
   fint		ysize = 0;
   float	*in = NULL;
   float	*ou = NULL;

   init_c( );
   {
      fchar	key = KEY_INSET;
      fchar	mes = MES_INSET;
      fint	class = CLASS;
      fint	classdim = CLASS_DIM;
      fint	maxaxes = MAXAXES;
      fint	maxsubsets = MAXSUBSETS;
      fint	input_level = 0;
      fint	output_level = 3;

      nsub = gdsinp_c( seti ,
                       subseti ,
                       &maxsubsets ,
                       &input_level ,
                       key ,
                       mes ,
                       &output_level ,
                       axpermi ,
                       axsizei ,
                       &maxaxes ,
                       &class ,
                       &classdim );
   }
   {
      fchar	key = KEY_BOX;
      fchar	mes = MES_BOX;
      fint	input_level = 2;
      fint	mode = 0;
      fint	output_level = 3;

      gdsbox_c( bloi ,
                bupi ,
                seti ,
                subseti ,
                &input_level ,
                key ,
                mes ,
                &output_level ,
                &mode );
      for (ns = 0; ns < CLASS_DIM; ns++) {
         indata *= ( bupi[ns] - bloi[ns] + 1 );
         switch(ns) {
            case 0: {
               xsize = bupi[ns] - bloi[ns] + 1;
               break;
            }
            case 1: {
               ysize = bupi[ns] - bloi[ns] + 1;
               break;
            }
            default: {
               break;
            }
         }
      }
   }
   {
      fchar	key = KEY_OPTION;
      fchar	mes = MES_OPTION;
      fint	input_level = 0;
      fint	items = 1;

      userint_c( &option, &items, &input_level, key, mes );
      if (option > 5 || option < 1) {
         fint	error_level = 4;

         error_c( &error_level, tofchar( "Illegal Option!" ) );
      }
      in = calloc( indata, sizeof( float ) );
      if (in == NULL) {
         fint	error_level = 4;

         error_c( &error_level, tofchar( "Cannot create enough memory!" ) );
      }
      if (option > 3) {
         ou = calloc( indata, sizeof( float ) );
         if (ou == NULL) {
            fint	error_level = 4;

            error_c( &error_level, tofchar( "Cannot create enough memory!" ) );
         }
      } else {
         ou = in;
      }
   }
   {
      fchar	key = KEY_OUTSET;
      fchar	mes = MES_OUTSET;
      fint	class = CLASS;
      fint	maxaxes = MAXAXES;
      fint	maxsubsets = nsub;
      fint	input_level = 4;
      fint	output_level = 3;

      gdsasn_c( KEY_INSET, KEY_OUTSET, &class );
      switch( option ) {
         case 1:
         case 2:
         case 3: {
            for ( ns = 0; ns < CLASS_DIM; ns++ ) {
               bloo[ns] = bloi[ns];
               bupo[ns] = bupi[ns];
            }
            break;
         }
         case 4:
         case 5: {
            for ( ns = 0; ns < CLASS_DIM; ns++ ) {
               bloo[ns] = bloi[(ns+1)%CLASS_DIM];
               bupo[ns] = bupi[(ns+1)%CLASS_DIM];
            }
            break;
         }
         default: {
            break;
         }
      }
      gdscss_c( KEY_OUTSET, bloo, bupo );
      nsub = gdsout_c( seto ,
                       subseto ,
                       &maxsubsets ,
                       &input_level ,
                       key ,
                       mes ,
                       &output_level ,
                       axpermo ,
                       axsizeo ,
                       &maxaxes );
   }
   for (ns = 0; ns < nsub; ns++) {
      fint	cwloi, cwupi;
      fint	cwloo, cwupo;
      fint	nread;
      fint	nwrite;
      fint	tid = 0;

      cwloi = gdsc_fill_c( seti, &subseti[ns], bloi );
      cwupi = gdsc_fill_c( seti, &subseti[ns], bupi );
      cwloo = gdsc_fill_c( seto, &subseto[ns], bloo );
      cwupo = gdsc_fill_c( seto, &subseto[ns], bupo );
      gdsi_read_c( seti, &cwloi, &cwupi, in, &indata, &nread, &tid );
      switch( option ) {
         case 1: {				/* flip around in x */
            fint	j;

            for (j = 0; j < ysize; j++) {
               fint	i1, i2, k;

               i1 = j * xsize;
               i2 = i1 + xsize - 1;
               for (k = 0; k < xsize / 2; k++) {
                  float	save = in[i1+k];

                  in[i1+k] = in[i2-k];
                  in[i2-k] = save;
               }
            }
            break;
         }
         case 2: {				/* flip around in y */
            fint	k;

            for (k = 0; k < ysize / 2; k++) {
               fint	i, j1, j2;

               j1 = k * xsize;
               j2 = ( ysize - k - 1 ) * xsize;
               for (i = 0; i < xsize; i++) {
                  float	save = in[j1+i];

                  in[j1+i] = in[j2+i];
                  in[j2+i] = save;
               }
            }
            break;
         }
         case 3: {				/* flip in x and y */
            {
               fint	j;

               for (j = 0; j < ysize; j++) {
                  fint	i1, i2, k;

                  i1 = j * xsize;
                  i2 = i1 + xsize - 1;
                  for (k = 0; k < xsize / 2; k++) {
                     float	save = in[i1+k];

                     in[i1+k] = in[i2-k];
                     in[i2-k] = save;
                  }
               }
            }
            {
               fint	k;

               for (k = 0; k < ysize / 2; k++) {
                  fint	i, j1, j2;

                  j1 = k * xsize;
                  j2 = ( ysize - k - 1 ) * xsize;
                  for (i = 0; i < xsize; i++) {
                     float	save = in[j1+i];

                     in[j1+i] = in[j2+i];
                     in[j2+i] = save;
                  }
               }
            }
            break;
         }
         case 4: {
            fint	i, j;

            for ( j = 0; j < ysize; j++ ) {
               for ( i = 0; i < xsize; i++ ) {
                  ou[(i*ysize)+ysize-j-1] = in[(j*xsize)+i];
               }
            }
            break;
         }
         case 5: {
            fint	i, j;

            for ( j = 0; j < ysize; j++ ) {
               for ( i = 0; i < xsize; i++ ) {
                  ou[((xsize-i-1)*ysize)+j] = in[(j*xsize)+i];
               }
            }
            break;
         }
         default: {
            break;
         }
      }
      gdsi_write_c( seto, &cwloo, &cwupo, ou, &indata, &nwrite, &tid );
   }
   finis_c( );
   return( EXIT_SUCCESS );
}

