/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package shape;

import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import textBox.*;
import DrawTop.*;
import util.*;

public class ShapeContainer {

    private String shapeId = "";
    protected int containerIndex = -1;
    private ShapeContainer parent = null;
    private ShapeElement element = null;
    private TextBox textBox = null;
    private PaintStyle paintStyle = null;
    public HashMap<String, Object> property = new HashMap<String, Object>();
    private boolean selected = false;
    private boolean visible = true;
    private boolean highlighting=false;
    private boolean blinking=false;
    protected int mode = Command.NORMAL_MODE;
    private int changeCode = -1;
    public boolean connectorTargetPermission = true;
    public boolean connectorPermission = true;
    //private boolean autoAlignPermission = true;
    public static int SHAPE = 0;
    public static int GROUP = 1;
    public static int debug = 0;
    int idNumber = 0;

    public ShapeContainer() {
        this.paintStyle = new PaintStyle(this);
    }

    public int getContainerType() {
        int type = ShapeContainer.SHAPE;
        if (this.element == null) {
            return type;
        }
        if (this.element.getTypeE() == Command.GROUP) {
            type = ShapeContainer.GROUP;
        }
        return type;
    }

    public String getShapeId() {
        return this.shapeId;
    }

    public void setShapeId(String shapeId) {
        this.shapeId = shapeId;
    }
	
	public int getElementType(String shapeId) {
		int index = shapeId.indexOf("(");
		String type = shapeId.substring(0, index);
		int id = Command.getCommandId(type);
		if (id < 0) {
			System.err.println("***Error  getElementType shapeId" + shapeId + ", type=" + type);
		}
		return id;
	}
	
    
	public void setNewShapeId(ContainerManager manager, boolean withChildren){
        String shapeId = this.getShapeId();
        String id = "";
        int serialNumber=manager.getUniqueSerialNumber();
        id = this.configureShapeId(serialNumber);
        this.shapeId = id;
        if (debug >0) {
            System.out.println("** ShapeContainer.setShapeId newId="
                    + this.getShapeId()+", serialNumber="+serialNumber);
        }
        if (!withChildren) {
            return;
        }
        ShapeContainer[] children = this.getGroupedContainers();
        int size = 0;
        if (children != null) {
            size = children.length;
        }
        for (int i = 1; i < size; i++) {
            shapeId = children[i].getShapeId();
            serialNumber=manager.getUniqueSerialNumber();
            id = children[i].configureShapeId(serialNumber);
            children[i].setShapeId(id);
            if (debug >0) {
                System.out.println("** Children setShapeId newId="
                        + children[i].getShapeId()+", serialNumber="+serialNumber);
            }
        }
    }

    public String configureShapeId(int number) {
        String idStr = this.getElement().getShapeIdString();
        idStr += "(No-" + number + ")";
        return idStr;
    }

    public int getSerialNumber() {
        int num = -1;
        String shapeId = this.shapeId;
        if (shapeId == null || shapeId.equals("")) {
            return num;
        }
        int start = shapeId.lastIndexOf("-");
        int end = shapeId.lastIndexOf(")");
        String subStr = shapeId.substring(start + 1, end);
        subStr = subStr.replace(" ", "");
        num = Integer.parseInt(subStr);
        //System.out.println("getSerialNumber callFrom="+callFrom);
        return num;
    }

    private static int getSerialNumber(String shapeId, String callFrom) {
        int num = -1;
        if (shapeId == null || shapeId.equals("")) {
            return num;
        }
        int start = shapeId.lastIndexOf("-");
        int end = shapeId.lastIndexOf(")");
        String subStr = shapeId.substring(start + 1, end);
        //String subStr1 = subStr.replace(" ", "");
        num = Integer.parseInt(subStr);
        if(debug>0) System.out.println("getSerialNumber(String) callFrom="+callFrom);
        return num;
    }

    public int getContainerIndex() {
        return this.containerIndex;
    }

    public void setContainerIndex(int containerIndex) {
        this.containerIndex = containerIndex;
    }

    public ShapeContainer getParent() {
        return this.parent;
    }

    public void setParent(ShapeContainer parent) {
        this.parent = parent;
    }

    public ShapeContainer getTopParent() {
        ShapeContainer topParent = null;
        if (this.parent == null) {
            return this;
        } else {
            topParent = this.parent.getTopParent();
        }
        return topParent;
    }

