package com.one.vector;

import com.one.ImageProcessor;
import javax.microedition.lcdui.*;
import javax.microedition.io.Connector;
import java.io.*;

public class Bitmap extends VectorElement
{
	public static final int MODE_NORMAL = 0;
	public static final int MODE_REPEAT_X = 1;
	public static final int MODE_REPEAT_Y = 2;
	public static final int MODE_REPEAT_BOTH = 3;
	public static final int MODE_SCALE = 4;
	
	public static final int DEFTEX_WIDTH = 16;
	public static final int DEFTEX_HEIGHT = 16;
	
	public static final int FP_SHIFT = 16;
	
	protected Image image, scaled;
	protected String filename;
	protected double[] data = new double[4];
	protected int[] sdata = new int[4];
	protected int width, height;
	protected int mode;
	protected int repx, repy;
	protected boolean usescaled;
	
	protected int[] clip = new int[4];
	
	public Bitmap()
	{
		data[0] = 0;
		data[1] = 0;
		data[2] = 0;
		data[3] = 0;
	}
	
	public void read(DataInputStream dis) throws IOException
	{
		name = dis.readUTF();
		color = dis.readInt();
		parseFlag(dis.readUnsignedByte());
		
		data[0] = dis.readFloat();
		data[1] = dis.readFloat();
		data[2] = dis.readFloat();
		data[3] = dis.readFloat();
		
		mode = dis.readUnsignedByte();
		
		System.gc();
		
		try
		{
			if(dis.readBoolean())
			{
				int blen = dis.readInt();
				byte[] b = new byte[blen];
				
				dis.readFully(b);
				image = Image.createImage(b, 0, blen);
				
				width = image.getWidth();
				height = image.getHeight();
			}
			else
			{
				width = dis.readInt();
				height = dis.readInt();
				
				int[] rgbdata = new int[width * height];
				
				for(int i = 0; i < rgbdata.length; i++)
				{
					rgbdata[i] = dis.readInt();
				}
				
				image = Image.createRGBImage(rgbdata, width, height, true);
			}
		}
		catch(OutOfMemoryError oome)
		{
			width = DEFTEX_WIDTH;
			height = DEFTEX_HEIGHT;
			
			int[] rgbdata = new int[width * height];
			
			for(int i = 0; i < rgbdata.length; i++)
			{
				rgbdata[i] = color;
			}
			
			image = Image.createRGBImage(rgbdata, width, height, true);
		}
		
		readTransformList(dis);
	}
	
	public void write(DataOutputStream dos) throws IOException
	{
		dos.writeUTF(name);
		dos.writeInt(color);
		dos.writeByte(getFlag());
		
		dos.writeFloat((float)data[0]);
		dos.writeFloat((float)data[1]);
		dos.writeFloat((float)data[2]);
		dos.writeFloat((float)data[3]);
		
		dos.writeByte(mode);
		
		try
		{
			InputStream is = Connector.openInputStream("file:///" + filename);
			
			byte[] b = new byte[4096];
			
			dos.writeBoolean(true);
			dos.writeInt(is.available());
			
			while(is.available() > 0)
			{
				dos.write(b, 0, is.read(b));
			}
			
			is.close();
		}
		catch(Exception e)
		{
			System.gc();
			
			try
			{
				int[] rgbdata = new int[width * height];
				image.getRGB(rgbdata, 0, width, 0, 0, width, height);
				
				dos.writeBoolean(false);
				dos.writeInt(width);
				dos.writeInt(height);
				
				for(int i = 0; i < rgbdata.length; i++)
				{
					dos.writeInt(rgbdata[i]);
				}
			}
			catch(OutOfMemoryError oome)
			{
				dos.writeBoolean(false);
				dos.writeInt(DEFTEX_WIDTH);
				dos.writeInt(DEFTEX_HEIGHT);
				
				for(int i = 0, len = DEFTEX_WIDTH * DEFTEX_HEIGHT; i < len; i++)
				{
					dos.writeInt(color);
				}
			}
		}
		
		writeTransformList(dos);
	}
	
	public void create()
	{
		if(image == null)
		{
			try
			{
				InputStream is = Connector.openInputStream("file:///" + filename);
				image = Image.createImage(is);
				is.close();
				
				width = image.getWidth();
				height = image.getHeight();
			}
			catch(Exception e)
			{
				width = DEFTEX_WIDTH;
				height = DEFTEX_HEIGHT;
				
				int[] rgbdata = new int[width * height];
				
				for(int i = 0; i < rgbdata.length; i++)
				{
					rgbdata[i] = color;
				}
				
				image = Image.createRGBImage(rgbdata, width, height, true);
			}
		}
	}
	
