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

// Directional Adaptive Non-Parametric Filter
public class AMNFD extends vectorFilter
{
	double wnorm[];
	int indent;

	// Create object and initialize data
	public AMNFD(int size)
	{
		masksize = size;
		maskIndex = new int[masksize*masksize];
		array = new double[masksize*masksize];
		wnorm = new double[masksize*masksize];
		indent = (int) Math.floor(masksize/2);
	}

	// Applies the weighting factor to the data array
	public void weight(int mask)
	{
		double w[] = new double[mask];
		double wtotal = 0;
		
		for(int i=0;i<mask;i++)
		{
			// w[i] is the weight for each vector
			w[i] = (0.000001)*array[i];
			wtotal += w[i];
		}

		for(int i=0;i<mask;i++)
		{
			// Normalize the weights
			if (wtotal == 0)
				wnorm[i] = 0;
			else
				wnorm[i] = w[i]/wtotal;
		}
	}

	// Runs the algorithm
	public void performEffect()
	{
		double sumr,sumg,sumb,cur_mag_sq,mag_sq;
		int counter, sumR, sumG, sumB, R, G, B;	
		int newPixels[] = new int [width*height];
		double theta, costheta_sq, product, inner;

		// 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
				int pointOffset = y*width+x;

				// Calculate Index for mask
				counter = 0;
				for (int i=-indent;i<=indent;i++)
				{
					for (int j=-indent;j<=indent;j++)
					{
						maskIndex[counter] = (y+i)*width+(x+j);
						counter++;
					}
				}

				// Code for kernal calculation given by DSP lab
				// Doesn't relate to book??
				for (int i=0;i<masksize*masksize;i++)
				{
					R = (pixels[maskIndex[i]] >> 16)&0xff;
					G = (pixels[maskIndex[i]] >> 8)&0xff;
					B = (pixels[maskIndex[i]])&0xff;
			
					// Magnitude squared
					cur_mag_sq = (R*R)+(G*G)+(B*B);

      				costheta_sq=0;
					product = 0;
					
					// Runs through mask again
					for (int j=0;j<masksize*masksize;j++)
					{
						if (i != j)
						{
							sumR = (pixels[maskIndex[j]] >> 16)&0xff;
							sumG = (pixels[maskIndex[j]] >> 8)&0xff;
							sumB = (pixels[maskIndex[j]])&0xff;
					
							// Dot product of two vectors
							inner = (R*sumR)+(G*sumG)+(B*sumB);
							
							// Magnitude squared
							mag_sq = (sumR*sumR)+(sumG*sumG)+(sumB*sumB);

							if ((cur_mag_sq) == 0 || mag_sq == 0)
							{
								// Special case
								costheta_sq = (inner*inner)/0.0001;
							}
							else
							{
								// Calc the angle between vectors
								costheta_sq = (inner*inner)/(cur_mag_sq*mag_sq);
							}
							
							theta = 1 + Math.sqrt(costheta_sq);
							product += Math.pow(theta,125);
						}
					}

					array[i] = product;
				}
				
				sumr = 0;
				sumg = 0;
				sumb = 0;
				
				// Apply weighting factor
				weight(masksize*masksize);

				// Calc output based on weighting and input pixels
				for (int i=0;i<masksize*masksize;i++)
				{
					sumr += wnorm[i]*((pixels[maskIndex[i]] >> 16)&0xff);
					sumg += wnorm[i]*((pixels[maskIndex[i]] >> 8)&0xff);
					sumb += wnorm[i]*((pixels[maskIndex[i]])&0xff);
				}

				sumR = (int)Math.round(sumr);
				sumG = (int)Math.round(sumg);
				sumB = (int)Math.round(sumb);

				if (sumR > 255) sumR = 255;
				if (sumR < 0) sumR = 0;
				if (sumG > 255) sumG = 255;
				if (sumG < 0) sumG = 0;
				if (sumB > 255) sumB = 255;
				if (sumB < 0) sumB = 0;

				newPixels[pointOffset] = (255<<24) | sumR<<16 | sumG <<8 | sumB;
			}
		}
		this.pixels = newPixels;
	}
}