    public ShapeElement getElement() {
        String id = this.shapeId;
        if (this.element == null && this.getContainerType() == SHAPE) {
            System.err.println("*** Error ShapeContainer.getElement: element=null"
                    + ", shapeId=" + id);
        }
        return this.element;
    }

    public void setElement(ShapeElement element) {
        this.element = element;
        element.shapeContainer=this;
        if (!this.getShapeId().equals("")) {
            int num = this.getSerialNumber();
            String shapeId = this.configureShapeId(num);
            this.setShapeId(shapeId);
        }
        //Move the next two line to CreateShapeLS  2013.01.29
        //String original_type=Command.getCommandString(Command.ORIGINAL_TYPE);
        //this.setProperty(original_type, element.getShapeIdString(),"ShapeContainer");
    }

    public int getMode() {
        return this.mode;
    }

    public void setMode(int mode) {
        if (debug > 0) {
            System.out.println(" ** ShapeContainer id=" + this.getShapeId()
                    + ", setMode=" + Command.getModeString(mode));
        }
        this.mode = mode;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
        if (!selected && this.isEditableTextBox()) {
            this.makeTextBoxEditable(false);
        }
        ShapeContainer[] containers = this.getGroupedContainers();
        for (int i = 1; i < containers.length; i++) {
            containers[i].selected = selected;
            if (!selected && containers[i].isEditableTextBox()) {
                containers[i].makeTextBoxEditable(false);
            }
        }
    }

    public boolean isSelected() {
        return this.selected;
    }

    public void setVisible(boolean visible) {
        this.visible = visible;
    }

    public boolean isVisible() {
        return this.visible;
    }
    public void setHighlighting(boolean highlighting) {
        if(!DrawParameters.ENABLE_HIGHLIGHTING) return;
        this.highlighting=highlighting;
        if(this.getContainerType()==ShapeContainer.GROUP){
            ShapeContainer[] containers = this.getGroupedContainers();
            for (int i = 0; i < containers.length; i++) {
                containers[i].highlighting=highlighting; 
            }
        }
        //if(!highlighting) System.out.println("ShapeContainer shapeId="+this.getShapeId()+", highlighting="+highlighting);
    }

    public boolean isHighlighting(){
        return this.highlighting;
    }
    
    public void setBlinking(boolean blinking) {
        if(!DrawParameters.ENABLE_BLINKING) return;
        this.blinking=blinking;
        if(this.getContainerType() == ShapeContainer.GROUP){
            ShapeContainer[] containers = this.getGroupedContainers();
            for (int i = 0; i < containers.length; i++) {
                containers[i].blinking=blinking; 
            }
        }
    }
    
    public boolean isBlinking(){
        return this.blinking;
    }
    
    public boolean isEditableTextBox() {
        if (!this.isTextBox()) {
            return false;
        }
        return this.getTextBox().isEditable();
    }
/*
    public boolean isEditableTextBox() {
        if (!this.isTextBox()) {
            return false;
        }
        return this.activated;
    }
*/
    public void makeTextBoxEditable(boolean activate) {
        if (!this.isTextBox()) {
            return;
        }
        if (activate) {
            if (!this.isSelected()) {
                this.setSelected(true);
            }
            this.getTextBox().activateMouseListener(true);
        }
        if (!activate) {
            this.getTextBox().activateMouseListener(false);
        }
    }

    public void makeTextBoxEditable(Point2D point, int ctrl) {
        if (!this.isTextBox()) {
            return;
        }
        if (!this.isSelected()) {
            this.setSelected(true);
        }
        TextBox textBox = this.getTextBox();
        textBox.activateMouseListener(true);
        double X = point.getX();
        double Y = point.getY();
        CaretPosition caretP = textBox.getCaretPositionAtMouse(X, Y, "makeTextBoxEditable");
        if (caretP != null) {
            textBox.setTextSelection(caretP, null, ctrl, "makeTextBoxEditable");
        }
    }

    public int getChangeCode() {
        return this.changeCode;
    }

    public void setChangeCode(int code) {
        this.changeCode = code;
        if (debug > 0) {
            System.out.println("ShapeContainer setChangeCode=" + UndoConstants.undoStr[code]
                    + ", " + this.getShapeId());
        }
    }

    public void setChangeCode(int code, String callFrom) {
        this.changeCode = code;
        if (debug > 0) {
            System.out.println("ShapeContainer setChangeCode=" + UndoConstants.undoStr[code]
                    + ", " + this.getShapeId() + ", callfrom=" + callFrom);
        }
    }

    public void resetChangeCode() {
        this.changeCode = -1;
    }
    
