package com.one.vector;

import javax.microedition.lcdui.Graphics;
import java.util.Vector;
import java.util.Enumeration;
import java.io.*;

public abstract class VectorElement
{
	public static final int NORMAL = 0;
	public static final int DOTTED = 1;
	public static final int FILL = 2;
	public static final int HIDDEN = 4;
	
	public static final int SHOW = 0,
							COLOR = 1,
							X = 2,
							Y = 3,
							WIDTH = 4,
							HEIGHT = 5,
							ARC_WIDTH = 6,
							ARC_HEIGHT = 7,
							START = 8,
							LENGTH = 9,
							ROTATION = 10,
							ANGLE = 11,
							THICKNESS = 12,
							OFFSET_X = 13,
							OFFSET_Y = 14,
							SCALE_X = 15,
							SCALE_Y = 16,
							VAL_A = 17,
							VAL_B = 18,
							DIV_A = 19,
							DIV_B = 20,
							DIV_C = 21,
							DIV_D = 22,
							INT_A = 23,
							INT_B = 24,
							FUNCTION = 25,
							POLY_COUNT = 26,
							COUNT = 27,
							QUALITY = 28,
							MODE = 29,
							FILE = 30;
	
	public static final int CLIP = 0,
							LINE = 1,
							ARC = 2,
							RECT = 3,
							ROUND_RECT = 4,
							POINT = 5,
							TRIANGLE = 6,
							POLYLINE = 7,
							POLYGON = 8,
							PARAMETRIC_CURVE = 9,
							BEZIER_CURVE = 10,
							THICK_LINE = 11,
							THICK_RECT = 12,
							THICK_TRIANGLE = 13,
							THICK_POLYLINE = 14,
							THICK_POLYGON = 15,
							THICK_PARAMETRIC_CURVE = 16,
							THICK_BEZIER_CURVE = 17,
							BITMAP = 18,
							TEXTURE_ARC = 19,
							TEXTURE_ROUND_RECT = 20,
							TEXTURE_TRIANGLE = 21,
							TEXTURE_POLYGON = 22,
							GRADIENT_RECT = 23,
							GRADIENT_CIRCLE = 24,
							LINE_ARRAY = 25,
							ARC_ARRAY = 26,
							RECT_ARRAY = 27,
							ROUND_RECT_ARRAY = 28,
							POINT_ARRAY = 29,
							TRIANGLE_ARRAY = 30,
							POLYGON_ARRAY = 31;
	
	public static final String[] OBJECT_NAMES =
	{
		"Group",
		"Comment",
		"Clip", "Line", "Arc", "Rect", "RoundRect", "Point", "Tringle", "Polyline", "Polygon", "ParametricCurve", "BezierCurve",
		"ThickLine", "ThickRect", "ThickTriangle", "ThickPolyline", "ThickPolygon", "ThickParametricCurve", "ThickBezierCurve",
		"Bitmap", "TextureArc", "TextureRoundRect", "TextureTriangle", "TexturePolygon",
		"GradientRect", "GradientCircle",
		"LineArray", "ArcArray", "RectArray", "RoundRectArray", "PointArray", "TriangleArray", "PolygonArray",
		"Visibility", "Color", "X", "Y", "Width", "Height",
		"ArcWidth", "ArcHeight", "Start", "Length", "Rotation", "Angle", "Thickness",
		"HorizontalOffset", "VerticalOffset", "HorizontalScale", "VerticalScale",
		"ValA", "ValB", "DivA", "DivB", "DivC", "DivD", "IntA", "IntB",
		"ColorReplace", "AreaFill", "LineFill", "ChannelMatrix", "PixelMatrix", "BitwiseFunction", "GradientReplace"
	};
	
	public static final int OFFSET_ELEMENTS = 2;
	public static final int OFFSET_TRANSFORMS = 34;
	public static final int OFFSET_EFFECTS = 59;
	
	public static VectorImage DEFAULT_IMAGE;
	public static Group DEFAULT_GROUP;
	
	static
	{
		DEFAULT_IMAGE = new VectorImage();
		DEFAULT_GROUP = new Group();
		DEFAULT_IMAGE.addGroup(DEFAULT_GROUP);
	}
	
