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

// Edge detection with Difference Vector Mean
public class mean_edge extends edgeFilter
{
	float min_edge;
	int indent;
	
	// Creates object and initializes data
	public mean_edge(float min, int mask)
	{
		min_edge = min;
		masksize = mask;
		indent = (int) Math.floor(masksize/2);
	}
		
	// Add the RGB components of a vector into their containers
	public void sumRGB(int d1[],int x)
	{
		d1[0] += (x>>16)&0xff;
		d1[1] += (x>>8)&0xff;
		d1[2] += (x)&0xff;
	}
	
	// Finds the mean RGB values for two sets of vectors
	public void meanRGB(int d1[],int d2[],int size)
	{
		for (int i=0;i<3;i++)
		{
			d1[i] = Math.round(d1[i]/size);
			d2[i] = Math.round(d2[i]/size);
		}
	}

	// Sets the RGB values for each container to zero
	public void resetRGB(int d1[],int d2[])
	{
		for (int i=0;i<3;i++)
		{
			d1[i] = 0;
			d2[i] = 0;
		}
	}
	
	// Runs algorithm
	public void performEffect()
	{
		int pos=0,xPixel,yPixel,pointOffset;
		float max_intensity = 0;
		double d0,d90,d45,d135;
		double edge[] = new double[width*height];
		int newPixels[] = new int[width*height];

		// Containers to store RGB values
		int xRGB[] = new int[3];
		int yRGB[] = new int[3];
		
		// 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;
				
				// Reset the RGB containers
				resetRGB(xRGB,yRGB);
			
			// 0 degrees and 180 degrees subwindows
			
				// Add all the RGB components in the subwindow
				for (int i=0;i<=indent;i++)
				{
					pos = (y-i)*width+x;
					sumRGB(xRGB,pixels[pos]);
					pos = (y+i)*width+x;
					sumRGB(yRGB,pixels[pos]);
				}
			
				// Find the mean RGB values for the subwindows
				meanRGB(xRGB,yRGB,indent+1);
				
				// Convert to vectors
				xPixel = (255<<24) | xRGB[0]<<16 | xRGB[1]<<8 | xRGB[2];
				yPixel = (255<<24) | yRGB[0]<<16 | yRGB[1]<<8 | yRGB[2];

				// Calculate the distance between the two mean vectors
				d0 = vect_dist(xPixel,yPixel);

			// 90 degrees and 270 degrees subwindows

				// Reset the RGB containers
				resetRGB(xRGB,yRGB);

				// Add all the RGB components in the subwindow			
				for (int i=0;i<=indent;i++)
				{
					pos = y*width+x-i;
					sumRGB(xRGB,pixels[pos]);
					pos = y*width+x+i;
					sumRGB(yRGB,pixels[pos]);
				}
			
				// Find the mean RGB values for the subwindows
				meanRGB(xRGB,yRGB,indent+1);

				// Convert to vectors
				xPixel = (255<<24) | xRGB[0]<<16 | xRGB[1]<<8 | xRGB[2];
				yPixel = (255<<24) | yRGB[0]<<16 | yRGB[1]<<8 | yRGB[2];
				
				// Calculate the distance between the two mean vectors
				d90 = vect_dist(xPixel,yPixel);

			// 45 degrees and 225 degrees subwindows

				// Reset the RGB containers
				resetRGB(xRGB,yRGB);
			
				// Add all the RGB components in the subwindow
				for (int i=0;i<=indent;i++)
				{
					for (int j=0;j<=indent;j++)
					{
						if ((i==0 && j==0) || (i!=0 && j!=0))
						{
							pos = (y-i)*width+x+j;
							sumRGB(xRGB,pixels[pos]);
							pos = (y+i)*width+x-j;
							sumRGB(yRGB,pixels[pos]);
						}
					}
				}
			
				// Find the mean RGB values for the subwindows
				meanRGB(xRGB,yRGB,(indent*indent)+1);

				// Convert to vectors
				xPixel = (255<<24) | xRGB[0]<<16 | xRGB[1]<<8 | xRGB[2];
				yPixel = (255<<24) | yRGB[0]<<16 | yRGB[1]<<8 | yRGB[2];
				
				// Calculate the distance between the two mean vectors
				d45 = vect_dist(xPixel,yPixel);

			// 135 degrees and 315 degrees subwindows

				// Reset the RGB containers
				resetRGB(xRGB,yRGB);
			
				// Add all the RGB components in the subwindow
				for (int i=0;i<=indent;i++)
				{
					for (int j=0;j<=indent;j++)
					{
						if ((i==0 && j==0) || (i!=0 && j!=0))
						{
							pos = (y-i)*width+x-j;
							sumRGB(xRGB,pixels[pos]);
							pos = (y+i)*width+x+j;
							sumRGB(yRGB,pixels[pos]);
						}
					}
				}
			
				// Find the mean RGB values for the subwindows
				meanRGB(xRGB,yRGB,(indent*indent)+1);

				// Convert to vectors
				xPixel = (255<<24) | xRGB[0]<<16 | xRGB[1]<<8 | xRGB[2];
				yPixel = (255<<24) | yRGB[0]<<16 | yRGB[1]<<8 | yRGB[2];
				
				// Calculate the distance between the two mean vectors
				d135 = vect_dist(xPixel,yPixel);
			
			// Finding the Edges
			
				edge[pointOffset] = d0;
				if (d90 > edge[pointOffset]) 
					edge[pointOffset] = d90;
				if (d45 > edge[pointOffset])
					edge[pointOffset] = d45;
				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;
	}
}