    public void setProperty(String key, Object object, String callFrom) {
        this.property.put(key, object);
        if(this.debug>0) {
            boolean print=false;
            String command="";
            command=Command.getCommandString(Command.ENABLE_RESIZING);
            if(key.equalsIgnoreCase(command)) print=true;
            command=Command.getCommandString(Command.KEEP_LINE_DIRECTION);
            if(key.equalsIgnoreCase(command)) print=true;
            command=Command.getCommandString(Command.KEEP_CONNECTOR_CONNECTIONS);
            if(key.equalsIgnoreCase(command)) print=true;
            if(print) System.out.println("ShapeContainer.setProperty key="+key+
                ", value="+object+", call From="+callFrom);
        }
        return;
    }

    public Object getProperty(String key) {
        Object inf=null;
        String original_type=Command.getCommandString(Command.ORIGINAL_TYPE);
        if(key.equals(original_type)){
            String typeStr=(String)this.property.get("type");
            if(typeStr!=null&&!typeStr.equals("")){
                String str=new String(typeStr);
                this.property.put(original_type, str);
                this.property.remove("type");
            }
            //System.out.println("getProperty key=type typeStr="+typeStr+
            //        ", original_type="+original_type+", value="+this.property.get(original_type));
        }
        inf=this.property.get(key);
        return inf;
    }

    public void removeProperty(String key, String callFrom) {
        this.property.remove(key);
        if(this.debug>0) {
            boolean print=false;
            String command="";
            command=Command.getCommandString(Command.ENABLE_RESIZING);
            if(key.equalsIgnoreCase(command)) print=true;
            command=Command.getCommandString(Command.KEEP_LINE_DIRECTION);
            if(key.equalsIgnoreCase(command)) print=true;
            command=Command.getCommandString(Command.KEEP_CONNECTOR_CONNECTIONS);
            if(key.equalsIgnoreCase(command)) print=true;
            if(print) System.out.println("ShapeContainer.removeProperty key="+key+
                ", call From="+callFrom);
        }
        return;
    }

    public boolean getBooleanProperty(String key, String callFrom){
        String pKey="";
        String command="";
        boolean value=false;
        command=Command.getCommandString(Command.ENABLE_RESIZING);
        if(key.equalsIgnoreCase(command)) {
            pKey=command;
            value=true;
        }
        command=Command.getCommandString(Command.KEEP_ASPECT_RATIO);
        if(key.equalsIgnoreCase(command)) {
            pKey=command;
            value=false;
        }
        command=Command.getCommandString(Command.KEEP_LINE_DIRECTION);
        if(key.equalsIgnoreCase(command)) {
            pKey=command;
            value=false;
        }
        command=Command.getCommandString(Command.KEEP_CONNECTOR_CONNECTIONS);
        if(key.equalsIgnoreCase(command)) {
            pKey=command;
            value=true;
        }
        command=Command.getCommandString(Command.ENABLE_UNGROUPING);
        if(key.equalsIgnoreCase(command)) {
            pKey=command;
            value=true;
        }
        if(pKey.equals("")){
            System.err.println("*** Error ShapeContainer.getBooleanPropery "
                    + "Undefined key,  key="+key+", call From="+callFrom);
            return false;
        }
        Object object=this.getProperty(pKey);
        if(object!=null){
            String className=object.getClass().getSimpleName();
            if(className.equals("Boolean")){
                Boolean flag=(Boolean)object;
                value=flag.booleanValue();
            } else {
                String flag=(String)object;
                value=Boolean.parseBoolean(flag);
            }
        }
        if(this.debug>0) {
            boolean print=false;
            command="";
            command=Command.getCommandString(Command.ENABLE_RESIZING);
            if(key.equalsIgnoreCase(command)) print=true;
            command=Command.getCommandString(Command.KEEP_LINE_DIRECTION);
            if(key.equalsIgnoreCase(command)) print=true;
            command=Command.getCommandString(Command.KEEP_CONNECTOR_CONNECTIONS);
            if(key.equalsIgnoreCase(command)) print=true;
            if(print) System.out.println("ShapeContainer.getBooleanPropery "
                  + ", key="+key+", object="+object+", value="+value+", call From="+callFrom);
        }
        return value;
    }

    public PaintStyle getPaintStyle() {
        if (this.paintStyle.getShapeContainer() == null) {
            this.paintStyle.setShapeContainer(this);
        }
        return this.paintStyle;
    }

