package shape;

import java.awt.*;
import java.awt.geom.*;
import java.io.*;
import java.util.*;
import shape.*;
import textBox.*;
import geomExtension.*;

public class SerializableElement implements Serializable {
	//public int type=0;
//Container data
	public int containerType;
	public int containerIndex = -1;
	public String parent = "";
	public String shapeId = "";
	public Date date = null;
	public String fileNameAndPage = "";
	public boolean connectorTargetPermission = true;
	public boolean connectorPermission = true;
	public HashMap<String, Object> property = new HashMap<String, Object>();
//data for shapeElement
	public String elementType = "";
	public SerializableCurve2D serializableCurve2D = new SerializableCurve2D();
//data for PaintStyle
	public Color fillColor = null;
	public Color lineColor = null;
	public float lineWidth = 0.5f;
	public String dashedStyle = "";
	public float[] dash = null;
	public int arrowStyle = 1;
	public int startArrowType = 0;
	public int endArrowType = 0;
// data for TextBox only
	public Rectangle2D textArea = null;
	public SerializableAttributedString attributedString=null;
	public Insets textBoxInsets = new Insets(0, 0, 0, 0);
	public int textAlign = 0;
	public int lineSpace = 0;
// data for ImageElement only
	public byte[] imageByteData;
// data for GroupElement only
	public ArrayList childrenList = new ArrayList();
	
	int debug=0;

	public SerializableElement() {
	}
	
	public SerializableElement[] getGroupedElements() {
		//System.out.println("** SerializableElement getGroupedElements() this="+this.shapeId);
		Vector vector = new Vector();
		vector.add(this);
	  //-------------------------------//
		this.getGroupedElementsE(vector);
	  //-------------------------------//
		int length = 0;
		if (vector.size() > 0) {
			length = vector.size();
		}
		SerializableElement[] elements = new SerializableElement[length];
		for (int i = 0; i < length; i++) {
			elements[i] = (SerializableElement) vector.get(i);
		}
		return elements;
	}
	
	private void getGroupedElementsE(Vector vector) {
		int size = 0;
		if (this.childrenList != null) {
			size = this.childrenList.size();
		}
		//if(debug>=0) System.out.println("- SerializableElement getGroupedElements size="+size);
		for (int i = 0; i < size; i++) {
			String ObjectName = this.childrenList.get(i).getClass().getSimpleName();
			//System.out.println("  -- ObjectName="+ObjectName);
			String shapeId="";
			if(ObjectName.equals("String")){
				shapeId=(String)this.childrenList.get(i);
			}else{
				SerializableElement element = (SerializableElement) childrenList.get(i);
				shapeId=element.shapeId;
				int type = element.containerType;
				vector.add(element);
				if(debug>0) System.out.println("** SerializableElement getGroupedElements(Vector vector)"
						+ " add element["+i+"]="+shapeId);
				if (type == ShapeContainer.GROUP) {
					element.getGroupedElementsE(vector);
				}
			}
			if(debug>0) System.out.println(" - child="+shapeId);
		}
		return;
	}
	
	public int getGroupTreeDepth(String shapeId) {
		Vector vector = new Vector();
		Integer treeDepth = new Integer(0);
		Integer findDepth = new Integer(-1);
		vector.add(shapeId);
		vector.add(treeDepth);
		vector.add(findDepth);
		if (this.shapeId.equals(shapeId)) {
			findDepth = new Integer(0);
			return 0;
		}
		//ShapeContainer[] children = new ShapeContainer[0];
		if (this.containerType == ShapeContainer.GROUP) {
			this.getGroupTreeDepthE(vector);
		}
		findDepth = (Integer) vector.get(2);

		return findDepth.intValue();
	}
	
