
/**************************************************************************
 *                                                                        *
 * Copyright (c) 1996 Michael Richmond and Richard Treffers               *
 *                                                                        *
 *                    This software may be copied and distributed for     *
 *                    educational, research and not for profit services   *
 *                    provided that this copyright and statement are      *
 *                    included in all such copies.                        *
 *                                                                        *
 **************************************************************************/


/*  
		IMSHIFT file [dr=] [dc=]

	shift the data in the given file by the given number of rows and cols 

	5/20/92 - allows fractional pixel shifts -rrt
			- add 'fill'

        11/26/95 - remove 'sinc' and 'lagrange' keywords from the
                        'usage' string, since they aren't currently
                        recognized.
	
	3/3/96  - add "sinc" and "lagrange" back into 'usage' string,
	                since their functions now exist.
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#include "pcvista.h"
#include "fits.h"
#include "interp.h"

#ifdef PROTO
int main(int, char **);
static void integer_shift(char *, double, double, int);
static void double_shift(char *, double, double, int16 (*interp)(),int fill);
static void show_options(void);
static int is_integer(double);
#else
static void integer_shift();
static void double_shift();
static void show_options();
static int is_integer();
#endif

#define TOLERANCE .0001			/* how small a shift to ignore */

int
main(argc, argv)
int argc;
char *argv[];
{
	static int i;
	char *gotit, buf[NBUF];
	double rshift,cshift;
	int16 fill;
	PFI16 interp;

	if (argc < 2 ){
		show_options();
		exit(1);
	}
	if (strcmp(argv[1], "help") == 0) {
		show_options();
		exit(0);
	}

	rshift = cshift = 0.;
	fill=0;

	/* default interpolation function */
	interp = (PFI16) bilinear;		

	for (i = 2; i < argc; i++) {
		if (keyword("help", argv[i])) {
			show_options();
			exit(0);
		}
		if ((gotit = find("dr", argv[i])) != NULL) {
			rshift = evaluate(gotit);
			continue;
		}
		if ((gotit = find("dc", argv[i])) != NULL) {
			cshift = evaluate(gotit);
			continue;
		}
		if ((gotit = find("fill", argv[i])) != NULL) {
			fill = (int16)(evaluate(gotit)+0.5);
			continue;
		}
		if (keyword("sinc",argv[i])) {
			interp = (PFI16) sinc;
			continue;
		}
		if (keyword("lagrange",argv[i])) {
			interp = (PFI16) lagrange;
			continue;
		}
		sprintf(buf,"Unknown argument '%s'", argv[i]);
		error(-1, buf);
	}
#ifdef DEBUG
	printf("shifting image %s by %d rows, %d cols\n", argv[1], rshift, cshift);
#endif

	/* if something to do .. do it */
	if ((fabs(rshift)>TOLERANCE) || (fabs(cshift) > TOLERANCE)){
		if(is_integer(rshift) && is_integer(cshift) )
			integer_shift(argv[1] ,rshift,cshift,fill);
		else
			double_shift(argv[1],rshift,cshift,interp,fill);
	}
	exit(0);
}

	/* check to see that the given shifts are okay, then perform the
	   shifts */

static void	  
integer_shift(name, in_rshift, in_cshift,fill)
char *name;
double in_rshift, in_cshift;
int16 fill;
{
	static int i, j, nr, nc, rs, re;
	static int16 outdata[2*NMAX];
	static int ssc;
	static FITS_HANDLE fh, fhout;
	int rshift, cshift;

	fh = fits_open(name, "r+", &nr, &nc);
	fhout = fits_open(name, "r+", &nr, &nc);

	rshift=(int)floor(in_rshift+0.5);
	cshift=(int)floor(in_cshift+0.5);

	if ((rshift < 1 - nr) || (rshift > nr - 1) || (cshift < 1 - nc) || 
	    (cshift > nc - 1))
		error(-1, "invalid number of rows/cols specified");

	/* figure out where to start and end shifting */
	rs = (rshift > 0 ? rshift : 0);
	re = (rshift > 0 ? nr : nr + rshift);
	ssc = NMAX + cshift;	/* where to put it in 'outdata' so that the
	                           place we start writing is outdata[NMAX] */

	for (j = 0; j < nc; j++)
		outdata[j] = fill;

	if (rshift < 0) {
		for (i = rs; i < re; i++) {
			fits_get_data(fh, i - rshift, 0, outdata + ssc, nc);
			fits_put_data_fast(fhout, outdata + NMAX, nc);
		}
	}
	else {
		for (i = re - 1; i >= rs; i--) {
			fits_get_data(fh, i - rshift, 0, outdata + ssc, nc);
			fits_put_data(fhout, i, 0, outdata + NMAX, nc);
		}
	}

	for (i = 0; i < nc; i++)
		outdata[i] = fill;

	/* do the blank rows at the 'bottom' */
	for (i = 0; i < rshift; i++) 
		fits_put_data_fast(fhout, outdata, nc);

	/* now do all the blank rows at the 'top' */
	for (i = nr + rshift; i < nr; i++)
		fits_put_data(fhout, i, 0, outdata, nc);

}


/*	returns 1 if the input is close enough to an integer 
*/

static int is_integer(x)
double x;
{
	int ix;

	if(x < 0.)
		x*=-1.;	/* forget about signs */

	ix=(int)(x+0.5);
	if(fabs(x-(double)ix) < TOLERANCE)
		return 1;
	else
		return 0;
}

/*	double shift requires */

static void double_shift(name, rshift, cshift, interp,fill)
char *name;
double rshift,cshift;
int16 (*interp)();
int fill;
{
	FITS_HANDLE fh;
	int row,col;
	int nrow,ncol,nr,nc;
	double y;
	int16 **data,buf[NMAX];

	fh = fits_open(name, "r+", &nrow, &ncol);

	if ((data = boxdata(fh, -1, (int) nrow, (int) ncol, &nr, &nc)) == NULL)
		error(-1,"couldn't read data from file");
	
	/* set up the sinc-interpolation function */
	initsinc(cshift, rshift);

	for(row=0; row<nrow; row++){
		y=row-rshift;
		for(col=0; col<ncol; col++)
			buf[col]=(*interp)(col-cshift,y,data,nrow,ncol,fill);
		fits_put_data(fh,row,0,buf,ncol);
	}
	fits_close(fh);
}

static void show_options()
{
	printf("usage: imshift image_file [dr=] [dc=] [fill=] \n");
	printf("               [sinc] [lagrange] [help] \n");
}
