//----------------------------BEGIN LICENSE----------------------------
/* 
 * Willow : the Open Source WorkFlow Project
 * Distributable under GNU LGPL license by gun.org
 *
 * Copyright (C) 2004-2010 huihoo.org 
 * Copyright (C) 2004-2010  ZosaTapo <dertyang@hotmail.com> 
 * 
 * ====================================================================
 * Project Homepage : http://www.huihoo.org/god4j
 * Source Forge     : http://sourceforge.net/projects/huihoo
 * Mailing list     : god4j@lists.sourceforge.net 
 */
//----------------------------END  LICENSE-----------------------------
package org.huihoo.god4j.jgraph;
import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.tree.DefaultMutableTreeNode;

import org.huihoo.god4j.GOD4JFactory;
import org.huihoo.god4j.JGraphFrame;
import org.huihoo.god4j.jgraph.event.XPDLJGraphComponentListener;
import org.huihoo.god4j.jgraph.event.XPDLJGraphKeyListener;
import org.huihoo.god4j.jgraph.event.XPDLJGraphModelListener;
import org.huihoo.god4j.jgraph.event.XPDLJGraphMouseListener;
import org.huihoo.god4j.jgraph.event.XPDLJGraphMouseMotionListener;
import org.huihoo.god4j.jgraph.event.XPDLJGraphSelectionListener;
import org.huihoo.god4j.jgraph.event.XPDLJGraphUndoManager;
import org.huihoo.god4j.jgraph.event.XPDLJGraphUndoableListener;
import org.huihoo.god4j.tree.ExplorerUtilities;
import org.huihoo.god4j.util.ToolUtils;
import org.huihoo.god4j.util.StringManager;
import org.huihoo.god4j.util.UUID;
import org.huihoo.workflow.WorkflowComplexComponent;
import org.huihoo.workflow.impl.xpdl.WorkflowActivityImpl;
import org.huihoo.workflow.impl.xpdl.WorkflowProcessImpl;
import org.huihoo.workflow.xpdl.ExtendedAttribute;
import org.huihoo.workflow.xpdl.WorkflowActivity;
import org.huihoo.workflow.xpdl.WorkflowPackage;
import org.huihoo.workflow.xpdl.WorkflowProcess;
import org.huihoo.workflow.xpdl.WorkflowTransition;
import org.huihoo.workflow.xpdl.activity.ActivityType;
import org.huihoo.workflow.xpdl.activity.SubFlowImplementation;
import org.jgraph.JGraph;
import org.jgraph.graph.CellMapper;
import org.jgraph.graph.CellView;
import org.jgraph.graph.ConnectionSet;
import org.jgraph.graph.DefaultEdge;
import org.jgraph.graph.DefaultGraphCell;
import org.jgraph.graph.DefaultGraphSelectionModel;
import org.jgraph.graph.EdgeView;
import org.jgraph.graph.GraphConstants;
import org.jgraph.graph.Port;
import org.jgraph.graph.PortView;
import org.jgraph.graph.VertexView;
public class XPDLJGraph extends JGraph implements JGraphConstants
{
  private static StringManager sm = StringManager.getManager(JGraphConstants.PACKAGE);

	
	protected Map cellsMap = new HashMap();

	protected JGraphFrame graphFrame;
	protected XPDLJGraphModel graphModel;
	protected XPDLJGraphUndoManager undoMananger;
	protected XPDLJGraphUndoableListener undoableListener;
	
	public XPDLJGraph(JGraphFrame graphFrame, XPDLJGraphModel graphModel)
	{
		super(graphModel);
		
		this.setUI(new XPDLJGraphUI());
		this.graphFrame = graphFrame;

		this.setHighlightColor(Color.red);
		this.setAutoscrolls(true);
		this.setCloneable(false);
		this.setDisconnectable(false);
		this.setBendable(true);
		this.setSelectNewCells(true);
		this.setMoveable(true);
		this.setEditable(false);
		this.setPortsVisible(false);
		this.setGridColor(Color.darkGray);
		
		this.setMarqueeHandler(new XPDLJGraphMarqueeHandler(this));
		this.getSelectionModel().setSelectionMode(DefaultGraphSelectionModel.SINGLE_GRAPH_SELECTION);
		
		this.graphModel = graphModel;
		this.graphModel.addGraphModelListener(new XPDLJGraphModelListener(this));
		this.undoableListener=new XPDLJGraphUndoableListener(this, true);
		this.graphModel.addUndoableEditListener(undoableListener);
		
		this.addKeyListener(new XPDLJGraphKeyListener(this));
		this.addGraphSelectionListener(new XPDLJGraphSelectionListener(this));
		this.addMouseMotionListener(new XPDLJGraphMouseMotionListener(this));
		this.addMouseListener(new XPDLJGraphMouseListener(this));
		this.addComponentListener(new XPDLJGraphComponentListener(this));
		
		this.undoMananger = new XPDLJGraphUndoManager(this);

		loadDocument();
	}
	
