package com.one.vector;

import javax.microedition.lcdui.Image;
import java.io.*;

public class PixelMatrix extends Effect
{
	protected int[][] factors;
	protected int[] divisors = new int[4];
	protected int[] offsets = new int[4];
	protected int size;
	
	protected int[] values = new int[4];
	protected int delta;
	
	public PixelMatrix()
	{
		setDelta(1);
	}
	
	public void read(DataInputStream dis) throws IOException
	{
		name = dis.readUTF();
		hidden = dis.readBoolean();
		
		setDelta(dis.readUnsignedByte());
		
		int length = size * size;
		
		for(int i = 0; i < length; i++)
		{
			factors[0][i] = dis.readInt();
			factors[1][i] = dis.readInt();
			factors[2][i] = dis.readInt();
			factors[3][i] = dis.readInt();
		}
		
		divisors[0] = dis.readInt();
		divisors[1] = dis.readInt();
		divisors[2] = dis.readInt();
		divisors[3] = dis.readInt();
		
		offsets[0] = dis.readInt();
		offsets[1] = dis.readInt();
		offsets[2] = dis.readInt();
		offsets[3] = dis.readInt();
	}
	
	public void write(DataOutputStream dos) throws IOException
	{
		dos.writeUTF(name);
		dos.writeBoolean(hidden);
		
		dos.writeByte(getDelta());
		
		int length = size * size;
		
		for(int i = 0; i < length; i++)
		{
			dos.writeInt(factors[0][i]);
			dos.writeInt(factors[1][i]);
			dos.writeInt(factors[2][i]);
			dos.writeInt(factors[3][i]);
		}
		
		dos.writeInt(divisors[0]);
		dos.writeInt(divisors[1]);
		dos.writeInt(divisors[2]);
		dos.writeInt(divisors[3]);
		
		dos.writeInt(offsets[0]);
		dos.writeInt(offsets[1]);
		dos.writeInt(offsets[2]);
		dos.writeInt(offsets[3]);
	}
	
	public void apply(int[] rgb, int[] temp, int width, int height)
	{
		if(hidden)
		{
			return;
		}
		
		System.arraycopy(rgb, 0, temp, 0, rgb.length);
		
		int mcx = width - delta;
		int mcy = height - delta;
		
		int cx, cy, x, y, mx, my, pi, fi;
		int a, r, g, b;
		
		for(cx = delta; cx < mcx; cx++)
		{
			for(cy = delta; cy < mcy; cy++)
			{
				values[0] = 0;
				values[1] = 0;
				values[2] = 0;
				values[3] = 0;
				
				mx = cx + delta;
				my = cy + delta;
				
				for(x = cx - delta; x <= mx; x++)
				{
					for(y = cy - delta; y <= my; y++)
					{
						pi = x + y * width;
						fi = (x - cx + delta) + (y - cy + delta) * size;
						
						values[0] += ((temp[pi] >> 24) & 0xFF) * factors[0][fi];
						values[1] += ((temp[pi] >> 16) & 0xFF) * factors[1][fi];
						values[2] += ((temp[pi] >> 8) & 0xFF) * factors[2][fi];
						values[3] += (temp[pi] & 0xFF) * factors[3][fi];
					}
				}
				
				a = values[0] / divisors[0] + offsets[0];
				r = values[1] / divisors[1] + offsets[1];
				g = values[2] / divisors[2] + offsets[2];
				b = values[3] / divisors[3] + offsets[3];
				
				if(a < 0)
				{
					a = 0;
				}
				else if(a > 255)
				{
					a = 255;
				}
				
				if(r < 0)
				{
					r = 0;
				}
				else if(r > 255)
				{
					r = 255;
				}
				
				if(g < 0)
				{
					g = 0;
				}
				else if(g > 255)
				{
					g = 255;
				}
				
				if(b < 0)
				{
					b = 0;
				}
				else if(b > 255)
				{
					b = 255;
				}
				
				rgb[cx + cy * width] = (a << 24) | (r << 16) | (g << 8) | b;
			}
		}
	}
	
	public void setSize(int sz)
	{
		setDelta((sz - 1) / 2);
	}
	
	public int getSize()
	{
		return size;
	}
	
	public void setDelta(int sz)
	{
		if(sz > 1)
		{
			delta = sz;
		}
		else
		{
			delta = 1;
		}
		
		size = delta * 2 + 1;
		
		int length = size * size;
		factors = new int[4][length];
		
		int index = length / 2;
		factors[0][index] = 1;
		factors[1][index] = 1;
		factors[2][index] = 1;
		factors[3][index] = 1;
		
		divisors[0] = 1;
		divisors[1] = 1;
		divisors[2] = 1;
		divisors[3] = 1;
		
		offsets[0] = 0;
		offsets[1] = 0;
		offsets[2] = 0;
		offsets[3] = 0;
	}
	
	public int getDelta()
	{
		return delta;
	}
	
	public void setFactor(int channel, int index, int value)
	{
		factors[channel][index] = value;
	}
	
	public void setDivisor(int channel, int value)
	{
		divisors[channel] = value;
	}
	
	public void setOffset(int channel, int value)
	{
		offsets[channel] = value;
	}
	
	public int getFactor(int channel, int index)
	{
		return factors[channel][index];
	}
	
	public int getDivisor(int channel)
	{
		return divisors[channel];
	}
	
	public int getOffset(int channel)
	{
		return offsets[channel];
	}
}