	private void getGroupTreeDepthE(Vector vector) {
		Integer treeDepth = (Integer) vector.get(1);
		++treeDepth;
		if (debug > 0) {
			System.out.println("   ** getGroupTreeDepth treeDepth=" + treeDepth
					+ ", search shapeId=" + (String) vector.get(0)
					+ ", target shapeId=" + this.shapeId);
		}
		vector.set(1, treeDepth);
		ArrayList childrenList = this.childrenList;
		int size = 0;
		if (this.childrenList != null) {
			size = this.childrenList.size();
		}
		for (int i = 0; i < size; i++) {
			SerializableElement childElement = (SerializableElement)this.childrenList.get(i);
			int type = childElement.containerType;
			String shapeId = (String) vector.get(0);
			if (childElement.shapeId.equals(shapeId)) {
				vector.set(2, (new Integer(treeDepth)));
				return;
			}
			if (type == ShapeContainer.GROUP) {
				childElement.getGroupTreeDepthE(vector);
			}
		}
		treeDepth = (Integer) vector.get(1);
		--treeDepth;
		vector.set(1, treeDepth);
		return;
	}
	
	public Object clone() {
		//System.out.println("\n**Serializable.clone start");
		SerializableElement newElement=new SerializableElement();
		newElement.containerType=this.containerType;
		newElement.containerIndex=this.containerIndex;
		newElement.parent=new String(this.parent);
		newElement.shapeId=new String(this.shapeId);
		newElement.date=(Date)this.date.clone();
		newElement.fileNameAndPage=new String(this.fileNameAndPage);
		newElement.connectorTargetPermission=this.connectorTargetPermission;
		newElement.connectorPermission=this.connectorPermission;
		newElement.property= this.cloneHashMap(this.property);
		//System.out.println("**Serializable.clone first setting end");
		newElement.elementType=new String(this.elementType);
		newElement.serializableCurve2D=(SerializableCurve2D)this.serializableCurve2D.clone();
		//System.out.println("\n**Serializable.clone second setting end");
		if(this.fillColor != null) {
			newElement.fillColor = new Color(this.fillColor.getRed(), this.fillColor.getGreen(),
					this.fillColor.getBlue(), this.fillColor.getAlpha());
		}
		if (this.lineColor != null) {
			newElement.lineColor = new Color(this.lineColor.getRed(), this.lineColor.getGreen(),
					this.lineColor.getBlue(), this.lineColor.getAlpha());
		}
		//System.out.println("**Serializable.clone third setting end");
		newElement.lineWidth=this.lineWidth;
		newElement.dashedStyle="";
		if(this.dashedStyle!=null||this.dashedStyle.equals("")){
			newElement.dashedStyle=new String(this.dashedStyle);
		}
		newElement.dash=this.dash;
		newElement.arrowStyle=this.arrowStyle;
		newElement.startArrowType=this.startArrowType;
		newElement.endArrowType=this.endArrowType;
		newElement.textArea=null;
		if(this.textArea!=null){
			newElement.textArea=new Rectangle2D.Double(this.textArea.getX(), this.textArea.getY(),
				this.textArea.getWidth(), this.textArea.getHeight());
		}
		newElement.attributedString=null;
		if(this.attributedString!=null){
			newElement.attributedString=(SerializableAttributedString)this.attributedString.clone();
		}
		newElement.textBoxInsets=(Insets)this.textBoxInsets.clone();
		newElement.textAlign=this.textAlign;
		newElement.lineSpace=this.lineSpace;
		newElement.imageByteData=this.imageByteData;
		newElement.childrenList=new ArrayList();
		//System.out.println("**Serializable.clone forth setting end");
		if (this.childrenList.size() > 0) {
			String className = this.childrenList.get(0).getClass().getSimpleName();
			if (className.equals("String")) {
				for (int i = 0; i < this.childrenList.size(); i++) {
					String newShapeId = new String((String) this.childrenList.get(i));
					newElement.childrenList.add(newShapeId);
				}
			} else {
				for (int i = 0; i < this.childrenList.size(); i++) {
					SerializableElement sElement = (SerializableElement) this.childrenList.get(i);
					SerializableElement cloneElement = (SerializableElement) sElement.clone();
					newElement.childrenList.add(cloneElement);
				}
			}
		}
		return newElement;
	}
	