	public static String defaultName()
	{
		return Long.toString(System.currentTimeMillis(), Character.MAX_RADIX).toUpperCase();
	}
	
	public static String getElementPrefix(int type)
	{
		return OBJECT_NAMES[type + OFFSET_ELEMENTS];
	}
	
	public static String getTransformPrefix(int param, int subparam)
	{
		if(subparam >= 0)
		{
			return Integer.toString(subparam) + OBJECT_NAMES[param + OFFSET_TRANSFORMS];
		}
		else
		{
			return OBJECT_NAMES[param + OFFSET_TRANSFORMS];
		}
	}
	
	public static String getEffectPrefix(int type)
	{
		return OBJECT_NAMES[type + OFFSET_EFFECTS];
	}
	
	protected String name;
	protected Group group;
	protected Vector transforms;
	protected int transcount;
	protected int color;
	protected boolean fill;
	protected int stroke;
	protected boolean hidden;
	
	public VectorElement()
	{
		name = defaultName();
		
		group = DEFAULT_GROUP;
		
		transforms = new Vector();
		transcount = 0;
		
		color = -1;
		
		parseFlag(NORMAL);
	}
	
	public abstract void read(DataInputStream dis) throws IOException;
	public abstract void write(DataOutputStream dos) throws IOException;
	
	public void writeSVG(PrintStream ps)
	{
	}
	
	protected void writeSVGTail(PrintStream ps, boolean usedotted, boolean usefill)
	{
		if(usedotted && !fill && stroke == Graphics.DOTTED)
		{
			ps.print(" stroke-dasharray=\"2\"");
		}
		
		ps.print(" stroke=\"" + formatColor(color) + "\"");
		
		if(usefill)
		{
			if(fill)
			{
				ps.print(" fill=\"" + formatColor(color) + "\"");
			}
			else
			{
				ps.print(" fill=\"none\"");
			}
		}
		
		if(hidden)
		{
			ps.print(" visibility=\"hidden\"");
		}
	}
	
	protected void readTransformList(DataInputStream dis) throws IOException
	{
		transcount = dis.readUnsignedShort();
		
		transforms.removeAllElements();
		transforms.ensureCapacity(transcount);
		
		for(int i = 0; i < transcount; i++)
		{
			transforms.addElement(new Transform(dis));
		}
	}
	
	protected void writeTransformList(DataOutputStream dos) throws IOException
	{
		dos.writeShort(transcount);
		
		for(int i = 0; i < transcount; i++)
		{
			((Transform)transforms.elementAt(i)).write(dos);
		}
	}
	
	public abstract void paint(Graphics g);
	
	public void setGroup(Group grp)
	{
		if(grp != null)
		{
			group = grp;
		}
		else
		{
			group = DEFAULT_GROUP;
		}
	}
	
	public Group getGroup()
	{
		return group;
	}
	
	protected void parseFlag(int flag)
	{
		fill = (flag & FILL) != 0;
		hidden = (flag & HIDDEN) != 0;
		stroke = ((flag & DOTTED) != 0) ? Graphics.DOTTED : Graphics.SOLID;
	}
	
	protected int getFlag()
	{
		int flag = NORMAL;
		
		if(fill)
		{
			flag |= FILL;
		}
		
		if(hidden)
		{
			flag |= HIDDEN;
		}
		
		if(stroke == Graphics.DOTTED)
		{
			flag |= DOTTED;
		}
		
		return flag;
	}
	
	public void setHidden(boolean hidden)
	{
		this.hidden = hidden;
	}
	
	protected void setHidden(double v)
	{
		hidden = v < 0.5f;
	}
	
	public boolean isHidden()
	{
		return hidden;
	}
	
	public void setFill(boolean fill)
	{
		this.fill = fill;
	}
	
	public boolean isFill()
	{
		return fill;
	}
	
	public void setDotted(boolean dotted)
	{
		stroke = dotted ? Graphics.DOTTED : Graphics.SOLID;
	}
	
	public boolean isDotted()
	{
		return stroke == Graphics.DOTTED;
	}
	
	public void setColor(int color)
	{
		this.color = color;
	}
	
	public int getColor()
	{
		return color;
	}
	