    public void setPaintStyle(PaintStyle paintStyle) {
        this.paintStyle = paintStyle;
        if (paintStyle.getShapeContainer() == null||
            !paintStyle.getShapeContainer().getShapeId().equals(this.shapeId) ) {
            paintStyle.setShapeContainer(this);
        }
    }

    public Color[] getColors() {
        Vector<Color> vector = new Vector<Color>();
        Color[] colors = new Color[0];
        if (this.getContainerType() != ShapeContainer.SHAPE) {
            return colors;
        }
        PaintStyle style = this.getPaintStyle();
        if(style.getFillColor()!=null) vector.add(style.getFillColor());
        if(style.getLineColor()!=null) vector.add(style.getLineColor());
        TextBox textBox = this.getTextBox();
        if (textBox != null) {
            Color[] fontColors = textBox.getFontColors();
            for (int i = 0; i < fontColors.length; i++) {
                if(fontColors[i]!=null) vector.add(fontColors[i]);
            }
        }
        Vector<Color> vector0 = new Vector<Color>();
        for (int i = 0; i < vector.size(); i++) {
             Color color=vector.get(i);
             int rgb=color.getRGB();
             int jsave=-1;
             for(int j=0;j<vector0.size();j++){
                 if(vector0.get(j).getRGB()==rgb){
                     jsave=j;
                     break;
                 }
             }
             if(jsave==-1) vector0.add(color);
        }
        colors = new Color[vector0.size()];
        for (int i = 0; i < vector0.size(); i++) {
            colors[i]=vector0.get(i);
        }
        return colors;
    }

    public boolean isTextBox() {
        boolean hasTextBox = false;
        if (textBox != null) {
            hasTextBox = true;
        }
        return hasTextBox;
    }

    public boolean isCommittedText() {
        boolean text = false;
        if (this.textBox != null&&this.textBox.isCommittedText()) {
            text = true;
        }
        return text;
    }

    public int addTextBox() {
        int result = 0;
        if (this.getContainerType() == ShapeContainer.GROUP) {
            result = 1;
        } else {
            int type = this.getElement().getTypeE();
            if (type < Command.RECTANGLE || type > Command.GENERAL_CURVE) {
                result = 2;
            }
        }
        if (!this.element.isClosed()) {
            result = 3;
        }

        if (this.isTextBox()) {
            result = 4;
        }
        Rectangle2D textArea = this.element.createTextArea();
        if(textArea==null){
            result = 5;
        }
        if(textArea!=null&&(textArea.getWidth()<ShapeElement.MinTextArea.getWidth()||
                textArea.getHeight()<ShapeElement.MinTextArea.getHeight())) {
            result = 6;
        }
        if(result==0){
            TextBox newTextBox = new TextBox();
            newTextBox.setShapeContainer(this);
            newTextBox.setTextArea(textArea);
            this.textBox = newTextBox;
            newTextBox.setShapeContainer(this);
        } else {
            System.err.println("*** Error ShapeContainer.addTextBox error code="+result);
            if(result==6){
                System.err.println(" --created text area too small"
                        + ", text area: "+Util.Rect(textArea));
            }
        }
        return result;
    }

    public void addTextBox(Rectangle2D textArea) {
        TextBox newTextBox = new TextBox();
        newTextBox.setShapeContainer(this);
        newTextBox.setTextArea(textArea);
        this.textBox = newTextBox;
    }

    public int deleteTextBox() {
        int result = 0;
        if (this.getContainerType() == ShapeContainer.GROUP) {
            result = 1;
            return result;
        } else {
            int type = this.getElement().getTypeE();
            if (type < Command.RECTANGLE || type > Command.GENERAL_CURVE) {
                result = 2;
                return result;
            }
        }
        if (!this.element.isClosed()) {
            result = 3;
            return result;
        }
        if (this.textBox==null) {
            result = 4;
            return result;
        }
        TextBox currentTBox=this.getTextBox();
        this.makeTextBoxEditable(false);
        currentTBox.setShapeContainer(null);
        this.textBox=null;
        if(debug>0) System.out.println("ShapeContainer deleteTextBox result="+result);
        return result;
    }

    public TextBox getTextBox() {
        return this.textBox;
    }

    public void setTextBox(TextBox textBox) {
        this.textBox = textBox;
        this.textBox.setShapeContainer(this);
    }

    public void setConnectorTargetPermission(boolean permission) {
        this.connectorTargetPermission = permission;
    }