	public Map getActivityCellsMap()
	{
		return this.cellsMap;
	}

	public WorkflowProcess getWorkflowProcess()
	{
		return graphFrame.getWorkflowProcess();
	}

	public XPDLJGraphUndoManager getUndoManager()
	{
		return this.undoMananger;
	}

	public void graphProperties()
	{
		Object selectedCell = this.getSelectionCell();
		if (selectedCell == null)
		{
			return;
		}
		GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().graphProperties();
	}

	/**
	 *
	 * 	Delete the selected cell.
	 **/
	public void graphDelete()
	{
		Object[] selectedCells = this.getSelectionCells();
		if (selectedCells != null && selectedCells.length > 1)
		{
			JOptionPane.showMessageDialog(
				GOD4JFactory.getGOD4J(),
				sm.getString("joptionpane.errorCannotDeleteMoreThenOneElementOnce"),
				sm.getString("joptionpane.error"),
				JOptionPane.YES_OPTION);
			return;
		}
		Object cell = getSelectionCell();
		if (cell == null)
		{
			return;
		}

		if (cell instanceof JGraphTransition)
		{
			remove((JGraphTransition) cell);
		}
		else if (cell instanceof JGraphActivity)
		{
			remove((JGraphActivity) cell);
		}

		GOD4JFactory.getGOD4J().setDirty(true);
	}

	public void remove(JGraphActivity graphCell)
	{
		WorkflowActivity activity = (WorkflowActivity) graphCell.getUserObject();
		int answer =
			JOptionPane.showConfirmDialog(
				this,
				sm.getString("joptionpane.confirmDeleteActivity",activity.getName()),
				sm.getString("joptionpane.confirm"),
				JOptionPane.YES_NO_OPTION);

		if (answer == JOptionPane.NO_OPTION)
		{
			return;
		}

		ArrayList cellsToRemove = new ArrayList();
		cellsMap.remove(activity.getUUID());
		Port port = graphCell.getDefaultPort();
		Iterator it = port.edges();
		int i = 0;
		while (it.hasNext())
		{
			DefaultEdge obj = (DefaultEdge) it.next();
			cellsToRemove.add(obj);
			if (obj instanceof JGraphTransition)
			{
				WorkflowTransition transition = (WorkflowTransition) obj.getUserObject();
				getWorkflowProcess().getWorkflowTransitions().remove(transition);

				GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().removeWorkflowTransition(transition);
			}
			i++;
		}

		cellsToRemove.add(graphCell);
		cellsToRemove.add(port);
		Object[] remove = cellsToRemove.toArray(new Object[cellsToRemove.size()]);
		graphModel.remove(remove);

		getWorkflowProcess().removeWorkflowActivity(activity);
		GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().removeWorkflowActivity(activity);
		activity.setWorkflowProcess(getWorkflowProcess());

		if (graphCell instanceof BeginActivity)
		{
			getWorkflowProcess().removeExtendedAttribute(JGraphConstants.ID_ACTIVITY_BEGIN);
		}
		else if (graphCell instanceof EndActivity)
		{
			getWorkflowProcess().removeExtendedAttribute(JGraphConstants.ID_ACTIVITY_END);
		}
		else if (graphCell instanceof SubFlowActivity)
		{
			if (JOptionPane.showConfirmDialog(this, sm.getString("joptionpane.confirmDeleteSubprocess"), sm.getString("joptionpane.confirm"), JOptionPane.YES_NO_OPTION)
				== JOptionPane.YES_OPTION)
			{
				SubFlowImplementation subImpl = (SubFlowImplementation) activity.getImplementation();
								
				WorkflowPackage pkg_def = GOD4JFactory.getGOD4J().getDocument();
				WorkflowProcess proc_remove = pkg_def.findWorkflowProcess(subImpl.getProcessID());
				if(!ExplorerUtilities.canRemoveWorkflowProcess(pkg_def,proc_remove))
				{
				  JOptionPane.showMessageDialog(
  				GOD4JFactory.getGOD4J(),
  				sm.getString("joptionpane.warnCannotDeleteProcessThatIsInUseBySomeSubflowActivity"),
  				sm.getString("joptionpane.warn"),
  				JOptionPane.YES_OPTION);
  				return;
				}
				
				GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().removeWorkflowProcess(proc_remove);
				GOD4JFactory.getGOD4J().getControlPanel().removeJGraph(subImpl.getProcessID());
				
				pkg_def.removeWorkflowProcess(proc_remove);
			}
		}
	}