	public int getScaled(double v, int mode)
	{
		switch(mode)
		{
			case 0:
				return (int)((v + group.param[0]) * group.param[2]);
			
			case 1:
				return (int)((v + group.param[1]) * group.param[3]);
			
			case 2:
				return (int)(v * group.param[2]);
			
			case 3:
				return (int)(v * group.param[3]);
			
			case 4:
				return (int)(v * group.param[6]);
		}
		
		return (int)v;
	}
	
	public double getInternal(int v, int mode)
	{
		switch(mode)
		{
			case 0:
				return (double)v / group.param[2] - group.param[0];
			
			case 1:
				return (double)v / group.param[3] - group.param[1];
			
			case 2:
				return (double)v / group.param[2];
			
			case 3:
				return (double)v / group.param[3];
			
			case 4:
				return (double)v / group.param[6];
		}
		
		return (double)v;
	}
	
	public void addTransform(Transform t, boolean flag)
	{
		if(flag)
		{
			t.setName(group.image.nextTransformName(t.getParam(), t.getSubParam()));
		}
		else
		{
			t.setName(group.image.currentTransformName(t.getParam(), t.getSubParam()));
		}
		
		transforms.addElement(t);
		transcount = transforms.size();
	}
	
	public void create()
	{
	}
	
	public abstract void rescale();
	public abstract void update(boolean crallow, boolean crforce);
	
	public void setName(String nm)
	{
		if(nm != null)
		{
			name = nm;
		}
		else
		{
			name = defaultName();
		}
	}
	
	public String getName()
	{
		return name;
	}
	
	public Enumeration listTransforms()
	{
		return transforms.elements();
	}
	
	public Transform getTransform(String name)
	{
		Transform transform;
		
		for(int i = 0; i < transcount; i++)
		{
			transform = (Transform)transforms.elementAt(i);
			
			if(transform.getName().equals(name))
			{
				return transform;
			}
		}
		
		return null;
	}
	
	public void deleteTransform(Transform transform)
	{
		transforms.removeElement(transform);
		transcount = transforms.size();
	}
	
	public void arrangeTransforms(int index, int newindex)
	{
		if(index < 0)
		{
			index = 0;
		}
		else if(index >= transforms.size())
		{
			index = transforms.size() - 1;
		}
		
		if(newindex < 0)
		{
			newindex = 0;
		}
		else if(newindex >= transforms.size())
		{
			newindex = transforms.size() - 1;
		}
		
		Object temp = transforms.elementAt(newindex);
		transforms.setElementAt(transforms.elementAt(index), newindex);
		transforms.setElementAt(temp, index);
	}
	
	public abstract Object getValue(int param, int subparam);
	public abstract void setValue(Object value, int param, int subparam);
	
	public static String formatColor(int color)
	{
		String res = Integer.toHexString(color & 0xFFFFFF).toUpperCase();
		
		while(res.length() < 6)
		{
			res = "0" + res;
		}
		
		return "#" + res;
	}
	
	public static VectorElement getInstance(int type)
	{
		switch(type)
		{
			case CLIP:
				return new Clip();
			
			case LINE:
				return new Line();
			
			case ARC:
				return new Arc();
			
			case RECT:
				return new Rect();
			
			case ROUND_RECT:
				return new RoundRect();
			
			case POINT:
				return new Point();
			
			case TRIANGLE:
				return new Triangle();
			
			case POLYLINE:
				return new Polyline();
			
			case POLYGON:
				return new Polygon();
			
			case PARAMETRIC_CURVE:
				return new ParametricCurve();
			
			case BEZIER_CURVE:
				return new BezierCurve();
			
			case THICK_LINE:
				return new ThickLine();
			
			case THICK_RECT:
				return new ThickRect();
			
			case THICK_TRIANGLE:
				return new ThickTriangle();
			
			case THICK_POLYLINE:
				return new ThickPolyline();
			
			case THICK_POLYGON:
				return new ThickPolygon();
			
			case THICK_PARAMETRIC_CURVE:
				return new ThickParametricCurve();
			
			case THICK_BEZIER_CURVE:
				return new ThickBezierCurve();
			
			case BITMAP:
				return new Bitmap();
			
			case TEXTURE_ARC:
				return new TextureArc();
			
			case TEXTURE_ROUND_RECT:
				return new TextureRoundRect();
			
			case TEXTURE_TRIANGLE:
				return new TextureTriangle();
			
			case TEXTURE_POLYGON:
				return new TexturePolygon();
			
			case GRADIENT_RECT:
				return new GradientRect();
			
			case GRADIENT_CIRCLE:
				return new GradientCircle();
			
			case LINE_ARRAY:
				return new LineArray();
			
			case ARC_ARRAY:
				return new ArcArray();
			
			case RECT_ARRAY:
				return new RectArray();
			
			case ROUND_RECT_ARRAY:
				return new RoundRectArray();
			
			case POINT_ARRAY:
				return new PointArray();
			
			case TRIANGLE_ARRAY:
				return new TriangleArray();
			
			case POLYGON_ARRAY:
				return new PolygonArray();
			
			default:
				//throw new IllegalArgumentException("Unknown element type: " + Integer.toString(type));
				throw new IllegalArgumentException();
		}
	}
	