    public void setConnectorPermission(boolean permission) {
        this.connectorPermission = permission;
        if (this.element == null) {
            return;
        }
        int type = this.getElement().getTypeE();
        if (type == Command.LINE || type == Command.ARROW || type == Command.DOUBLE_ARROW
                || type == Command.POLYLINE) {
            return;
        } else {
            this.connectorPermission = false;
            return;
        }
    }

    public boolean isConnectorTarget() {
        return this.connectorTargetPermission;
    }

    public boolean isConnector() {
        if (this.getElement() == null || this.getContainerType() == GROUP) {
            this.connectorPermission = false;
            return false;
        }
        int type = this.getElement().getTypeE();
        boolean close = this.getElement().isClosed();
        if (type == Command.LINE || type == Command.ARROW || type == Command.DOUBLE_ARROW
                || type == Command.POLYLINE && !close) {
            return this.connectorPermission;
        }
        return false;
    }

    public boolean compare(ShapeContainer container) {
        boolean compare = false;
        if (this.getSerialNumber() == container.getSerialNumber()) {
            compare = true;
        }
        return compare;
    }

    public boolean compare(ShapeContainer[] containers) {
        boolean found = false;
        if (containers == null) {
            return false;
        }
        for (int i = 0; i < containers.length; i++) {
            if (this.getSerialNumber() == containers[i].getSerialNumber()) {
                found = true;
                break;
            }
        }
        return found;
    }

    public ShapeContainer[] getGroupedContainers() {
        ShapeContainer[] children = new ShapeContainer[0];
        if (this.getContainerType() == ShapeContainer.GROUP) {
            GroupElement groupElement = (GroupElement) this.getElement();
            children = groupElement.getGroupedContainers();
        }
        ShapeContainer[] containers = new ShapeContainer[1 + children.length];
        containers[0] = this;
        for (int i = 0; i < children.length; i++) {
            containers[i + 1] = children[i];
        }
        return containers;
    }

