import java.awt.*;
import java.awt.image.*;
import java.io.*;

// Edge detection with Difference Vector Median operators
public class median_edge extends edgeFilter
{
	float min_edge;
	int indent;
	
	// Creates object and initializes data
	public median_edge(float min, int size)
	{
		min_edge = min;
		masksize = size;
		indent = (int) Math.floor(masksize/2);
	}
	
	// Runs algorithm
	public void performEffect()
	{
		float max_intensity = 0;
		double xRGB,yRGB,xtestRGB,ytestRGB,d0,d45,d90,d135;
		int pointOffset,x1=0,x2=0,y1=0,y2=0,posX=0,posY=0;
		int newPixels[] = new int[width*height];
		double edge[] = new double[width*height];
		
		// Moves through the input array pixel by pixel
		for (int y=indent;y<height-indent;y++)
		{
			for (int x=indent;x<width-indent;x++)
			{
				// Location of centre of mask
				pointOffset = y*width+x;
				
			// 0 degrees and 180 degrees subwindows
			
				// Set inital values very high (so they will be replaced)
				xRGB = 50000;
				yRGB = 50000;

				// Find median RGB vector for each region
				for (int i=0;i<=indent;i++)
				{
					x1 = (y-i)*width+x;
					y1 = (y+i)*width+x;
					xtestRGB = 0;
					ytestRGB = 0;
					for (int j=0;j<=indent;j++)
					{
						x2 = (y-j)*width+x;
						y2 = (y+j)*width+x;
						xtestRGB += vect_dist(pixels[x1],pixels[x2]);
						ytestRGB += vect_dist(pixels[y1],pixels[y2]);
					}
					// Compare results to find lowest distance totals
					if (xtestRGB <= xRGB)
					{
						xRGB = xtestRGB;
						posX = x1;
					}
					if (ytestRGB <= yRGB)
					{
						yRGB = ytestRGB;
						posY = y1;
					}
				}
				
				// Calculate the distance between the two median vectors
				d0 = vect_dist(pixels[posX],pixels[posY]);
				
			// 90 degrees and 270 degrees subwindows
			
				// Set inital values very high (so they will be replaced)
				xRGB = 50000;
				yRGB = 50000;

				// Find median RGB vector for each region
				for (int i=0;i<=indent;i++)
				{
					x1 = y*width+x-i;
					y1 = y*width+x+i;
					xtestRGB = 0;
					ytestRGB = 0;
					for (int j=0;j<=indent;j++)
					{
						x2 = y*width+x-j;
						y2 = y*width+x+j;
						xtestRGB += vect_dist(pixels[x1],pixels[x2]);
						ytestRGB += vect_dist(pixels[y1],pixels[y2]);
					}
					// Compare results to find lowest distance totals
					if (xtestRGB <= xRGB)
					{
						xRGB = xtestRGB;
						posX = x1;
					}
					if (ytestRGB <= yRGB)
					{
						yRGB = ytestRGB;
						posY = y1;
					}
				}
				
				// Calculate the distance between the two median vectors
				d90 = vect_dist(pixels[posX],pixels[posY]);
				
			// 45 degrees and 225 degrees subwindows

				// Set inital values very high (so they will be replaced)
				xRGB = 50000;
				yRGB = 50000;

				// Find median RGB vector for each region
				for (int i=0;i<=indent;i++)
				{
					for (int k=0;k<=indent;k++)
					{
						x1 = (y-i)*width+x+k;
						y1 = (y+i)*width+x-k;
						xtestRGB = 0;
						ytestRGB = 0;
						for (int j=0;j<=indent;j++)
						{
							for (int l=0;l<=indent;l++)
							{
								if ((i==0 && j==0) || (i!=0 && j!=0))
								{
									x2 = (y-j)*width+x+l;
									y2 = (y+j)*width+x-l;
									xtestRGB += vect_dist(pixels[x1],pixels[x2]);
									ytestRGB += vect_dist(pixels[y1],pixels[y2]);
								}
							}
						}
						// Compare results to find lowest distance totals
						if (xtestRGB <= xRGB)
						{
							xRGB = xtestRGB;
							posX = x1;
						}
						if (ytestRGB <= yRGB)
						{
							yRGB = ytestRGB;
							posY = y1;
						}
					}
				}
				
				// Calculate the distance between the two median vectors
				d45 = vect_dist(pixels[posX],pixels[posY]);
				
			// 135 degrees and 315 degrees subwindows

				// Set inital values very high (so they will be replaced)
				xRGB = 50000;
				yRGB = 50000;

				// Find median RGB vector for each region
				for (int i=0;i<=indent;i++)
				{
					for (int k=0;k<=indent;k++)
					{
						x1 = (y-i)*width+x-k;
						y1 = (y+i)*width+x+k;
						xtestRGB = 0;
						ytestRGB = 0;
						for (int j=0;j<=indent;j++)
						{
							for (int l=0;l<=indent;l++)
							{
								if ((i==0 && j==0) || (i!=0 && j!=0))
								{
									x2 = (y-j)*width+x-l;
									y2 = (y+j)*width+x+l;
									xtestRGB += vect_dist(pixels[x1],pixels[x2]);
									ytestRGB += vect_dist(pixels[y1],pixels[y2]);
								}
							}
						}
						// Compare results to find lowest distance totals
						if (xtestRGB <= xRGB)
						{
							xRGB = xtestRGB;
							posX = x1;
						}
						if (ytestRGB <= yRGB)
						{
							yRGB = ytestRGB;
							posY = y1;
						}
					}
				}
				
				// Calculate the distance between the two median vectors
				d135 = vect_dist(pixels[posX],pixels[posY]);
				
			// Finding the Edges
			
				edge[pointOffset] = d0;
				if (d45 > edge[pointOffset])
					edge[pointOffset] = d45;
				if (d90 > edge[pointOffset])
					edge[pointOffset] = d90;
				if (d135 > edge[pointOffset])
					edge[pointOffset] = d135;
				if (edge[pointOffset] > max_intensity)
					max_intensity = (float)edge[pointOffset];
			}
		}
		
		// Place the edges on an output array
		if (max_intensity > 0.0)
		{
			// Run through image pixel by pixel
			for (int y=0; y<height;y++)
			{
				for (int x=0; x<width; x++)
				{
					// Position of centre pixel
					pointOffset = y*width+x;
					
					edge[pointOffset] = edge[pointOffset]/max_intensity;
					
					// Set to grey if edge
					if (edge[pointOffset] >= min_edge)
					{
						newPixels[pointOffset] = 0xff000000 +
						(0x010101*(255-(int)(edge[pointOffset]*255)));
					}
					// Set to white
					else
					{
						newPixels[pointOffset] = 0x01010101*255;
					}
				}
			}
		}
		this.pixels = newPixels;
	}
}
