package com.one;

import com.vmx.ProgressCallback;
import java.io.IOException;
import java.io.OutputStream;
import javax.microedition.lcdui.Image;

public class GIFFile
{
	protected OutputStream out;
	protected ColorQuantizer gct;
	
	public GIFFile(OutputStream out, int[] palette, int backcolor, int width, int height, int loopcount) throws IOException
	{
		this.out = out;

		if(palette != null)
		{
			gct = new ColorQuantizer(palette, true, false, null);
			palette = gct.getPalette();
		}
		
		out.write(0x47);
		out.write(0x49);
		out.write(0x46);
		out.write(0x38);
		out.write(0x39);
		out.write(0x61);
		
		writeWord(out, width);
		writeWord(out, height);
		
		if(palette != null)
		{
			out.write(0xF7);
			out.write(gct.getColorIndex(backcolor));
			out.write(0);
			
			for(int index = 0; index < 256; index++)
			{
				out.write(palette[index] >> 16);
				out.write(palette[index] >> 8);
				out.write(palette[index]);
			}
		}
		else
		{
			out.write(0x70);
			out.write(0);
			out.write(0);
		}
		
		out.write(0x21);
		out.write(0xFF);
		out.write(0x0B);
		out.write(0x4E);
		out.write(0x45);
		out.write(0x54);
		out.write(0x53);
		out.write(0x43);
		out.write(0x41);
		out.write(0x50);
		out.write(0x45);
		out.write(0x32);
		out.write(0x2E);
		out.write(0x30);
		out.write(0x03);
		out.write(0x01);
		writeWord(out, loopcount);
		out.write(0);
	}
	
	public void writeImage(Image image, int delay, boolean quantize, boolean dither, ProgressCallback callback) throws IOException
	{
		int width = image.getWidth();
		int height = image.getHeight();
		
		if(callback != null)
		{
			callback.setProgress(0);
			callback.setMax(height);
		}
		
		out.write(0x21);
		out.write(0xF9);
		out.write(4);
		out.write(0);
		writeWord(out, delay);
		out.write(0);
		out.write(0);
		
		out.write(0x2C);
		writeWord(out, 0);
		writeWord(out, 0);
		writeWord(out, width);
		writeWord(out, height);
		
		ColorQuantizer quantizer = null;
		int[] palette;
				
		if(quantize || gct == null)
		{
			out.write(0x87);
			
			quantizer = new ColorQuantizer(image, 256, ColorQuantizer.MAX_NODES * 2, true, false, callback);
			palette = quantizer.getPalette();
			
			int index = 0;
			
			for(; index < palette.length; index++)
			{
				out.write(palette[index] >> 16);
				out.write(palette[index] >> 8);
				out.write(palette[index]);
			}
			
			for(; index < 256; index++)
			{
				out.write(0);
				out.write(0);
				out.write(0);
			}
		}
		else
		{
			out.write(0x07);

			quantizer = gct;
			palette = quantizer.getPalette();
		}
		
		if(dither)
		{
			image = ImageProcessor.quantizeImage(image, quantizer, true, callback);
		}
		
		out.write(8);
		LZWCompressor lzw = new LZWCompressor(out, 8);

		int[] pixel = new int[width];
		int x, y;
		
		for(y = 0; y < height; y++)
		{
			image.getRGB(pixel, 0, width, 0, y, width, 1);

			for(x = 0; x < width; x++)
			{
				lzw.write((byte)quantizer.getColorIndex(pixel[x]));
			}
			
			if(callback != null)
			{
				callback.progress(1);
			}
		}
		
		lzw.finish();
		
		out.write(0);
	}
	
	public void finish() throws IOException
	{
		out.write(0x3B);
	}
	
	protected static void writeWord(OutputStream os, int v) throws IOException
	{
		os.write(v);
		os.write(v >> 8);
	}

//	public static int[] SQUARES = new int[256];
//
//	static
//	{
//		for(int i = 0; i < 256; i++)
//		{
//			SQUARES[i] = i * i;
//		}
//	}
	
//	public static int colorDistance(int color1, int color2)
//	{
//		/*
//		int dr = ((color1 >> 16) & 0xFF) - ((color2 >> 16) & 0xFF);
//		int dg = ((color1 >> 8) & 0xFF) - ((color2 >> 8) & 0xFF);
//		int db = (color1 & 0xFF) - (color2 & 0xFF);
//
//		return dr * dr + dg * dg + db * db;
//		*/
//
//		return SQUARES[Math.abs(((color1 >> 16) & 0xFF) - ((color2 >> 16) & 0xFF))] +
//			   SQUARES[Math.abs(((color1 >> 8) & 0xFF) - ((color2 >> 8) & 0xFF))] +
//			   SQUARES[Math.abs((color1 & 0xFF) - (color2 & 0xFF))];
//	}

//	public static int nearestColor(int color, int[] palette)
//	{
//		int mindistance = colorDistance(0, -1) + 1;
//		int distance, index = -1;
//
//		for(int i = 0; i < palette.length; i++)
//		{
//			distance = colorDistance(palette[i], color);
//
//			if(distance == 0)
//			{
//				return i;
//			}
//			else if(distance < mindistance)
//			{
//				index = i;
//				mindistance = distance;
//			}
//		}
//
//		return index;
//	}
}