	private HashMap<String, Object> cloneHashMap(HashMap<String, Object> hashMap) {
		HashMap<String, Object> newHashMap = new HashMap<String, Object>();
		Set<String> set = hashMap.keySet();
		Vector<String> list = new Vector(set);
		for (int i = 0; i < list.size(); i++) {
			String key = list.get(i);
			if (key.equals("")) {
				continue;
			}
			String object = hashMap.get(key).toString();
			String name = object.getClass().getSimpleName();
			if (debug > 0) {
				System.out.println("cloneHashMap key=" + key + ", object=" + object + ", object name=" + name);
			}
			if (name.equals("String")) {
				String str = (String) object;
				String newStr = new String(str);
				newHashMap.put(key, newStr);
			}
		}
		return newHashMap;
	}
	
	public String toString() {
		String str = "";
		str += this.toStringE(0, "");
		if (this.containerType == ShapeContainer.GROUP) {
			SerializableElement[] childElements = this.getGroupedElements();

			for (int i = 1; i < childElements.length; i++) {
				//childElements[0] is the parent
				int treeDepth = this.getGroupTreeDepth(childElements[i].shapeId);
				String space = "";
				for (int j = 0; j < treeDepth; j++) {
					space += "    ";
				}
				//if(debug>0) System.out.println(space+"* toVeryShortString treeDepth="+treeDepth);
				if(debug>0) System.out.println(" debug childElements[" + i + "].toVeryShortString: "
						+ childElements[i].shapeId + ", treeDepth=" + treeDepth);
				str += "\n" + childElements[i].toStringE(treeDepth, "- child: ");

			}
		}
		return str;
	}
	
	private String toStringE(int indent, String header) {
	/*
	public int containerType;
	public int containerIndex = -1;
	public String parent = "";
	public String shapeId = "";
	public Date date = null;
	public String fileNameAndPage = "";
	public boolean connectorTargetPermission = true;
	public boolean connectorPermission = true;
	*/
		String str = "";
		String space = "";
		for (int j = 0; j < indent; j++) {
			space += "    ";
		}
		if (containerType == ShapeContainer.SHAPE) {
			String parentSTr = "null";
			if (!parent.equals("")) {
				parentSTr = parent;
			}
			str += space + header + shapeId + ", containertype=SHAPE" + ", index=" + containerIndex + ", parent=" + parentSTr;
			//str += space + header +"date="+date.toString()+", fileNameAndPage="+fileNameAndPage;
			String attrStr = null;
			if (this.attributedString != null) {
				attrStr = this.attributedString.getString();
			}
			if (attrStr==null||attrStr.equals("")) {
				str += ", Text=null";
			} else if (textArea != null) {
				str += "\n" + space + "    Text=" + attributedString.getString();
			}
			
			String fillColorStr = "null";
			String lineColorStr = "null";
			if (fillColor != null) {
				fillColorStr = fillColor.toString();
			}
			if (lineColor != null) {
				lineColorStr = lineColor.toString();
			}

			str += "\n"+space+ "   fillColor=" + fillColorStr + ", lineColor=" + lineColorStr;
			str += "\n"+space+ "   lineWidth=" + lineWidth + ", dashedStyle=" + dashedStyle;
			String dashStr = "null";
			if (dash != null && dash.length > 0) {
				dashStr = "";
				for (int i = 0; i < dash.length; i++) {
					dashStr = String.valueOf(dash[i]) + ", ";
				}
			}
			str += ", dash=" + dashStr;
			str += ", startArrowType=" + startArrowType + ", endArrowType=" + endArrowType;
		}

		if (containerType == ShapeContainer.GROUP) {
			int size = this.childrenList.size();
			String parentSTr = "null";
			if (!parent.equals("")) {
				parentSTr = parent;
			}
			String ObjectName = this.childrenList.get(0).getClass().getSimpleName();
			str += space + header +shapeId + ", containertype=Group" + ", index=" + containerIndex + ", parent=" + parentSTr
					+ ", children type=" + ObjectName;
			for (int i = 0; i < size; i++) {
				if (ObjectName.startsWith("String")) {
					String childId = (String) this.childrenList.get(i);
					//str += ", " + childId;
					str += "\n" + space + "    - children[" + i + "]=" + childId;
				}
			}
		}
		return str;
	}