	public void rescale()
	{
		sdata[0] = getScaled(data[0], 0);
		sdata[1] = getScaled(data[1], 1);
		sdata[2] = getScaled(data[2], 2);
		sdata[3] = getScaled(data[3], 3);
		
		if(mode == MODE_REPEAT_X)
		{
			repx = (sdata[2] + width - 1) / width;
			repy = 1;
			
			usescaled = false;
			scaled = null;
		}
		else if(mode == MODE_REPEAT_Y)
		{
			repx = 1;
			repy = (sdata[3] + height - 1) / height;
			
			usescaled = false;
			scaled = null;
		}
		else if(mode == MODE_REPEAT_BOTH)
		{
			repx = (sdata[2] + width - 1) / width;
			repy = (sdata[3] + height - 1) / height;
			
			usescaled = false;
			scaled = null;
		}
		else if(mode == MODE_SCALE)
		{
			if(image != null && (sdata[2] != width || sdata[3] != height))
			{
				if(scaled == null || scaled.getWidth() != sdata[2] || scaled.getHeight() != sdata[3])
				{
					scaled = ImageProcessor.scaleImage(image, sdata[2], sdata[3], sdata[2] > width || sdata[3] > height, false);
				}
				
				usescaled = true;
			}
			else
			{
				repx = 1;
				repy = 1;
				
				usescaled = false;
			}
		}
		else
		{
			repx = 1;
			repy = 1;
			
			usescaled = false;
			scaled = null;
		}
	}
	
	public void paint(Graphics g)
	{
		if(hidden)
		{
			return;
		}
		
		if(group.image.usecolor)
		{
			if(usescaled && scaled != null)
			{
				g.drawImage(scaled, sdata[0], sdata[1], Graphics.LEFT | Graphics.TOP);
			}
			else if(image != null)
			{
				clip[0] = g.getClipX();
				clip[1] = g.getClipY();
				clip[2] = g.getClipWidth();
				clip[3] = g.getClipHeight();
				
				g.clipRect(sdata[0], sdata[1], sdata[2], sdata[3]);
				
				for(int i = 0; i < repx; i++)
				{
					for(int j = 0; j < repy; j++)
					{
						g.drawImage(image, sdata[0] + i * width, sdata[1] + j * height, Graphics.LEFT | Graphics.TOP);
					}
				}
				
				g.setClip(clip[0], clip[1], clip[2], clip[3]);
			}
			else
			{
				g.setColor(color);
				g.fillRect(sdata[0], sdata[1], sdata[2], sdata[3]);
			}
		}
	}
	
	public void update(boolean flag, boolean changed)
	{
		Transform transform;
		int param;
		
		for(int i = 0; i < transcount; i++)
		{
			transform = (Transform)transforms.elementAt(i);
			transform.setFrame(group.image.frame);
			
			if(transform.isApplied())
			{
				param = transform.getParam();
				
				switch(param)
				{
					case SHOW:
						setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()));
						break;
					
					case COLOR:
						color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition());
						break;
					
					case X:
						data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition());
						changed = true;
						break;
					
					case Y:
						data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition());
						changed = true;
						break;
					
					case WIDTH:
						data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition());
						changed = true;
						break;
					
					case HEIGHT:
						data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition());
						changed = true;
						break;
				}
			}
		}
		
		if(flag && changed)
		{
			rescale();
		}
	}
	
	public Object getValue(int param, int subparam)
	{
		switch(param)
		{
			case X:
				return new Double(data[0]);
			
			case Y:
				return new Double(data[1]);
			
			case WIDTH:
				return new Double(data[2]);
			
			case HEIGHT:
				return new Double(data[3]);
			
			case MODE:
				return new Integer(mode);
			
			case FILE:
				return filename;
		}
		
		return null;
	}
	
	public void setValue(Object value, int param, int subparam)
	{
		switch(param)
		{
			case X:
				data[0] = ((Double)value).doubleValue();
				break;
			
			case Y:
				data[1] = ((Double)value).doubleValue();
				break;
			
			case WIDTH:
				data[2] = ((Double)value).doubleValue();
				break;
			
			case HEIGHT:
				data[3] = ((Double)value).doubleValue();
				break;
			
			case MODE:
				mode = ((Integer)value).intValue();
				break;
			
			case FILE:
				filename = (String)value;
				image = null;
				scaled = null;
				break;
		}
	}
}