import ij.*;
import ij.gui.*;
import java.awt.*;
import ij.plugin.filter.PlugInFilter;
import ij.process.*;

/** offsetXYstack
  *
  * Translates the origin of an XY stack by integer xOff,yOff, 
  * over writing the original stack.  Extensions might translate 
  * all or selected frames in a stack, might take integer x-y 
  * inputs instead of r and phi since the translation is rounded 
  * off to integer values so far, and might learn to interpolate
  * between pixels as well. /pf2007july13
  *
  * This example adapted by pf from tutorial plugins named
  * ColorInverter & StackAverage found with the tutorial at
  * http://www.fh-hagenberg.at/mtd/depot/imaging/imagej
  * 
  */
public class offsetXYmask_ implements PlugInFilter {

	protected ImagePlus imp; // defines an instance variable, protected means what?
	static double xoff = 0;
	static double yoff = 0;
	static double wrad = 8;	

	public int setup(String arg, ImagePlus imp) {
		if (arg.equals("about"))
			{showAbout(); return DONE;}
		this.imp=imp;
                return DOES_32+STACK_REQUIRED; // checks for stacked floats as input
	}

	public void run(ImageProcessor ip) { //line30

		if (!IJ.showMessageWithCancel("Warning","Are you ready to over write the selected image?")) return;
		if (!showDialog()) return;
		
		ImageStack stack=imp.getStack(); // sets up the image stack for access
		// get width, height and the region of interest
		int w = ip.getWidth();     
		int h = ip.getHeight();    
		// int dimension = ip.getWidth()*ip.getHeight();	
		float[] pixels01 = (float[]) stack.getPixels(1); // gets the first slice pixel array
		float[] pixels02 = (float[]) stack.getPixels(2); // gets the 2nd slice pixel array //line40
	
		// create a scratch image with the same size
		ImagePlus oImage = NewImage.createFloatImage("Offset XY Stack",w,h,2,NewImage.FILL_BLACK);
		ImageStack oStack = oImage.getStack();
		// oStack.ConvertToGray32();
		float[] pixels01o = (float[]) oStack.getPixels(1);
		float[] pixels02o = (float[]) oStack.getPixels(2); 

		// now calculate offsets from dialog inputs
        		// int xoff = (int) (roff*Math.cos(aoff*Math.PI/180.)); 
        		// int yoff = (int) (roff*Math.sin(aoff*Math.PI/180.));

		// 
		int xnew, ynew; 
		int oldj, newj;
        		for (int y = 0; y < h; y++){
			if(y+yoff>h-1){
				ynew=(int) (y+yoff-h);
			} else if (y+yoff<0) {
				ynew=(int) (y+yoff+h);
			} else {
				ynew=(int) (y+yoff);
			} 
            		for (int x = 0; x < w; x++){
				if(x+xoff>w-1){
					xnew=(int) (x+xoff-w);
				} else if (x+xoff<0) {
					xnew = (int) (x+xoff+w);
				} else {
					xnew=(int) (x+xoff);
				}
				oldj=x+w*y; newj=xnew+w*ynew;
				pixels01o[newj]=pixels01[oldj];
				pixels02o[newj]=pixels02[oldj];
			}
		}
		int j;
		double distance;
        		for (int y = 0; y < h; y++){
            		for (int x = 0; x < w; x++){
				j=x+w*y;
              	 	 	distance = Math.abs(x-w/2)*Math.abs(x-w/2)+Math.abs(y-h/2)*Math.abs(y-h/2);
                			distance = Math.sqrt(distance);
                			if(distance<wrad){
					pixels01[j]=pixels01o[j];
					pixels02[j]=pixels02o[j];
				} else {
					pixels01[j]=0;
					pixels02[j]=0;
				}
			}
		}

		// hsbstack.setSliceLabel("cColor (hue)",1);
		// hsbstack.setSliceLabel("cColor (saturation)",2);
		// hsbstack.setSliceLabel("cColor (brightness)",3);
		imp.show();
		imp.updateAndDraw();
	}

	void showAbout() {
		// called by setup if the string argument is "about"
		IJ.showMessage("offsetXYstack",
			"offsets pixels in an XY stack by integer amounts"
		);
	}

	public boolean showDialog() {
		GenericDialog gd = new GenericDialog("Parameters");
		gd.addNumericField("horizontal offset frequency in fpixels:", xoff, 64);
		gd.addNumericField("vertical offset frequency in fpixels:", yoff, 64);
		gd.addNumericField("window radius in fpixels:", wrad, 8);
		gd.showDialog();
		if (gd.wasCanceled()) return false;
		xoff = gd.getNextNumber();
		yoff = gd.getNextNumber();
		wrad = gd.getNextNumber();
        		return true;
	}

}