import java.awt.*;
import java.awt.image.*;
import java.applet.*;
import java.net.*;
import java.io.*;
import java.lang.Math;
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.JApplet;
import javax.imageio.*;
import javax.swing.event.*;

public class symmetry {

		int[] input;
		double[] direction;
		int[] output;
		double[] magnitude;
		double[] logOfInput;

		double[][] distanceLookup;
		double[][] phaseLookup;

		double sigma;
		double mu;

		double progress;
		int width;
		int height;
		double distanceWeightingMultiplier;

		public void symmetry() {
			progress=0;
		}

		public void init(int[] inputIn, double[] directionIn, double sigmaIn, double muIn, int widthIn, int heightIn){
			width=widthIn;
			height=heightIn;
			sigma=sigmaIn;
			mu=muIn;

			input = new int[width*height];
			direction = new double[width*height];
			output = new int[width*height];
			magnitude = new double[width*height];
			logOfInput = new double[width*height];

			distanceLookup = new double[width][height];
			phaseLookup = new double[181][181];

			input=inputIn;
			direction=directionIn;

			distanceWeightingMultiplier=(double)1/(double)Math.sqrt(2*Math.PI*sigma);
			createTables();
		}
		public void createTables(){
			//get log magnitude of edges
			for (int Xi=1;Xi<width-1;Xi++) {
				for (int Xj=1;Xj<height-1;Xj++) {
					int M = (input[Xj*width+Xi]&0xff);
					logOfInput[Xj*width+Xi]=Math.log((double)(1+M));
				}
			}
			//setup distance lookup table
			for (int Xi=1;Xi<width;Xi++) {
				for (int Xj=1;Xj<height;Xj++) {
						distanceLookup[Xj][Xi]=distanceWeightingMultiplier*(double)Math.pow(Math.E,(-(Math.sqrt((Xi)*(Xi)+(Xj)*(Xj))/(2*sigma))));
				}
			}
			//setup angle lookup table
			for (int Xi=1;Xi<181;Xi++) {
				for (int Xj=1;Xj<181;Xj++) {
					phaseLookup[Xj][Xi]=(1-Math.cos(Xi-Xj));
				}
			}
		}

		public int midpoint(int x1, int x2){
			return (int)((x1+x2)/2);
		}

		public int[] process() {
				progress=0;
	
			double max=0;
			double dist, phase;
			double value;
		
			for (int Xi=1;Xi<width-1;Xi++) {
			progress++;
				for (int Xj=1;Xj<height-1;Xj++) {
				
					if(logOfInput[Xj*width+Xi]==0)
						continue;
		
					for (int Yi=1;Yi<width-1;Yi++) {
						for (int Yj=1;Yj<height-1;Yj++) {

							if(logOfInput[Yj*width+Yi]==0 || (Xi==Yi && Xj==Yj))
								continue;

							if(logOfInput[Xj*width+Xi]<1) continue;
							if(logOfInput[Yj*width+Yi]<1) continue;
							dist=distanceLookup[Math.abs(Xi-Yi)][Math.abs(Xj-Yj)];
							if(dist<0.01) continue;
							phase=(float)(1-Math.cos(direction[Xj*width+Xi]+direction[Yj*width+Yi]-2*Math.atan(Yi-Yj/Xi-Xj)))*(1-(float)Math.cos(direction[Xj*width+Xi]-direction[Yj*width+Yi]));
							if(phase<0.1) continue;
							value=dist*phase*logOfInput[Xj*width+Xi]*logOfInput[Yj*width+Yi];
							magnitude[midpoint(Xj,Yj)*width+midpoint(Xi,Yi)] += (value);
						}
					}

				}
			}
			for (int Xi=1;Xi<width-1;Xi++) {
				for (int Xj=1;Xj<height-1;Xj++) {
					if(max<magnitude[Xj*width+Xi])
						max=magnitude[Xj*width+Xi];
				}
			}		

			// normalising ratio
			double ratio = (double)255 / (double)max;
				System.out.println(ratio+"=ratio");

		
			// normalise values
			for (int x=1;x<width-1;x++) {
				for (int y=1;y<height-1;y++) {
					magnitude[y*width+x] = (int)(magnitude[y*width+x] * ratio);
					int M = (int)magnitude[y*width+x];
					output[y*width+x] = 0xff000000 | (M << 16 | M << 8 | M);
				}
			}
		
			return output;

		}

		public int getProgress() {
			return (int)progress;
		}

	}