    public ShapeContainer[] getGroupedSingleShapeContainers() {
        ShapeContainer[] shapeContainers = new ShapeContainer[1];
        if (this.getContainerType() == ShapeContainer.SHAPE) {
            shapeContainers[0] = this;
        } else {
            GroupElement groupElement = (GroupElement) this.getElement();
            shapeContainers = groupElement.getGroupedSingleShapeContainers();
        }
        return shapeContainers;
    }
	
	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.getShapeId().equals(shapeId)){
			findDepth=new Integer(0);
			return 0;
		}
		//ShapeContainer[] children = new ShapeContainer[0];
		if (this.getContainerType() == ShapeContainer.GROUP) {
			GroupElement groupElement = (GroupElement) this.getElement();
			groupElement.getGroupTreeDepth(vector);
		}
		findDepth=(Integer)vector.get(2);

		return findDepth.intValue();
	}
	
    public TextBox[] getGroupedTextBoxes() {
        TextBox[] textBoxes = new TextBox[0];
        if (this.getContainerType() == ShapeContainer.SHAPE) {
            if (this.isTextBox()) {
                textBoxes = new TextBox[1];
                textBoxes[0] = this.getTextBox();
            }
        } else {
            ShapeContainer[] children = this.getGroupedSingleShapeContainers();
            Vector vector = new Vector();
            for (int i = 0; i < children.length; i++) {
                if (!children[i].isTextBox()) {
                    continue;
                }
                vector.add(children[i].getTextBox());
            }
            int size = vector.size();
            textBoxes = new TextBox[size];
            for (int i = 0; i < size; i++) {
                textBoxes[i] = (TextBox) vector.get(i);
            }
        }
        return textBoxes;
    }

    public TextBox getGroupedTextBox(int serialNumber) {
        TextBox targetTextBox = null;
        TextBox[] textBoxes = this.getGroupedTextBoxes();
        for (int i = 0; i < textBoxes.length; i++) {
            if (textBoxes[i].getShapeContainer().getSerialNumber() == serialNumber) {
                targetTextBox = textBoxes[i];
                break;
            }
        }
        if (targetTextBox == null) {
            System.err.println("*** Error in ShapeContainer.getGroupedTextBox:"
                    + "Target TextBox not found, shapeId=" + shapeId
                    + ", this.shapeId=" + this.getShapeId());
        }
        return targetTextBox;
    }

    public PaintStyle[] getGroupedPaintStyles() {
        PaintStyle[] paintStyles = new PaintStyle[0];
        if (this.getContainerType() == ShapeContainer.SHAPE) {
            paintStyles = new PaintStyle[1];
            paintStyles[0] = this.getPaintStyle();
        } else {
            ShapeContainer[] children = this.getGroupedSingleShapeContainers();
            Vector vector = new Vector();
            for (int i = 0; i < children.length; i++) {
                vector.add(children[i].getPaintStyle());
            }
            int size = vector.size();
            paintStyles = new PaintStyle[size];
            for (int i = 0; i < size; i++) {
                paintStyles[i] = (PaintStyle) vector.get(i);
            }
        }
        return paintStyles;
    }

    public PaintStyle getGroupedPaintStyle(int serialNumber) {
        PaintStyle targetPaintStyle = null;
        PaintStyle[] paintStyles = this.getGroupedPaintStyles();
        for (int i = 0; i < paintStyles.length; i++) {
            if (paintStyles[i].getShapeContainer().getSerialNumber() == serialNumber) {
                targetPaintStyle = paintStyles[i];
                break;
            }
        }
        if (targetPaintStyle == null) {
            System.err.println("*** Error in ShapeContainer.getGroupedPaintStyle:"
                    + "Target paintStyle not found, shapeId=" + shapeId
                    + ", this.shapeId=" + this.getShapeId());
        }
        return targetPaintStyle;
    }

    public Rectangle2D getBoundingBox() {
        return this.element.getBoundingBox();
    }

    public void setTextBoxLayout(Insets textBoxInsets, int textAlign, double lineSpace) {
        ShapeContainer[] containers = this.getGroupedSingleShapeContainers();
        for (int i = 0; i < containers.length; i++) {
            if (containers[i].isTextBox()) {
                containers[i].getTextBox().setTextBoxLayout(textBoxInsets, textAlign, lineSpace);
                //containers[i].setChangeCode(UndoConstants.TEXTBOX);
            }
        }
    }

    public void setFillColor(Color fillColor) {
        ShapeContainer[] containers = this.getGroupedSingleShapeContainers();
        for (int i = 0; i < containers.length; i++) {
            containers[i].getPaintStyle().setFillColor(fillColor);
        }

    }

    public void setLineColor(Color lineColor) {
		if(debug>0) System.out.println("ShapeContainer.setLineColor ShapeId="+this.getShapeId()
				+", Color="+lineColor);
        ShapeContainer[] containers = this.getGroupedSingleShapeContainers();
        for (int i = 0; i < containers.length; i++) {
            containers[i].getPaintStyle().setLineColor(lineColor);
            //if(debug>=0) System.out.println("setLineColor after: "+containers[i].getShapeId());
        }

    }

    public void setLineWidth(String lineWidth) {
        ShapeContainer[] containers = this.getGroupedSingleShapeContainers();
        for (int i = 0; i < containers.length; i++) {
            containers[i].getPaintStyle().setLineWidth(lineWidth);
            //containers[i].setChangeCode(UndoConstants.PAINTSTYLE);
        }
    }

    public void setLineStroke(String lineStroke) {

        ShapeContainer[] containers = this.getGroupedSingleShapeContainers();
        for (int i = 0; i < containers.length; i++) {
            containers[i].getPaintStyle().setDashedStyle(lineStroke);
            //containers[i].setChangeCode(UndoConstants.PAINTSTYLE);
        }
    }

    public void setArrowStyle(String arrowStyle) {
        ShapeContainer[] containers = this.getGroupedSingleShapeContainers();
        for (int i = 0; i < containers.length; i++) {
            int elementType = containers[i].getElement().getTypeE();
            if (elementType == Command.POLYLINE && containers[i].getElement().isClosed()) {
                continue;
            }
            containers[i].getPaintStyle().setArrowStyle(arrowStyle);
        }
    }

    public void drawShape(Graphics g) {
        if (debug >0) System.out.println(" - drawShape start "+ this.getShapeId());
        Graphics2D g2 = (Graphics2D) g;
        if (!this.isVisible()) {
            return;
        }
        Composite currentComposit = g2.getComposite();
        int mode = this.getMode();
        float alphaComposite = DrawParameters.DefaultAlpha;
        if (mode == Command.MOVE || mode == Command.RESIZE || mode == Command.MOVE_ENDPT) {
            alphaComposite = DrawParameters.MoveAlpha;
        }
        AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                alphaComposite);
        g2.setComposite(ac);
        //---------------------------------------------------//
        if (this.getContainerType() == ShapeContainer.SHAPE) {
            DrawShapeUtil.drawShapeElement(g, this);
        } else {
            ShapeContainer[] containers = this.getGroupedSingleShapeContainers();
            for (int i = 0; i < containers.length; i++) {
                containers[i].drawShape(g);
            }
        }
        if (this.getTextBox() != null) {
            this.getTextBox().drawTextBox(g);
        }

        if (this.isSelected()) {
            if (this.getMode() == Command.MODIFYING_SHAPE_MODE) {
                DrawShapeUtil.drawSegmentModifiers(g, this);
            } else {
                if (this.getParent() == null) {
                    DrawShapeUtil.drawSelection(g, this);
                }
            }
        }
        g2.setComposite(currentComposit);
        if(debug>0) System.out.println(" - drawShape end");
    }

    public Object clone() {
        if(debug>0) System.out.println("ShapeContainer.clone "+this.getShapeId());
        ShapeContainer newContainer = new ShapeContainer();
        int type = this.getContainerType();
        newContainer.setShapeId(this.getShapeId());
        newContainer.setContainerIndex(this.getContainerIndex());
        newContainer.setConnectorTargetPermission(this.connectorTargetPermission);
        newContainer.setConnectorPermission(this.connectorPermission);
        this.cloneHashMap(this.property);
        newContainer.property=this.cloneHashMap(this.property);
        if (type == ShapeContainer.SHAPE) {
            ShapeElement shapeElement = (ShapeElement) this.getElement().clone();
            newContainer.setElement(shapeElement);
            shapeElement.setShapeContainer(newContainer);
            PaintStyle paintStyle = (PaintStyle) this.getPaintStyle().clone();
            newContainer.setPaintStyle(paintStyle);
            paintStyle.setShapeContainer(newContainer);
            if (this.isTextBox()) {
                TextBox textBox = (TextBox) this.getTextBox().clone();
                newContainer.setTextBox(textBox);
                textBox.setShapeContainer(newContainer);
            }
        }
        if (type == ShapeContainer.GROUP) {
            GroupElement groupElement = new GroupElement();
            newContainer.setElement(groupElement);
            groupElement.setShapeContainer(newContainer);
            ShapeContainer[] children = ((GroupElement) this.getElement()).getChildren();
            for (int i = 0; i < children.length; i++) {
                ShapeContainer childContainer = (ShapeContainer) children[i].clone();
                groupElement.addChildren(childContainer);
                childContainer.setParent(newContainer);
            }
        }
        return newContainer;
    }

    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.toString(0, "- ");
		if (this.getContainerType()==ShapeContainer.GROUP) {
			ShapeContainer[] childContainers = this.getGroupedContainers();
			for (int i = 1; i < childContainers.length; i++) {
				int treeDepth = this.getGroupTreeDepth(childContainers[i].getShapeId());
				str+="\n"+childContainers[i].toString(treeDepth, "- Child: ");
			}
		}
		return str;
	}
	
    public String toString(int indent, String header) {
        String space = "";
		for (int j = 0; j < indent; j++) {
			space += "    ";
		}
		String str = "";
		ShapeContainer parent = this.getParent();
		int containerType = this.getContainerType();
		String typeStr = "SHAPE";
		if (containerType == 1) {
			typeStr = "GROUP";
		}

		str += space + header + this.getShapeId() + ", type=" + typeStr
				+ ", mode=" + Command.getModeString(this.getMode());
		int index = this.getContainerIndex();

		if(parent!=null) str += ", parent=" + parent.getShapeId() + ", ";
		str += "\n" + space + " containerIndex="+ index + " changeCode=" + this.getChangeCode();
		if(this.selected) str += ", selected=" ;
		int elementType = this.getElement().getTypeE();
		if (elementType != Command.GROUP) {
			String textAreaStr = "null";
			if (this.getTextBox() != null) {
				Rectangle2D textArea = this.getTextBox().getTextArea();
				textAreaStr = "textArea:" + Util.Rect(textArea);
			}
			str += "\n" + space + "  text box=" + this.isTextBox() + ", " + textAreaStr;
			if(this.isTextBox()){
				str += "\n" + space + "  Text=\"" 
					+ this.getTextBox().getCommittedTextContainer().getString().replace("\n", "\\n")+ "\"";
			}
		} else {
			GroupElement groupElement = (GroupElement) this.getElement();
			str += "\n" + space + "  children=" + groupElement.toShortString() + ", ";
		}
		//Supplemental Information
		Set<String> set = this.property.keySet();
		String infStr = "";
		Vector<String> list = new Vector(set);
		infStr = "\n" + space + "  property information: ";
		//int listSize=list.size();
		if (list.size() <= 0) {
			infStr += "none";
		}
		for (int i = 0; i < list.size(); i++) {
			String key = list.get(i);
			if (key.equals("")) {
				continue;
			}
			String object = this.property.get(key).toString();
			key = key.toLowerCase();
			key = key.replace("_", " ");
			infStr += " key=" + key + ", value=" + object;
			if (i < list.size() - 1) {
				infStr += ";";
			}
		}
		str += infStr;
        return str;
    }

	public String toShortString() {
		String str="";
		str+=this.toShortString(0, "- ");
		if (this.getContainerType()==ShapeContainer.GROUP) {
			ShapeContainer[] childContainers = this.getGroupedContainers();
			for (int i = 1; i < childContainers.length; i++) {
				int treeDepth = this.getGroupTreeDepth(childContainers[i].getShapeId());
				str+="\n"+childContainers[i].toShortString(treeDepth, "- Child: ");
			}
		}
		return str;
	}
    
	private String toShortString(int indent, String header) {
		String space="";
		for(int j=0;j<indent;j++){
			space+="    ";
		}
		String str="";
		String parentStr = "null";
		ShapeContainer parent = this.getParent();
		int containerType = this.getContainerType();
		String typeStr = "SHAPE";
		if (containerType == 1) {
			typeStr = "GROUP";
		}
		str += space+header+this.getShapeId() + ", type=" + typeStr 
				+ ", mode=" + Command.getModeString(this.getMode());
		int index = this.getContainerIndex();
		if(parent!=null) str += ", parent=" + parent.getShapeId() + ", ";
		str += "\n" + space + " containerIndex="+ index + " changeCode=" + this.getChangeCode();
		if(this.selected) str += ", selected=" ;
		int elementType = this.getElement().getTypeE();
		if (elementType != Command.GROUP) {
			String textAreaStr = "null";
			if (this.getTextBox() != null) {
				Rectangle2D textArea = this.getTextBox().getTextArea();
				textAreaStr ="textArea:" + Util.Rect(textArea);
			}
			str += "\n"+space+"  text box=" + this.isTextBox() + ", " + textAreaStr;
			if(this.isTextBox()){
				str += "\n"+space+ "  Text=\"" 
					+ this.getTextBox().getCommittedTextContainer().getString().replace("\n", "\\n")+ "\"";
			}
		} else {
			GroupElement groupElement = (GroupElement) this.getElement();
			str += "\n"+space+ "  children=" + groupElement.toShortString()+", ";
		}
		//Supplemental Information
		Set<String> set = this.property.keySet();
		String infStr = "";
		Vector<String> list = new Vector(set);
		infStr = "\n"+space+ "  property information: ";
		//int listSize=list.size();
		if (list.size() <= 0) {
			infStr += "none";
		}
		for (int i = 0; i < list.size(); i++) {
			String key = list.get(i);
			if (key.equals("")) {
				continue;
			}
			String object = this.property.get(key).toString();
			key = key.toLowerCase();
			key = key.replace("_", " ");
			infStr += " key=" + key + ", value=" + object;
			if (i < list.size() - 1) {
				infStr += ";";
			}
		}
		str += infStr;

		return str;
	}
	
	public String toVeryShortString() {
		String str="";
		str+=this.toVeryShortString(0, "");
		if (this.getContainerType()==ShapeContainer.GROUP) {
			ShapeContainer[] childContainers = this.getGroupedContainers();
			for (int i = 1; i < childContainers.length; i++) {
				int treeDepth = this.getGroupTreeDepth(childContainers[i].getShapeId());
				str+="\n"+childContainers[i].toVeryShortString(treeDepth, "- child: ");
			}
		}
		return str;
	}
	
	public String toVeryShortString(int indent, String header) {
		String str = "";
		String space = "";
		for (int j = 0; j < indent; j++) {
			space += "    ";
		}
		String parentStr = "null";
		ShapeContainer parent = this.getParent();
		if (parent != null) {
			parentStr = parent.getShapeId();
		}
		int containerType = this.getContainerType();
		String typeStr = "SHAPE";
		if (containerType == 1) {
			typeStr = "GROUP";
		}
		str += space+header+this.getShapeId();
		//nt index = this.getContainerIndex();
		str += ", parent=" + parentStr;

		return str;
	}
	
    public String toPathString() {
        String str="";
        int elementType = this.getElement().getTypeE();
        if (elementType != Command.GROUP) {
            str +=this.getElement().getCurve2D().toPathString();
        } 
        return str;
    }
} // End of ShapeContainer class