	public String toShortString() {
		String str = "";
		str += this.toShortStringE(0, "");
		if (this.containerType == ShapeContainer.GROUP) {
			SerializableElement[] childElements = this.getGroupedElements();

			for (int i = 1; i < childElements.length; i++) {
				//childElements[0] is the parent
				int treeDepth = this.getGroupTreeDepth(childElements[i].shapeId);
				String space = "";
				for (int j = 0; j < treeDepth; j++) {
					space += "    ";
				}
				if(debug>0) System.out.println(" debug childElements[" + i + "].toVeryShortString: "
						+ childElements[i].shapeId + ", treeDepth=" + treeDepth);
				str += "\n" + childElements[i].toShortStringE(treeDepth, "- child: ");

			}
		}
		return str;
	}
	
	private String toShortStringE(int indent, String header) {
		String str = "";
		String space = "";
		for (int j = 0; j < indent; j++) {
			space += "    ";
		}
		if (containerType == ShapeContainer.SHAPE) {
			str += space + header + shapeId + ", containertype=SHAPE" + ", index=" + containerIndex;
			//String parentSTr = "null";
			if (!parent.equals("")) {
				//parentSTr = parent;
				str += ", parent=" + parent;
			}
			
			String attrStr=null;
			if(this.attributedString!=null){
				attrStr = this.attributedString.getString();
			}
			//System.out.println("** toShortString attrStr="+attrStr);
			if (attrStr == null||attrStr.equals("")) {
				str += ", Text=null";
			} else if (textArea != null) {
				str += "\n" + space + "    Text=" + attributedString.getString();
			}
			
		}
		if (containerType == ShapeContainer.GROUP) {
			int size = this.childrenList.size();
			str += space + header + shapeId + ", containertype=Group" + ", index=" + containerIndex;
			//String parentSTr = "null";
			if (!parent.equals("")) {
				//parentSTr = parent;
				str+=", parent=" + parent;
			}
			String ObjectName = this.childrenList.get(0).getClass().getSimpleName();
			str += ", children type=" + ObjectName;
			for (int i = 0; i < size; i++) {
				if (ObjectName.startsWith("String")) {
					String childId = (String) this.childrenList.get(i);
					//str += ", " + childId;
					str += "\n" + space + "    - children[" + i + "]=" + childId;
				}
			}	
		}
		return str;
	}

	public String toVeryShortString() {
		String str = "";
		str += this.toVeryShortStringE(0, "");
		if (this.containerType == ShapeContainer.GROUP) {
			SerializableElement[] childElements = this.getGroupedElements();
			
			for (int i = 1; i < childElements.length; i++) {
			//childElements[0] is the parent
				int treeDepth = this.getGroupTreeDepth(childElements[i].shapeId);
				String space="";
				for (int j = 0; j < treeDepth; j++) {
					space += "    ";
				}
				if(debug>0)System.out.println(" debug childElements["+i+ "].toVeryShortString: "
						+ childElements[i].shapeId+", treeDepth="+treeDepth);
				str += "\n" + childElements[i].toVeryShortStringE(treeDepth, "- child: ");
				
			}
		}
		return str;
	}

	private String toVeryShortStringE(int indent, String header) {
		String str = "";
		String space = "";
		for (int j = 0; j < indent; j++) {
			space += "    ";
		}
		if (containerType == ShapeContainer.SHAPE) {
			str += space + header + shapeId;
			String parentSTr = "null";
			if (!parent.equals("")) {
				str+=", parent=" + parent;
			}
			
		}
		if (containerType == ShapeContainer.GROUP) {
			int size = 0;
			if (this.childrenList != null) {
				size = this.childrenList.size();
			}
			str += space + header + shapeId;
			//String parentSTr = "null";
			if (!parent.equals("")) {
				str+=", parent=" + parent;
			}
			String ObjectName = this.childrenList.get(0).getClass().getSimpleName();
			str +=", children type="+ObjectName;
			for (int i = 0; i < size; i++) {
				if (ObjectName.startsWith("String")) {
					String childId = (String) this.childrenList.get(i);
					//str += ", " + childId;
					str += "\n" + space + "    - children[" + i + "]=" + childId;
				}
			}
		}
		return str;
	}
}