	public static int elementType(VectorElement ve)
	{
		if(ve instanceof Clip)
		{
			return CLIP;
		}
		else if(ve instanceof Line)
		{
			return LINE;
		}
		else if(ve instanceof Arc)
		{
			return ARC;
		}
		else if(ve instanceof Rect)
		{
			return RECT;
		}
		else if(ve instanceof RoundRect)
		{
			return ROUND_RECT;
		}
		else if(ve instanceof Point)
		{
			return POINT;
		}
		else if(ve instanceof Triangle)
		{
			return TRIANGLE;
		}
		else if(ve instanceof Polyline)
		{
			return POLYLINE;
		}
		else if(ve instanceof Polygon)
		{
			return POLYGON;
		}
		else if(ve instanceof ParametricCurve)
		{
			return PARAMETRIC_CURVE;
		}
		else if(ve instanceof BezierCurve)
		{
			return BEZIER_CURVE;
		}
		else if(ve instanceof ThickLine)
		{
			return THICK_LINE;
		}
		else if(ve instanceof ThickRect)
		{
			return THICK_RECT;
		}
		else if(ve instanceof ThickTriangle)
		{
			return THICK_TRIANGLE;
		}
		else if(ve instanceof ThickPolyline)
		{
			return THICK_POLYLINE;
		}
		else if(ve instanceof ThickPolygon)
		{
			return THICK_POLYGON;
		}
		else if(ve instanceof ThickParametricCurve)
		{
			return THICK_PARAMETRIC_CURVE;
		}
		else if(ve instanceof ThickBezierCurve)
		{
			return THICK_BEZIER_CURVE;
		}
		else if(ve instanceof Bitmap)
		{
			return BITMAP;
		}
		else if(ve instanceof TextureArc)
		{
			return TEXTURE_ARC;
		}
		else if(ve instanceof TextureRoundRect)
		{
			return TEXTURE_ROUND_RECT;
		}
		else if(ve instanceof TextureTriangle)
		{
			return TEXTURE_TRIANGLE;
		}
		else if(ve instanceof TexturePolygon)
		{
			return TEXTURE_POLYGON;
		}
		else if(ve instanceof GradientRect)
		{
			return GRADIENT_RECT;
		}
		else if(ve instanceof GradientCircle)
		{
			return GRADIENT_CIRCLE;
		}
		else if(ve instanceof LineArray)
		{
			return LINE_ARRAY;
		}
		else if(ve instanceof ArcArray)
		{
			return ARC_ARRAY;
		}
		else if(ve instanceof RectArray)
		{
			return RECT_ARRAY;
		}
		else if(ve instanceof RoundRectArray)
		{
			return ROUND_RECT_ARRAY;
		}
		else if(ve instanceof PointArray)
		{
			return POINT_ARRAY;
		}
		else if(ve instanceof TriangleArray)
		{
			return TRIANGLE_ARRAY;
		}
		else if(ve instanceof PolygonArray)
		{
			return POLYGON_ARRAY;
		}
		else
		{
			//throw new IllegalArgumentException("Unknown element: " + ve.getClass().getName());
			throw new IllegalArgumentException();
		}
	}
	
	public String toString()
	{
		return getElementPrefix(elementType(this)) + ":" + name + "@" + group.getName();
	}
}