	public void putIntoCellsMap(String id, Object obj)
	{
		cellsMap.put(id, obj);
	}
	public void removeFromCellsMap(String id)
	{
		cellsMap.remove(id);
	}
	public void remove(JGraphTransition edge)
	{
		WorkflowTransition transition = (WorkflowTransition) edge.getUserObject();
		if (JOptionPane.showConfirmDialog(this, sm.getString("joptionpane.confirmDeleteTransition",transition.getName()),sm.getString("joptionpane.confirm"), JOptionPane.YES_NO_OPTION)
			== JOptionPane.YES_OPTION)
		{
			graphModel.remove(new Object[] { edge });

			getWorkflowProcess().removeWorkflowTransition(transition);
			GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().removeWorkflowTransition(transition);
			transition.setWorkflowProcess(getWorkflowProcess());
			cellsMap.remove(transition.getUUID());
		}
	}
	public void loadDocument()
	{
		boolean addEdits=undoableListener.getAddEdits();
		
		undoableListener.setAddEdits(false);
		
		Iterator activities = getWorkflowProcess().getWorkflowActivities().iterator();
		while (activities.hasNext())
		{
			WorkflowActivity activity = (WorkflowActivity) activities.next();
			loadActivityController(activity);
		}
		Iterator trans = getWorkflowProcess().getWorkflowTransitions().iterator();
		while (trans.hasNext())
		{
			WorkflowTransition tran = (WorkflowTransition) trans.next();
			JGraphActivity source =
				(JGraphActivity) cellsMap.get(tran.getFromWorkflowActivity().getUUID());
			JGraphActivity target = (JGraphActivity) cellsMap.get(tran.getToWorkflowActivity().getUUID());
			connect(source.getDefaultPort(), target.getDefaultPort(), tran, true);
		}
		
		undoableListener.setAddEdits(addEdits);
	}
	
	public void updateTransitionAttributes(DefaultEdge edge)
	{
		EdgeView edgeV = (EdgeView) this.getGraphLayoutCache().getMapping(edge, false);
		WorkflowTransition transition = (WorkflowTransition) edge.getUserObject();
		List pointList_old = edgeV.getPoints();
		List pointList = new ArrayList();
		if (pointList_old != null)
		{
			int size = pointList_old.size();
			for (int i = 0; i < size; ++i)
			{
				Object obj = pointList_old.get(i);
				if (obj instanceof PortView)
				{
					PortView pv = (PortView) obj;
					pointList.add(pv.getLocation(edgeV));
				}
				else
				{
					pointList.add(obj);
				}
			}
		}
		ExtendedAttribute transPosition =
			new ExtendedAttribute(
				JGraphConstants.GOD4J_TRANSITION_POINT_LIST,
				XPDLJGraphUtils.savePointList(pointList));
		transition.addExtendedAttribute(transPosition);
		ExtendedAttribute labelPosition =
			new ExtendedAttribute(
				JGraphConstants.GOD4J_TRANSITION_LABEL_LOCATION,
				XPDLJGraphUtils.savePoint(XPDLJGraphUtils.convertToPoint(edgeV.getLabelPosition())));
		transition.addExtendedAttribute(labelPosition);
		GOD4JFactory.getGOD4J().setDirty(true);
	}
	public void updateActivityAttributes(DefaultGraphCell cell)
	{
		Rectangle rect = GraphConstants.getBounds(cell.getAttributes()).getBounds();
		WorkflowActivity activity = (WorkflowActivity) cell.getUserObject();
		ExtendedAttribute bounds =
			new ExtendedAttribute(JGraphConstants.GOD4J_ACTIVITY_BOUNDS, XPDLJGraphUtils.saveRect(rect));
		activity.addExtendedAttribute(bounds);
		GOD4JFactory.getGOD4J().setDirty(true);
	}

