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


// Super-class for edge detection functions
// Contains Euclidean algebra modules and sorts
public abstract class edgeFilter extends EffectFilter
{
	// Global data
	int masksize;
	int maskIndex[];
	double array[];
	
	// Calculates the sum of the angles between each pixel in the mask
	// and all other pixels in the mask
	public void calc_angle()
	{
		int curr,curg,curb,r,g,b;
		double mag_sq,cur_mag_sq;
		double theta,costheta_sq,product,inner;

		// Runs through mask
		for (int i=0;i<masksize*masksize;i++)
		{
			curr = (pixels[maskIndex[i]] >> 16)&0xff;
			curg = (pixels[maskIndex[i]] >> 8)&0xff;
			curb = (pixels[maskIndex[i]])&0xff;
			
			// Magnitude squared
			cur_mag_sq = (curr*curr)+(curg*curg)+(curb*curb);
      		costheta_sq=0;
			product = 0;

			// Runs through mask again
			for (int j=0;j<masksize*masksize;j++)
			{
				if (i != j)
				{
					r = (pixels[maskIndex[j]] >> 16)&0xff;
					g = (pixels[maskIndex[j]] >> 8)&0xff;
					b = (pixels[maskIndex[j]])&0xff;
					
					// Dot product of two vectors
					inner = (curr*r)+(curg*g)+(curb*b);
					mag_sq = (r*r)+(g*g)+(b*b);

					// Calc the angle between vectors
					if ((cur_mag_sq) == 0 || mag_sq == 0)
					{
						// special case
						theta = 10;
					}
					else
					{
						costheta_sq = (inner*inner)/(cur_mag_sq*mag_sq);
						theta = Math.acos(costheta_sq);
					}
					
					// Sum of all angles
					product += theta;
				}
			}

			array[i] = product;
		}
	}

	// Calculates the sum of the euclidean distances between each pixel in 
	// the mask and all other pixels in the mask	
	public void calc_dist()
	{
		int curr,curg,curb,r,g,b;
		double dis;

		// Runs through mask
		for (int i=0;i<masksize*masksize;i++)
		{
			curr = (pixels[maskIndex[i]] >> 16)&0xff;
			curg = (pixels[maskIndex[i]] >> 8)&0xff;
			curb = (pixels[maskIndex[i]])&0xff;
			dis = 0;

			// Runs through mask again
			for (int j=0;j<masksize*masksize;j++)
			{
				if (i != j)
				{
					r = (pixels[maskIndex[j]] >> 16)&0xff;
					g = (pixels[maskIndex[j]] >> 8)&0xff;
					b = (pixels[maskIndex[j]])&0xff;
					
					// Sum of distances between pixels
					dis += Math.sqrt((curr-r)*(curr-r)+(curg-g)*(curg-g)+(curb-b)*(curb-b));
				}
			}
			array[i] = dis;
		}
	}
	
	// Calculates the sum of the absolute distances between each pixel in 
	// the mask and all other pixels in the mask	
	public void calc_dist2()
	{
		int curr,curg,curb,r,g,b;
		double dis;

		// Runs through mask
		for (int i=0;i<masksize*masksize;i++)
		{
			curr = (pixels[maskIndex[i]] >> 16)&0xff;
			curg = (pixels[maskIndex[i]] >> 8)&0xff;
			curb = (pixels[maskIndex[i]])&0xff;
			dis = 0;

			// Runs through mask again
			for (int j=0;j<masksize*masksize;j++)
			{
				if (i != j)
				{
					r = (pixels[maskIndex[j]] >> 16)&0xff;
					g = (pixels[maskIndex[j]] >> 8)&0xff;
					b = (pixels[maskIndex[j]])&0xff;
					
					// Sum of distances between pixels
					dis += Math.abs(curr-r)+Math.abs(curg-g)+Math.abs(curb-b);
				}
			}
			array[i] = dis;
		}
	}

	// Returns euclidean distance between two vectors
	public double vect_dist(int v1, int v2)
	{
		int r1, r2, g1, g2, b1, b2;
		double result;
		
		// RGB components of first vector
		r1 = (v1>>16)&0xff;
		g1 = (v1>>8)&0xff;
		b1 = (v1)&0xff;
		
		// RGB components of second vector
		r2 = (v2>>16)&0xff;
		g2 = (v2>>8)&0xff;
		b2 = (v2)&0xff;
		
		// Distance calculation
		result = Math.sqrt((r2-r1)*(r2-r1)+(g2-g1)*(g2-g1)+(b2-b1)*(b2-b1));
		
		return result;
	}
	
	// Returns absolute distance between two vectors
	public double vect_dist2(int v1, int v2)
	{
		int r1, r2, g1, g2, b1, b2;
		double result;
		
		// RGB components of first vector
		r1 = (v1>>16)&0xff;
		g1 = (v1>>8)&0xff;
		b1 = (v1)&0xff;
		
		// RGB components of second vector
		r2 = (v2>>16)&0xff;
		g2 = (v2>>8)&0xff;
		b2 = (v2)&0xff;
		
		// Distance calculation
		result = Math.abs(r2-r1)+Math.abs(g2-g1)+Math.abs(b2-b1);
		
		return result;
	}	

	// Bubble sort of the mask array in ascending order
	public void b_sort(int size)
	{
		int temp;
		double temp2;
		
		// Standard bubble sort
		for (int x=0; x < (size)-1; x++)
		{
			for (int y=0; y < (size)-x-1; y++)
			{
				if (array[y] > array[y+1])
				{
					temp2 = array[y];
					temp = maskIndex[y];
					array[y] = array[y+1];
					maskIndex[y] = maskIndex[y+1];
					array[y+1] = temp2;
					maskIndex[y+1] = temp;
				}
			}
		}
	}
}