	public void addActivityController(Point point)
	{
		point = XPDLJGraphUtils.convertToPoint(this.fromScreen(point));
		if (GOD4JFactory.getGOD4J().getControlPanel().getActionType() == XPDLJGraphToolBar.INSERT_BUSINESS)
		{
			
			addBusinessActivity(point);
		}
		if (GOD4JFactory.getGOD4J().getControlPanel().getActionType() == XPDLJGraphToolBar.INSERT_ROUTE)
		{
			addRouteActivity(point);
		}
		if (GOD4JFactory.getGOD4J().getControlPanel().getActionType() == XPDLJGraphToolBar.INSERT_SUBFLOW)
		{
			addSubFlowActivity(point);
		}
		else if (GOD4JFactory.getGOD4J().getControlPanel().getActionType() == XPDLJGraphToolBar.INSERT_BEGIN)
		{
			addBeginActivity(point);
		}
		else if (GOD4JFactory.getGOD4J().getControlPanel().getActionType() == XPDLJGraphToolBar.INSERT_END)
		{
			addEndActivity(point);
		}
		GOD4JFactory.getGOD4J().getControlPanel().setActionType(XPDLJGraphToolBar.SELECT);
	}
	
	protected void addBeginActivity(Point point)
	{
		if (getWorkflowProcess().findExtendedAttribute(JGraphConstants.ID_ACTIVITY_BEGIN) != null)
		{
			JOptionPane.showMessageDialog(this, sm.getString("joptionpane.errorWorkflowProcessCanHaveOnlyOneBeginActivity"));
			return;
		}

		WorkflowActivity activity = new WorkflowActivityImpl(UUID.generate(), sm.getString("jgraph.beginActivityLabel"));
		activity.setActivityType(ActivityType.ACTIVITY_BEGIN);
		activity.setWorkflowProcess(graphFrame.getWorkflowProcess());
		getWorkflowProcess().addWorkflowActivity(activity);
		getWorkflowProcess().addExtendedAttribute(
			new ExtendedAttribute(JGraphConstants.ID_ACTIVITY_BEGIN, activity.getUUID()));
		GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowActivity(activity);

		Rectangle bounds = new Rectangle(point.x, point.y, ACTIVITY_HEIGHT, ACTIVITY_HEIGHT);
		this.insertActivityController(bounds, activity, true);

		GOD4JFactory.getGOD4J().setDirty(true);
	}
	protected void addEndActivity(Point point)
	{
		if (getWorkflowProcess().findExtendedAttribute(JGraphConstants.ID_ACTIVITY_END) != null)
		{
			JOptionPane.showMessageDialog(this, sm.getString("joptionpane.errorWorkflowProcessCanHaveOnlyOneEndActivity"));
			return;
		}

		WorkflowActivity activity = new WorkflowActivityImpl(UUID.generate(), sm.getString("jgraph.endActivityLabel"));
		activity.setActivityType(ActivityType.ACTIVITY_END);
		activity.setWorkflowProcess(graphFrame.getWorkflowProcess());
		getWorkflowProcess().addWorkflowActivity(activity);
		getWorkflowProcess().addExtendedAttribute(
			new ExtendedAttribute(JGraphConstants.ID_ACTIVITY_END, activity.getUUID()));
		GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowActivity(activity);

		Rectangle bounds = new Rectangle(point.x, point.y, ACTIVITY_HEIGHT, ACTIVITY_HEIGHT);
		this.insertActivityController(bounds, activity, true);

		GOD4JFactory.getGOD4J().setDirty(true);
	}
	protected void addBusinessActivity(Point point)
	{
		int size = this.getWorkflowProcess().getWorkflowActivities().size() + 1;
		WorkflowActivity activity =new WorkflowActivityImpl(UUID.generate(), sm.getString("jgraph.businessActivityLabel") +" "+size);
		activity.setActivityType(ActivityType.ACTIVITY_BUSINESS);
		activity.setWorkflowProcess(graphFrame.getWorkflowProcess());
		getWorkflowProcess().addWorkflowActivity(activity);

		GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowActivity(activity);

		Rectangle bounds = new Rectangle(point.x, point.y, ACTIVITY_WIDTH, ACTIVITY_HEIGHT);
		this.insertActivityController(bounds, activity, true);

		GOD4JFactory.getGOD4J().setDirty(true);
	}
	protected void addRouteActivity(Point point)
	{
		int size = this.getWorkflowProcess().getWorkflowActivities().size() + 1;
		WorkflowActivity activity =
			new WorkflowActivityImpl(UUID.generate(), sm.getString("jgraph.routeActivityLabel")+" "+ size);
		activity.setActivityType(ActivityType.ACTIVITY_ROUTE);
		activity.setWorkflowProcess(graphFrame.getWorkflowProcess());
		getWorkflowProcess().addWorkflowActivity(activity);
		GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowActivity(activity);

		Rectangle bounds = new Rectangle(point.x, point.y, ACTIVITY_WIDTH, ACTIVITY_HEIGHT);
		this.insertActivityController(bounds, activity, true);

		GOD4JFactory.getGOD4J().setDirty(true);
	}
	protected void addSubFlowActivity(Point point)
	{
		int size = this.getWorkflowProcess().getWorkflowActivities().size()+1 ;
		WorkflowActivity activity =
			new WorkflowActivityImpl(UUID.generate(), sm.getString("jgraph.subflowActivityLabel") +" "+ size);
		activity.setActivityType(ActivityType.ACTIVITY_SUBFLOW);
    
		if (JOptionPane
			.showConfirmDialog(
				GOD4JFactory.getGOD4J(),
				sm.getString("joptionpane.confirmCreateSubprocess"),
				sm.getString("joptionpane.confirm"),
				JOptionPane.YES_NO_OPTION,
				JOptionPane.NO_OPTION)
			== JOptionPane.YES_OPTION)
		{
			WorkflowPackage default_pkg = GOD4JFactory.getGOD4J().getDocument();
			WorkflowProcess wflProc =
				new WorkflowProcessImpl(
					UUID.generate(),
					sm.getString("jgraph.subprocessLabel")+ " " + (default_pkg.getWorkflowProcesses().size()));
			wflProc.setWorkflowPackage(default_pkg);
			default_pkg.getWorkflowProcesses().add(wflProc);
			GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowProcess(wflProc,true);
			JGraphFrame graphFrame = ToolUtils.createJGraph((WorkflowProcess)wflProc);
			GOD4JFactory.getGOD4J().getControlPanel().addJGraph(graphFrame);	
			
			activity.setImplementation(new SubFlowImplementation(wflProc.getUUID()));
		}

		activity.setWorkflowProcess(graphFrame.getWorkflowProcess());
		getWorkflowProcess().addWorkflowActivity(activity);
		GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowActivity(activity);

		Rectangle bounds = new Rectangle(point.x, point.y, ACTIVITY_WIDTH, ACTIVITY_HEIGHT);
		this.insertActivityController(bounds, activity, true);

		GOD4JFactory.getGOD4J().setDirty(true);
	}
	//----------------------------------------------------------------------------
	//----------------------------------------------------------------------------
	protected void loadActivityController(WorkflowActivity activity)
	{
		ActivityType activityType = activity.getActivityType();
		if (ActivityType.ACTIVITY_BEGIN.equals(activityType))
		{
			loadBeginActivity(activity);
		}
		else if (ActivityType.ACTIVITY_END.equals(activityType))
		{
			loadEndActivity(activity);
		}
		else if (ActivityType.ACTIVITY_ROUTE.equals(activityType))
		{
			loadRouteActivity(activity);
		}
		else if (ActivityType.ACTIVITY_SUBFLOW.equals(activityType))
		{
			loadSubFlowActivity(activity);
		}
		else
		{
			loadBusinessActivity(activity);
		}
	}
	protected void loadBeginActivity(WorkflowActivity activity)
	{

		BeginActivity cell = new BeginActivity(activity);
		cellsMap.put(activity.getUUID(), cell); //??

		Rectangle bounds = null;
		ExtendedAttribute bounds_attr =
			activity.findExtendedAttribute(JGraphConstants.GOD4J_ACTIVITY_BOUNDS);
		if (bounds_attr != null)
		{
			bounds = XPDLJGraphUtils.parseBounds(bounds_attr.getValue());
		}
		if (bounds == null)
		{
			bounds = new Rectangle(INSERT_POINT_X, INSERT_POINT_Y, ACTIVITY_HEIGHT, ACTIVITY_HEIGHT);
			updateActivityAttributes(cell);
		}

		this.insertActivityController(bounds, activity, false);
	}
	protected void loadEndActivity(WorkflowActivity activity)
	{
		EndActivity cell = new EndActivity(activity);
		cellsMap.put(activity.getUUID(), cell); //??

		Rectangle bounds = null;
		ExtendedAttribute bounds_attr =
			activity.findExtendedAttribute(JGraphConstants.GOD4J_ACTIVITY_BOUNDS);
		if (bounds_attr != null)
		{
			bounds = XPDLJGraphUtils.parseBounds(bounds_attr.getValue());
		}
		if (bounds == null)
		{
			bounds = new Rectangle(INSERT_POINT_X, INSERT_POINT_Y, ACTIVITY_HEIGHT, ACTIVITY_HEIGHT);
			updateActivityAttributes(cell);
		}
		this.insertActivityController(bounds, activity, false);
	}
	protected void loadBusinessActivity(WorkflowActivity activity)
	{
		BusinessActivity cell = new BusinessActivity(activity);
		cellsMap.put(activity.getUUID(), cell);
		Rectangle bounds = null;
		ExtendedAttribute bounds_attr =
			activity.findExtendedAttribute(JGraphConstants.GOD4J_ACTIVITY_BOUNDS);
		if (bounds_attr != null)
		{
			bounds = XPDLJGraphUtils.parseBounds(bounds_attr.getValue());
		}
		if (bounds == null)
		{
			bounds = new Rectangle(INSERT_POINT_X, INSERT_POINT_Y, ACTIVITY_WIDTH, ACTIVITY_HEIGHT);
			updateActivityAttributes(cell);
		}
		this.insertActivityController(bounds, activity, false);
	}
	protected void loadRouteActivity(WorkflowActivity activity)
	{
		RouteActivity cell = new RouteActivity(activity);
		cellsMap.put(activity.getUUID(), cell);
		Rectangle bounds = null;
		ExtendedAttribute bounds_attr =
			activity.findExtendedAttribute(JGraphConstants.GOD4J_ACTIVITY_BOUNDS);
		if (bounds_attr != null)
		{
			bounds = XPDLJGraphUtils.parseBounds(bounds_attr.getValue());
		}
		if (bounds == null)
		{
			bounds = new Rectangle(INSERT_POINT_X, INSERT_POINT_Y, ACTIVITY_WIDTH, ACTIVITY_HEIGHT);
			updateActivityAttributes(cell);
		}

		this.insertActivityController(bounds, activity, false);
	}
	protected void loadSubFlowActivity(WorkflowActivity activity)
	{
		SubFlowActivity cell = new SubFlowActivity(activity);
		cellsMap.put(activity.getUUID(), cell);
		Rectangle bounds = null;
		ExtendedAttribute bounds_attr =
			activity.findExtendedAttribute(JGraphConstants.GOD4J_ACTIVITY_BOUNDS);

		if (bounds_attr != null)
		{
			bounds = XPDLJGraphUtils.parseBounds(bounds_attr.getValue());
		}
		if (bounds == null)
		{
			bounds = new Rectangle(INSERT_POINT_X, INSERT_POINT_Y, ACTIVITY_WIDTH, ACTIVITY_HEIGHT);
			updateActivityAttributes(cell);
		}
		this.insertActivityController(bounds, activity, false);

	}
	//----------------------------------------------------------------------------
	//----------------------------------------------------------------------------
	protected void insertActivityController(
		Rectangle bounds,
		WorkflowActivity activity,
		boolean update)
	{
		ActivityType activityType = activity.getActivityType();
		if (ActivityType.ACTIVITY_BEGIN.equals(activityType))
		{
			insertBeginActivity(bounds, activity, update);
		}
		else if (ActivityType.ACTIVITY_END.equals(activityType))
		{
			insertEndActivity(bounds, activity, update);
		}
		else if (ActivityType.ACTIVITY_ROUTE.equals(activityType))
		{
			insertRouteActivity(bounds, activity, update);
		}
		else if (ActivityType.ACTIVITY_SUBFLOW.equals(activityType))
		{
			insertSubFlowActivity(bounds, activity, update);
		}
		else
		{
			insertBusinessActivity(bounds, activity, update);
		}
	}

	protected void insertBeginActivity(Rectangle bounds, WorkflowActivity activity, boolean update)
	{
		BeginActivity cell = new BeginActivity(activity);
		cellsMap.put(activity.getUUID(), cell); //??

		if (update)
		{
			updateActivityAttributes(cell);
		}

		Map attributeMap = new HashMap();
		Map map = new HashMap();
		GraphConstants.setBounds(map, bounds);
		GraphConstants.setConnectable(map, true);
		GraphConstants.setBorderColor(map, Color.blue);
		GraphConstants.setOpaque(map, true);
		GraphConstants.setSizeable(map, false);
		GraphConstants.setEditable(map, false);
		attributeMap.put(cell, map);
		Object[] insert = { cell };
		getGraphLayoutCache().insert(insert, attributeMap, null, null, null);
	}
	protected void insertEndActivity(Rectangle bounds, WorkflowActivity activity, boolean update)
	{
		EndActivity cell = new EndActivity(activity);
		cellsMap.put(activity.getUUID(), cell); //??

		if (update)
		{
			updateActivityAttributes(cell);
		}

		Map attributeMap = new HashMap();
		Map map = new HashMap();
		GraphConstants.setBounds(map, bounds);
		GraphConstants.setConnectable(map, true);
		GraphConstants.setBorderColor(map, Color.blue);
		GraphConstants.setOpaque(map, true);
		GraphConstants.setSizeable(map, false);
		GraphConstants.setEditable(map, false);
		attributeMap.put(cell, map);
		Object[] insert = { cell };
		getGraphLayoutCache().insert(insert, attributeMap, null, null, null);
	}
	protected void insertBusinessActivity(
		Rectangle bounds,
		WorkflowActivity activity,
		boolean update)
	{
		BusinessActivity cell = new BusinessActivity(activity);
		cellsMap.put(activity.getUUID(), cell);

		if (update)
		{
			updateActivityAttributes(cell);
		}

		Map attributeMap = new HashMap();
		Map map = new HashMap();
		GraphConstants.setBounds(map, bounds);
		GraphConstants.setConnectable(map, true);
		GraphConstants.setHorizontalTextPosition(map, SwingConstants.TRAILING);
		//      GraphConstants.setHorizontalAlignment(map,SwingConstants.LEFT);
		Border border2 =
			BorderFactory.createBevelBorder(
				BevelBorder.RAISED,
				Color.white,
				Color.white,
				new Color(103, 101, 98),
				new Color(148, 145, 140));
		GraphConstants.setBorder(map, border2);
		GraphConstants.setBackground(map, new Color(0x84ffff));
		GraphConstants.setBorderColor(map, Color.blue);
		GraphConstants.setOpaque(map, true);
		GraphConstants.setSizeable(map, true);
		GraphConstants.setEditable(map, false);
		attributeMap.put(cell, map);
		Object[] insert = { cell };
		getGraphLayoutCache().insert(insert, attributeMap, null, null, null);

	}
	protected void insertRouteActivity(Rectangle bounds, WorkflowActivity activity, boolean update)
	{
		RouteActivity cell = new RouteActivity(activity);
		cellsMap.put(activity.getUUID(), cell);

		if (update)
		{
			updateActivityAttributes(cell);
		}

		Map attributeMap = new HashMap();
		Map map = new HashMap();
		GraphConstants.setBounds(map, bounds);
		GraphConstants.setConnectable(map, true);
		GraphConstants.setHorizontalTextPosition(map, SwingConstants.TRAILING);
		//      GraphConstants.setHorizontalAlignment(map,SwingConstants.LEFT);
		Border border2 =
			BorderFactory.createBevelBorder(
				BevelBorder.RAISED,
				Color.white,
				Color.white,
				new Color(103, 101, 98),
				new Color(148, 145, 140));
		GraphConstants.setBorder(map, border2);
		GraphConstants.setBackground(map, new Color(0x84ffff));
		GraphConstants.setBorderColor(map, Color.blue);
		GraphConstants.setOpaque(map, true);
		GraphConstants.setSizeable(map, true);
		GraphConstants.setEditable(map, false);
		attributeMap.put(cell, map);
		Object[] insert = { cell };
		getGraphLayoutCache().insert(insert, attributeMap, null, null, null);
		GOD4JFactory.getGOD4J().setDirty(true);
	}
	protected void insertSubFlowActivity(Rectangle bounds, WorkflowActivity activity, boolean update)
	{
		SubFlowActivity cell = new SubFlowActivity(activity);
		cellsMap.put(activity.getUUID(), cell);

		if (update)
		{
			updateActivityAttributes(cell);
		}

		Map attributeMap = new HashMap();
		Map map = new HashMap();
		GraphConstants.setBounds(map, bounds);
		GraphConstants.setConnectable(map, true);
		GraphConstants.setHorizontalTextPosition(map, SwingConstants.TRAILING);
		//      GraphConstants.setHorizontalAlignment(map,SwingConstants.LEFT);
		Border border2 =
			BorderFactory.createBevelBorder(
				BevelBorder.RAISED,
				Color.white,
				Color.white,
				new Color(103, 101, 98),
				new Color(148, 145, 140));
		GraphConstants.setBorder(map, border2);
		GraphConstants.setBackground(map, new Color(0x84ffff));
		GraphConstants.setBorderColor(map, Color.blue);
		GraphConstants.setOpaque(map, true);
		GraphConstants.setSizeable(map, true);
		GraphConstants.setEditable(map, false);
		attributeMap.put(cell, map);
		Object[] insert = { cell };
		getGraphLayoutCache().insert(insert, attributeMap, null, null, null);
	}
	//----------------------------------------------------------------------------
	//----------------------------------------------------------------------------
	public void connect(Port source, Port target, WorkflowTransition transition, boolean loadXPDL)
	{
		if (!loadXPDL)
		{
			getWorkflowProcess().addWorkflowTransition(transition);
			GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowTransition(transition);
		}

		JGraphTransition edge = new JGraphTransition(transition);
		cellsMap.put(transition.getUUID(), edge);

		ConnectionSet cs = new ConnectionSet();
		cs.connect(edge, source, target);
		Map map = new HashMap();
		GraphConstants.setLineEnd(map, GraphConstants.ARROW_CLASSIC);
		GraphConstants.setEndFill(map, true);
		GraphConstants.setLineColor(map, Color.blue);
		GraphConstants.setForeground(map, Color.black);
		GraphConstants.setEditable(map, true);
		GraphConstants.setBendable(map, true);

		if (loadXPDL)
		{
			ExtendedAttribute pointListAttr =
				transition.findExtendedAttribute(JGraphConstants.GOD4J_TRANSITION_POINT_LIST);
			if (pointListAttr != null)
			{
				List pointList = XPDLJGraphUtils.parsePointList(pointListAttr.getValue());
				if (pointList != null)
				{
					GraphConstants.setPoints(map, pointList);
				}
			}

			ExtendedAttribute locLabel =
				transition.findExtendedAttribute(JGraphConstants.GOD4J_TRANSITION_LABEL_LOCATION);
			if (locLabel != null)
			{
				Point pointLabel = XPDLJGraphUtils.parsePoint(locLabel.getValue());
				if (pointLabel != null)
				{
					GraphConstants.setLabelPosition(map, pointLabel);
				}
			}
		}

		HashMap attributes = new HashMap();
		attributes.put(edge, map);
		this.getGraphLayoutCache().insert(new Object[] { edge }, attributes, cs, null, null);

		if (!loadXPDL)
		{
			updateTransitionAttributes(edge);
		}

		GOD4JFactory.getGOD4J().getControlPanel().setActionType(XPDLJGraphToolBar.SELECT);
	}

	public void setSelectionCell(String objUUID)
	{
		Object obj = cellsMap.get(objUUID);
		this.setSelectionCell(obj);
	}
	//=====================================================================================
	//=====================================================================================
	/**
	 * Converts the specified value to string. If the value is an instance of
	 * CellView or the current GraphLayoutCache returns a mapping for value,
	 * then then value attribute of that CellView is used. (The value is
	 * retrieved using getAllAttributes.) If the value is an instance of
	 * DefaultMutableTreeNode (e.g. DefaultGraphCell), then the userobject is
	 * returned as a String.
	 */
	public String convertValueToString(Object value)
	{
		CellView view =
			(value instanceof CellView)
				? (CellView) value
				: getGraphLayoutCache().getMapping(value, false);
		if (view != null)
		{
			Object newValue = GraphConstants.getValue(view.getAllAttributes());
			if (newValue != null)
			{
				value = newValue;
			}
			else
			{
				value = view.getCell();
			}
		}
		if (value != null)
		{
			if (value instanceof DefaultMutableTreeNode)
			{
				return ((DefaultMutableTreeNode) value).toString();
			}
			else if (value instanceof WorkflowComplexComponent)
			{
				return ((WorkflowComplexComponent) value).getName();
			}
			else
			{
				return value.toString();
			}
		}
		return null;
	}
	//=====================================================================================
	//=====================================================================================
	protected EdgeView createEdgeView(JGraph graph, CellMapper mapper, Object cell)
	{
		return new JGraphTransitionView(cell, this, mapper);
	}
	protected PortView createPortView(JGraph graph, CellMapper mapper, Object cell)
	{
		return new XPDLPortView(cell, this, mapper);
	}
	protected VertexView createVertexView(JGraph graph, CellMapper mapper, Object cell)
	{
		if (cell instanceof BeginActivity)
		{
			return new BeginActivityView(cell, this, mapper);
		}
		else if (cell instanceof EndActivity)
		{
			return new EndActivityView(cell, this, mapper);
		}
		else if (cell instanceof BusinessActivityView)
		{
			return new BusinessActivityView(cell, this, mapper);
		}
		else if (cell instanceof RouteActivity)
		{
			return new RouteActivityView(cell, this, mapper);
		}
		else if (cell instanceof SubFlowActivity)
		{
			return new SubFlowActivityView(cell, this, mapper);
		}
		return new VertexView(cell, this, mapper);
	}
}
