All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yaoqiang.graph.model.GraphModel Maven / Gradle / Ivy

package org.yaoqiang.graph.model;

import java.awt.Color;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.JOptionPane;

import org.yaoqiang.bpmn.model.BPMNModelConstants;
import org.yaoqiang.bpmn.model.BPMNModelUtils;
import org.yaoqiang.bpmn.model.elements.XMLCollection;
import org.yaoqiang.bpmn.model.elements.XMLComplexElement;
import org.yaoqiang.bpmn.model.elements.XMLElement;
import org.yaoqiang.bpmn.model.elements.activities.Activity;
import org.yaoqiang.bpmn.model.elements.activities.AdHocSubProcess;
import org.yaoqiang.bpmn.model.elements.activities.BusinessRuleTask;
import org.yaoqiang.bpmn.model.elements.activities.CallActivity;
import org.yaoqiang.bpmn.model.elements.activities.ReceiveTask;
import org.yaoqiang.bpmn.model.elements.activities.ScriptTask;
import org.yaoqiang.bpmn.model.elements.activities.SendTask;
import org.yaoqiang.bpmn.model.elements.activities.ServiceTask;
import org.yaoqiang.bpmn.model.elements.activities.SubProcess;
import org.yaoqiang.bpmn.model.elements.activities.Task;
import org.yaoqiang.bpmn.model.elements.activities.Transaction;
import org.yaoqiang.bpmn.model.elements.artifacts.Artifact;
import org.yaoqiang.bpmn.model.elements.artifacts.Artifacts;
import org.yaoqiang.bpmn.model.elements.artifacts.Association;
import org.yaoqiang.bpmn.model.elements.artifacts.Category;
import org.yaoqiang.bpmn.model.elements.artifacts.CategoryValue;
import org.yaoqiang.bpmn.model.elements.artifacts.Group;
import org.yaoqiang.bpmn.model.elements.artifacts.TextAnnotation;
import org.yaoqiang.bpmn.model.elements.choreography.Choreography;
import org.yaoqiang.bpmn.model.elements.choreographyactivities.CallChoreography;
import org.yaoqiang.bpmn.model.elements.choreographyactivities.ChoreographyActivity;
import org.yaoqiang.bpmn.model.elements.choreographyactivities.ChoreographyTask;
import org.yaoqiang.bpmn.model.elements.choreographyactivities.SubChoreography;
import org.yaoqiang.bpmn.model.elements.collaboration.Collaboration;
import org.yaoqiang.bpmn.model.elements.collaboration.MessageFlow;
import org.yaoqiang.bpmn.model.elements.collaboration.Participant;
import org.yaoqiang.bpmn.model.elements.conversations.CallConversation;
import org.yaoqiang.bpmn.model.elements.conversations.Conversation;
import org.yaoqiang.bpmn.model.elements.conversations.ConversationLink;
import org.yaoqiang.bpmn.model.elements.conversations.ConversationNode;
import org.yaoqiang.bpmn.model.elements.conversations.SubConversation;
import org.yaoqiang.bpmn.model.elements.core.common.FlowElement;
import org.yaoqiang.bpmn.model.elements.core.common.FlowElements;
import org.yaoqiang.bpmn.model.elements.core.common.FlowElementsContainer;
import org.yaoqiang.bpmn.model.elements.core.common.FlowNode;
import org.yaoqiang.bpmn.model.elements.core.common.Message;
import org.yaoqiang.bpmn.model.elements.core.common.SequenceFlow;
import org.yaoqiang.bpmn.model.elements.core.foundation.BaseElement;
import org.yaoqiang.bpmn.model.elements.core.foundation.RootElements;
import org.yaoqiang.bpmn.model.elements.core.infrastructure.Definitions;
import org.yaoqiang.bpmn.model.elements.data.DataAssociation;
import org.yaoqiang.bpmn.model.elements.data.DataInput;
import org.yaoqiang.bpmn.model.elements.data.DataObject;
import org.yaoqiang.bpmn.model.elements.data.DataObjectReference;
import org.yaoqiang.bpmn.model.elements.data.DataOutput;
import org.yaoqiang.bpmn.model.elements.data.DataStore;
import org.yaoqiang.bpmn.model.elements.data.DataStoreReference;
import org.yaoqiang.bpmn.model.elements.data.InputOutputSpecification;
import org.yaoqiang.bpmn.model.elements.data.ItemAwareElement;
import org.yaoqiang.bpmn.model.elements.events.BoundaryEvent;
import org.yaoqiang.bpmn.model.elements.events.CancelEventDefinition;
import org.yaoqiang.bpmn.model.elements.events.CatchEvent;
import org.yaoqiang.bpmn.model.elements.events.CompensateEventDefinition;
import org.yaoqiang.bpmn.model.elements.events.EndEvent;
import org.yaoqiang.bpmn.model.elements.events.Event;
import org.yaoqiang.bpmn.model.elements.events.LinkEventDefinition;
import org.yaoqiang.bpmn.model.elements.events.MessageEventDefinition;
import org.yaoqiang.bpmn.model.elements.events.StartEvent;
import org.yaoqiang.bpmn.model.elements.events.ThrowEvent;
import org.yaoqiang.bpmn.model.elements.gateways.ComplexGateway;
import org.yaoqiang.bpmn.model.elements.gateways.EventBasedGateway;
import org.yaoqiang.bpmn.model.elements.gateways.ExclusiveGateway;
import org.yaoqiang.bpmn.model.elements.gateways.Gateway;
import org.yaoqiang.bpmn.model.elements.gateways.InclusiveGateway;
import org.yaoqiang.bpmn.model.elements.gateways.ParallelGateway;
import org.yaoqiang.bpmn.model.elements.humaninteraction.ManualTask;
import org.yaoqiang.bpmn.model.elements.humaninteraction.UserTask;
import org.yaoqiang.bpmn.model.elements.process.BPMNProcess;
import org.yaoqiang.bpmn.model.elements.process.GlobalTask;
import org.yaoqiang.bpmn.model.elements.process.Lane;
import org.yaoqiang.util.Constants;
import org.yaoqiang.util.Resources;

import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGraphModel;
import com.mxgraph.model.mxICell;

/**
 * GraphModel
 * 
 * @author Shi Yaoqiang([email protected])
 */
public class GraphModel extends mxGraphModel {

	private static final long serialVersionUID = 1849803771002631750L;

	protected Definitions bpmnModel;

	protected PageFormat pageFormat;

	protected Color backgroundColor = Color.WHITE;

	protected int pageCount = Integer.parseInt(Constants.SETTINGS.getProperty("pageNumV", "1"));

	protected int horizontalPageCount = Integer.parseInt(Constants.SETTINGS.getProperty("pageNumH", "1"));

	public GraphModel() {
	}

	public GraphModel(String version) {
		super();
		setBpmnModel(new Definitions(), version);
	}

	public Definitions getBpmnModel() {
		return bpmnModel;
	}

	public void setBpmnModel(Definitions bpmnModel, String version) {
		this.bpmnModel = bpmnModel;
		bpmnModel.setExporterVersion(version);
		bpmnModel.setId("_" + System.currentTimeMillis());
		bpmnModel.setTargetNamespace(BPMNModelConstants.BPMN_TARGET_MODEL_NS + getBpmnModel().getId());
		bpmnModel.getNamespaces().put(getBpmnModel().getTargetNamespace(), "tns");
	}

	public PageFormat getPageFormat() {
		return pageFormat;
	}

	public void setPageFormat(PageFormat pageFormat) {
		this.pageFormat = pageFormat;
	}

	public PageFormat setDefaultPageFormat() {
		PageFormat pageFormat = new PageFormat();
		Paper paper = pageFormat.getPaper();
		paper.setSize(Constants.PAGE_HEIGHT, Constants.PAGE_WIDTH);
		double margin = 5;
		paper.setImageableArea(margin, margin, paper.getWidth() - margin * 2, paper.getHeight() - margin * 2);
		pageFormat.setOrientation(Integer.parseInt(Constants.SETTINGS.getProperty("pageOrientation", "0")));
		pageFormat.setPaper(paper);
		this.pageFormat = pageFormat;
		return pageFormat;
	}

	public int getPageCount() {
		return pageCount;
	}

	public void setPageCount(int pageCount) {
		this.pageCount = pageCount;
	}

	public int getHorizontalPageCount() {
		return horizontalPageCount;
	}

	public void setHorizontalPageCount(int horizontalPageCount) {
		this.horizontalPageCount = horizontalPageCount;
	}

	public Color getBackgroundColor() {
		return backgroundColor;
	}

	public void setBackgroundColor(Color backgroundColor) {
		this.backgroundColor = backgroundColor;
	}

	public List getAllEdgesInOrder(Object root, List callActivities) {
		List edges = new ArrayList();
		Collection cells = getCells().values();
		for (Object cell : cells) {
			if (isEdge(cell) && isAncestor(root, cell)) {
				boolean add = true;
				for (Object parent : callActivities) {
					if (isAncestor(parent, cell)) {
						add = false;
						break;
					}
				}
				if (add) {
					edges.add(cell);
				}
			}
		}
		return edges;
	}

	public Object getParentPool(Object cell) {
		Object parent = null;
		if (cell != null) {
			if (isPool(cell)) {
				return cell;
			}
			if (getParent(cell) != getRoot()) {
				parent = getParent(cell);
				while (parent != null && !isPool(parent)) {
					parent = getParent(cell);
					cell = parent;
				}
			}
		}

		return parent;
	}

	public boolean hasSameParentPool(Object source, Object target) {
		Object srcPool = getParentPool(source);
		Object tgtPool = getParentPool(target);
		return srcPool == tgtPool;
	}

	public boolean canHasDefaultSequenceFlow(Object cell) {
		if (isActivity(cell) || isGateway(cell) && !isEventGateway(cell) && !isParallelGateway(cell)) {
			return true;
		}
		return false;
	}

	public boolean isPool(Object cell) {
		return getValue(cell) instanceof Participant && (getStyle(cell).startsWith("pool") || getStyle(cell).startsWith("verticalPool"));
	}

	public boolean isParticipant(Object cell) {
		return getValue(cell) instanceof Participant;
	}

	public boolean isLane(Object cell) {
		return getValue(cell) instanceof Lane;
	}

	public boolean isEvent(Object cell) {
		return getValue(cell) instanceof Event;
	}

	public boolean isCatchEvent(Object cell) {
		return getValue(cell) instanceof CatchEvent;
	}

	public boolean isThrowEvent(Object cell) {
		return getValue(cell) instanceof ThrowEvent;
	}

	public boolean isStartEvent(Object cell) {
		return getValue(cell) instanceof StartEvent;
	}

	public boolean isEndEvent(Object cell) {
		return getValue(cell) instanceof EndEvent;
	}

	public boolean isIntermediateEvent(Object cell) {
		return getStyle(cell) != null && getStyle(cell).startsWith("intermediate");
	}

	public boolean isMultipleEvent(Object cell) {
		return getStyle(cell) != null && getStyle(cell).indexOf("Multiple") > 0;
	}

	public boolean isNoneEvent(Object cell) {
		return ((Event) getValue(cell)).getEventDefinition() == null && !isMultipleEvent(cell);
	}

	public boolean isBoundaryEvent(Object cell) {
		return getValue(cell) instanceof BoundaryEvent && getGeometry(cell).isRelative();
	}

	public boolean isInterruptingEvent(Event event) {
		return (event instanceof StartEvent && ((StartEvent) event).isInterrupting() || event instanceof BoundaryEvent
				&& ((BoundaryEvent) event).cancelActivity());
	}

	public boolean isNonInterruptingEvent(Event event) {
		return (event instanceof StartEvent && !((StartEvent) event).isInterrupting() || event instanceof BoundaryEvent
				&& !((BoundaryEvent) event).cancelActivity());
	}

	public boolean isCancelBoundaryEvent(Object cell) {
		return isBoundaryEvent(cell) && isCancelEvent(cell);
	}

	public boolean isCancelEndEvent(Object cell) {
		return isEndEvent(cell) && isCancelEvent(cell);
	}

	public boolean isCancelEvent(Object cell) {
		return isEvent(cell) && ((Event) getValue(cell)).getEventDefinition() instanceof CancelEventDefinition;
	}

	public boolean isLinkEvent(Object cell) {
		return isEvent(cell) && ((Event) getValue(cell)).getEventDefinition() instanceof LinkEventDefinition;
	}

	public boolean isMessageEvent(Object cell) {
		return isEvent(cell) && ((Event) getValue(cell)).getEventDefinition() instanceof MessageEventDefinition;
	}

	public boolean isCompensationEvent(Object cell) {
		return isEvent(cell) && ((Event) getValue(cell)).getEventDefinition() instanceof CompensateEventDefinition;
	}

	public boolean isCompensationIntermediateEvent(Object cell) {
		return isIntermediateEvent(cell) && isCompensationEvent(cell);
	}

	public boolean isMessageStartEvent(Object cell) {
		return isStartEvent(cell) && isMessageEvent(cell);
	}

	public boolean isMessageIntermediateEvent(Object cell) {
		return isIntermediateEvent(cell) && isMessageEvent(cell);
	}

	public boolean isMessageEndEvent(Object cell) {
		return isEndEvent(cell) && isMessageEvent(cell);
	}

	public boolean isActivity(Object cell) {
		return getValue(cell) instanceof Activity;
	}

	public boolean isLoopActivity(Object cell) {
		if (isActivity(cell)) {
			return ((Activity) getValue(cell)).getLoopCharacteristics() != null;
		}
		return false;
	}

	public boolean isCompensationActivity(Object cell) {
		if (isActivity(cell)) {
			return ((Activity) getValue(cell)).isForCompensation();
		}
		return false;
	}

	public boolean isTask(Object cell) {
		return getValue(cell) instanceof Task;
	}

	public boolean isUserTask(Object cell) {
		return getValue(cell) instanceof UserTask;
	}

	public boolean isSendTask(Object cell) {
		return getValue(cell) instanceof SendTask;
	}

	public boolean isReceiveTask(Object cell) {
		return getValue(cell) instanceof ReceiveTask;
	}

	public boolean isInstantiateReceiveTask(Object cell) {
		return isReceiveTask(cell) && ((ReceiveTask) getValue(cell)).isInstantiate();
	}

	public boolean isServiceTask(Object cell) {
		return getValue(cell) instanceof ServiceTask;
	}

	public boolean isScriptTask(Object cell) {
		return getValue(cell) instanceof ScriptTask;
	}

	public boolean isManualTask(Object cell) {
		return getValue(cell) instanceof ManualTask;
	}

	public boolean isBusinessRuleTask(Object cell) {
		return getValue(cell) instanceof BusinessRuleTask;
	}

	public boolean isAbstractTask(Object cell) {
		return isTask(cell) && ((Task) getValue(cell)).toName().equals("task");
	}

	public boolean isCallActivity(Object cell) {
		return getValue(cell) instanceof CallActivity;
	}

	public boolean isCallProcess(Object cell) {
		return getValue(cell) instanceof CallActivity && getStyle(cell).startsWith("callProcess");
	}

	public boolean isGateway(Object cell) {
		return getValue(cell) instanceof Gateway;
	}

	public boolean isExclusiveGateway(Object cell) {
		return getValue(cell) instanceof ExclusiveGateway;
	}

	public boolean isExclusiveGatewayWithIndicator(Object cell) {
		return getValue(cell) instanceof ExclusiveGateway && getStyle(cell).startsWith("exclusiveGatewayWithIndicator");
	}

	public boolean isInclusiveGateway(Object cell) {
		return getValue(cell) instanceof InclusiveGateway;
	}

	public boolean isParallelGateway(Object cell) {
		return getValue(cell) instanceof ParallelGateway;
	}

	public boolean isComplexGateway(Object cell) {
		return getValue(cell) instanceof ComplexGateway;
	}

	public boolean isEventGateway(Object cell) {
		return getValue(cell) instanceof EventBasedGateway;
	}

	public boolean isExclusiveEventGateway(Object cell) {
		return isEventGateway(cell) && ((EventBasedGateway) getValue(cell)).getEventGatewayType().equals("Exclusive");
	}

	public boolean isParallelEventGateway(Object cell) {
		return isEventGateway(cell) && ((EventBasedGateway) getValue(cell)).getEventGatewayType().equals("Parallel");
	}

	public boolean isInstantiateEventGateway(Object cell) {
		return isEventGateway(cell) && ((EventBasedGateway) getValue(cell)).isInstantiate();
	}

	public boolean isSubProcess(Object cell) {
		return getValue(cell) instanceof SubProcess;
	}

	public boolean isEventSubProcess(Object cell) {
		return isSubProcess(cell) && ((SubProcess) getValue(cell)).isTriggeredByEvent();
	}

	public boolean isAdhocSubProcess(Object cell) {
		return getValue(cell) instanceof AdHocSubProcess;
	}

	public boolean isTransactionSubProcess(Object cell) {
		return getValue(cell) instanceof Transaction;
	}

	public boolean isCollapsedSubProcess(Object cell) {
		if (isSubProcess(cell) || isChoreographySubprocess(cell)) {
			return (((mxCell) cell).getGeometry().getWidth() <= Constants.FOLDED_SUBPROCESS_WIDTH)
					&& (((mxCell) cell).getGeometry().getHeight() <= Constants.FOLDED_SUBPROCESS_HEIGHT);
		}
		return false;
	}

	public boolean isExpandedSubProcess(Object cell) {
		if (isSubProcess(cell) || isChoreographySubprocess(cell)) {
			return ((mxCell) cell).getGeometry().getWidth() > Constants.FOLDED_SUBPROCESS_WIDTH
					|| ((mxCell) cell).getGeometry().getHeight() > Constants.FOLDED_SUBPROCESS_HEIGHT;
		}
		return false;
	}

	public boolean isMessage(Object cell) {
		return getValue(cell) instanceof Message;
	}

	public boolean isAttachedMessage(Object cell) {
		if (isMessage(cell) && ((mxCell) cell).getParent() != null) {
			if (((mxCell) cell).getParent().isEdge()) {
				return true;
			}
		}
		return false;
	}

	public boolean isArtifact(Object cell) {
		return getValue(cell) instanceof Artifact;
	}

	public boolean isAnnotation(Object cell) {
		return getValue(cell) instanceof TextAnnotation;
	}

	public boolean isGroupArtifact(Object cell) {
		return getValue(cell) instanceof Group;
	}

	public boolean isAssociation(Object cell) {
		return getValue(cell) instanceof Association;
	}

	public boolean isItemAwareElement(Object cell) {
		return getValue(cell) instanceof ItemAwareElement;
	}

	public boolean isDataObject(Object cell) {
		return getValue(cell) instanceof DataObject || getValue(cell) instanceof DataObjectReference;
	}

	public boolean isCollectionDataObject(Object cell) {
		if (isDataInput(cell) || isDataOutput(cell) || getValue(cell) instanceof DataObject) {
			return Boolean.parseBoolean(((BaseElement) getValue(cell)).get("isCollection").toValue());
		} else if (getValue(cell) instanceof DataObjectReference) {
			DataObject dataObject = ((DataObjectReference) getValue(cell)).getRefDataObject();
			if (dataObject != null) {
				return dataObject.isCollection();
			}
		}
		return false;
	}

	public boolean isDataInput(Object cell) {
		return getValue(cell) instanceof DataInput;
	}

	public boolean isDataOutput(Object cell) {
		return getValue(cell) instanceof DataOutput;
	}

	public boolean isDataStore(Object cell) {
		return getValue(cell) instanceof DataStoreReference;
	}

	public boolean isConversationLink(Object cell) {
		return getValue(cell) instanceof ConversationLink;
	}

	public boolean isConversationNode(Object cell) {
		return getValue(cell) instanceof ConversationNode;
	}

	public boolean isConversation(Object cell) {
		return getValue(cell) instanceof Conversation;
	}

	public boolean isSubConversation(Object cell) {
		return getValue(cell) instanceof SubConversation;
	}

	public boolean isCallConversation(Object cell) {
		return getValue(cell) instanceof CallConversation;
	}

	public boolean isCallChoreographyActivity(Object cell) {
		return getValue(cell) instanceof CallChoreography;
	}

	public boolean isChoreographyTask(Object cell) {
		return getValue(cell) instanceof ChoreographyTask;
	}

	public boolean isChoreographySubprocess(Object cell) {
		return getValue(cell) instanceof SubChoreography;
	}

	public boolean isChoreographyParticipant(Object cell) {
		return getValue(cell) instanceof Participant && getStyle(cell).startsWith("participant");
	}

	public boolean isInitiatingChoreographyParticipant(Object cell) {
		if (isChoreographyParticipant(cell)) {
			int index = ((mxCell) cell).getId().indexOf("_part_");
			String actId = ((mxCell) cell).getId().substring(0, index);
			String partId = ((mxCell) cell).getId().substring(index + 6);
			Object act = getValue(getCell(actId));
			return partId.equals(((ChoreographyActivity) act).getInitiatingParticipantRef());
		}
		return false;
	}

	public boolean isMultiInstanceParticipant(Object cell) {
		if (getValue(cell) instanceof Participant) {
			return ((Participant) getValue(cell)).getMultiplicity() != 1;
		}
		return false;
	}

	public boolean isDataAssociation(Object cell) {
		return getValue(cell) instanceof DataAssociation;
	}

	public boolean isMessageFlow(Object cell) {
		return getValue(cell) instanceof MessageFlow;
	}

	public boolean isSequenceFlow(Object cell) {
		return getValue(cell) instanceof SequenceFlow;
	}

	public boolean isDefaultSequenceFlow(Object cell) {
		if (isSequenceFlow(cell)) {
			FlowNode source = (FlowNode) ((mxCell) cell).getSource().getValue();
			if (source.get("default") != null && ((mxCell) cell).getId().equals(source.get("default").toValue())) {
				return true;
			}
		}
		return false;
	}

	public boolean isConditionalSequenceFlow(Object cell) {
		if (isSequenceFlow(cell)) {
			String expression = ((SequenceFlow) getValue(cell)).getConditionExpression().toValue();
			return expression.trim().length() != 0;
		}
		return false;
	}

	public boolean hasConditionalSequenceFlow(Object cell) {
		if (!isGateway(cell) && canHasDefaultSequenceFlow(cell)) {
			for (Object edge : getOutgoingEdges(this, cell)) {
				if (isConditionalSequenceFlow(edge)) {
					return true;
				}
			}
		}
		return false;
	}

	public boolean hasDefaultSequenceFlow(Object cell) {
		if (canHasDefaultSequenceFlow(cell)) {
			for (Object edge : getOutgoingEdges(this, cell)) {
				if (isDefaultSequenceFlow(edge)) {
					return true;
				}
			}
		}
		return false;
	}

	public Map getAllParticipants() {
		Map participants = new HashMap();
		Choreography choreography = BPMNModelUtils.getChoreography(bpmnModel);
		if (choreography != null) {
			for (XMLElement p : choreography.getParticipantList()) {
				Participant participant = (Participant) p;
				participants.put(participant.getName(), participant);
			}
		}
		return participants;
	}

	public Map getAllChoreographyParticipants() {
		Map participants = new HashMap();
		for (Object cell : getCells().values()) {
			if (isChoreographyParticipant(cell)) {
				participants.put(((mxCell) cell).getId(), (mxCell) cell);
			}
		}
		return participants;
	}

	public boolean hasParticipantRef(mxCell owner, String participantId) {
		Map participantCells = getAllChoreographyParticipants();
		for (Entry part : participantCells.entrySet()) {
			if (part.getKey().endsWith(participantId) && part.getValue() != owner) {
				return true;
			}
		}
		return false;
	}

	public Object getCell(String id) {
		Object result = super.getCell(id);
		if (result == null && cells != null && id != null) {
			for (String cellId : cells.keySet()) {
				if (cellId.endsWith("_part_" + id) || cellId.startsWith(id + "_CT") || cellId.startsWith(id + "_SC")) {
					return cells.get(cellId);
				}
			}
		}
		return result;
	}

	public String createId(Object cell) {
		return "_" + nextId++;
	}

	public Object createRoot() {
		mxCell root = new mxCell();
		root.insert(new mxCell(Resources.get("newDiagram")));

		return root;
	}

	protected void cellAdded(Object cell) {
		if (cell instanceof mxICell) {
			mxICell mxc = (mxICell) cell;

			if (mxc.getId() == null && isCreateIds()) {
				mxc.setId(createId(cell));
			}

			if (mxc.getId() != null) {
				Object collision = getCell(mxc.getId());

				if (collision != cell) {
					while (collision != null) {
						mxc.setId(createId(cell));
						collision = getCell(mxc.getId());
					}

					if (cells == null) {
						cells = new Hashtable();
					}

					cells.put(mxc.getId(), cell);
				}
			}

			// Makes sure IDs of deleted cells are not reused
			// ==============start==============
			// try
			// {
			// int id = Integer.parseInt(mxc.getId());
			// nextId = Math.max(nextId, id + 1);
			// }
			// catch (NumberFormatException e)
			// {
			// // ignore
			// }
			// ==============end================
			int childCount = mxc.getChildCount();

			for (int i = 0; i < childCount; i++) {
				cellAdded(mxc.getChildAt(i));
			}
		}
	}

	protected Object parentForCellChanged(Object cell, Object parent, int index) {
		mxICell child = (mxICell) cell;
		mxICell previous = (mxICell) getParent(cell);

		boolean changed = false;
		if (parent != null) {
			if (parent != previous || previous.getIndex(child) != index) {
				((mxICell) parent).insert(child, index);
				changed = true;
			}
		} else if (previous != null) {
			int oldIndex = previous.getIndex(child);
			previous.remove(oldIndex);
		}

		// Checks if the previous parent was already in the
		// model and avoids calling cellAdded if it was.
		if (!contains(previous) && parent != null) {
			cellAdded(cell);
			addNodeElements(child, parent);
		} else if (parent == null) {
			cellRemoved(cell);
			Object value = getValue(cell);
			if (value instanceof BaseElement) {
				XMLElement parentElement = ((BaseElement) value).getParent();
				if (parentElement instanceof XMLCollection) {
					((XMLCollection) parentElement).remove(child.getId());
				}
				if (value instanceof Participant) {
					Choreography choreography = BPMNModelUtils.getChoreography(bpmnModel);
					if (choreography != null) {
						int idx = child.getId().indexOf("_part_");
						String partId = child.getId().substring(idx + 6);
						String actId = child.getId().substring(0, idx);
						if (getValue(getCell(actId)) != null) {
							((ChoreographyActivity) getValue(getCell(actId))).removeParticipantRef(partId);
						}
						if (!hasParticipantRef((mxCell) child, partId)) {
							choreography.removeParticipant(partId);
						}
					}
					BPMNProcess process = bpmnModel.getProcess(((Participant) value).getProcessRef());
					if (process != null) {
						((XMLCollection) process.getParent()).remove(process.getId());
					}
				} else if (value instanceof FlowNode) {
					Object parentValue = getValue(previous);
					if (parentValue instanceof Lane) {
						((Lane) parentValue).removeFlowNodeRef(child.getId());
					}
				} else if (value instanceof Lane) {
					BPMNProcess process = BPMNModelUtils.getParentProcess((XMLElement) value);
					for (String id : BPMNModelUtils.getFlowNodeRefs((Lane) value)) {
						process.removeFlowElement(id);
					}
				} else if (value instanceof DataInput || value instanceof DataOutput) {
					FlowElementsContainer container = null;
					if (getParent(previous) == getRoot()) {
						container = bpmnModel.getProcess(((mxICell) previous).getId());
						if (container == null) {
							container = BPMNModelUtils.getDefaultProcess(bpmnModel);
						}
					} else if (getValue(previous) instanceof FlowElementsContainer) {
						container = (FlowElementsContainer) getValue(parent);
					}
					InputOutputSpecification ioSpec = null;
					if (container instanceof BPMNProcess) {
						ioSpec = ((BPMNProcess) container).getIoSpecification();
					} else if (container instanceof SubProcess) {
						ioSpec = ((SubProcess) container).getIoSpecification();
					}
					if (value instanceof DataInput) {
						ioSpec.removeDataInputRef(((DataInput) value).getId());
					} else {
						ioSpec.removeDataOutputRef(((DataOutput) value).getId());
					}
				}
				removeEmptyProcess((XMLElement) value);
			} else if ("choreography".equals(child.getStyle()) || "subChoreography".equals(child.getStyle())) {
				for (Object c : GraphModel.getChildVertices(this, child)) {
					remove(c);
				}
			}
		} else if (changed && (getValue(cell) instanceof XMLElement) && !(getValue(cell) instanceof SequenceFlow)
				&& !(getValue(cell) instanceof DataAssociation)) {// TODO: A
			Object value = getValue(cell);
			XMLElement parentElement = ((BaseElement) value).getParent();
			if (parentElement instanceof XMLCollection) {
				if (getValue(previous) instanceof Lane) {
					if (value instanceof FlowNode) {
						((Lane) getValue(previous)).removeFlowNodeRef(child.getId());
					}
				}
				((XMLCollection) parentElement).remove(child.getId());
				removeEmptyProcess((XMLElement) value);
			}
			if (value instanceof Lane) {
				if (getValue(parent) instanceof Participant) {
					BPMNProcess process = bpmnModel.getProcess(((Participant) getValue(parent)).getProcessRef());
					if (process == null) {
						process = bpmnModel.createProcess(false);
						((Participant) getValue(parent)).setProcessRef(process.getId());
					}
					process.addLane((Lane) value);
				} else if (getValue(parent) instanceof Lane) {
					((Lane) getValue(parent)).addChildLane((Lane) value);
				}
			} else if (value instanceof Participant) {
				Choreography choreography = BPMNModelUtils.getChoreography(bpmnModel);
				choreography.addParticipant((Participant) value);
			} else {
				FlowElementsContainer container = null;
				if (getParent(parent) == getRoot()) {
					container = bpmnModel.getProcess(((mxICell) parent).getId());
					if (container == null) {
						container = BPMNModelUtils.getDefaultProcess(bpmnModel);
					}
					if (container == null) {
						container = bpmnModel.createProcess(BPMNModelUtils.getCollaboration(bpmnModel) == null);
					}
				} else if (getValue(parent) instanceof FlowElementsContainer) {
					container = (FlowElementsContainer) getValue(parent);
				} else if (getValue(parent) instanceof Participant) {
					Participant participant = (Participant) getValue(parent);
					container = bpmnModel.getProcess(participant.getProcessRef());
					if (container == null) {
						container = bpmnModel.createProcess(false);
						participant.setProcessRef(((BaseElement) container).getId());
					}
				} else if (getValue(parent) instanceof Lane) {
					container = BPMNModelUtils.getParentProcess((XMLElement) getValue(parent));
					if (value instanceof FlowNode) {
						((Lane) getValue(parent)).addFlowNodeRef(child.getId());
					}
				}
				if (container != null) {
					if (value instanceof Artifact) {
						container.addArtifact((XMLElement) value);
					} else if (value instanceof FlowElement) {
						container.addFlowElement((XMLElement) value);
					}
				}
			}
		}

		return previous;
	}

	protected Object terminalForCellChanged(Object edge, Object terminal, boolean isSource) {
		mxICell previous = (mxICell) getTerminal(edge, isSource);
		mxCell cell = (mxCell) edge;
		Object value = cell.getValue();
		if (terminal != null) {
			((mxICell) terminal).insertEdge(cell, isSource);
			if ((!isSource || isSource && (previous != null && previous != terminal)) && (value instanceof String || value instanceof SequenceFlow)) {
				Object source = cell.getSource().getValue();
				Object target = cell.getTarget().getValue();
				if (source instanceof TextAnnotation || target instanceof TextAnnotation || source instanceof Message || target instanceof Message
						|| (isBoundaryEvent(cell.getSource()) && isCompensationIntermediateEvent(cell.getSource()))) {
					Artifacts artifacts = BPMNModelUtils.getArtifacts(bpmnModel);
					if (!(value instanceof Association)) {
						Association association = new Association(artifacts);
						association.setId(cell.getId());
						association.setSourceRef(((BaseElement) source).getId());
						association.setTargetRef(((BaseElement) target).getId());
						if (isBoundaryEvent(cell.getSource())) {
							association.setAssociationDirection("One");
						}
						artifacts.add(association);
						cell.setValue(association);
					}
				} else if (source instanceof ItemAwareElement || target instanceof ItemAwareElement) {
					DataAssociation da = null;
					ItemAwareElement data = null;
					String dataId = null;
					mxCell sCell = (mxCell) cell.getSource();
					mxCell tCell = (mxCell) cell.getTarget();
					int opt = JOptionPane.YES_OPTION;
					if (isItemAwareElement(sCell)) {
						dataId = "Din" + tCell.getId() + sCell.getId();
						XMLElement actOrEvent = (XMLElement) tCell.getValue();
						if (actOrEvent instanceof Activity) {
							Activity act = (Activity) actOrEvent;
							int size = act.getIoSpecification().getDataInputs().size();
							if (size > 0) {
								opt = JOptionPane.showConfirmDialog(null, Resources.get("InfoYesToCreateNewInputOutputOrNoToSelectExistedInputOutput"),
										Resources.get("InfoCreateOrSelect"), JOptionPane.YES_NO_OPTION);
							}
							if (opt == JOptionPane.NO_OPTION) {
								data = (ItemAwareElement) JOptionPane.showInputDialog(null, Resources.get("dataInput"), Resources.get("selectDataInput"),
										JOptionPane.PLAIN_MESSAGE, null, BPMNModelUtils.getDataInOuts(actOrEvent, "selectDataInput").toArray(), null);
							}
							if (data == null) {
								data = act.getIoSpecification().addDataInput(dataId, null, false);
							}
							da = act.addDataInputAssociation(cell.getId(), sCell.getId(), data.getId());
						} else if (actOrEvent instanceof ThrowEvent) {
							ThrowEvent evt = (ThrowEvent) actOrEvent;
							int size = evt.getDataInputs().size();
							if (size > 0) {
								opt = JOptionPane.showConfirmDialog(null, Resources.get("InfoYesToCreateNewInputOutputOrNoToSelectExistedInputOutput"),
										Resources.get("InfoCreateOrSelect"), JOptionPane.YES_NO_OPTION);
							}
							if (opt == JOptionPane.NO_OPTION) {
								data = (ItemAwareElement) JOptionPane.showInputDialog(null, Resources.get("dataInput"), Resources.get("selectDataInput"),
										JOptionPane.PLAIN_MESSAGE, null, BPMNModelUtils.getDataInOuts(actOrEvent, "selectDataInput").toArray(), null);

							}
							if (data == null) {
								data = evt.addDataInput(dataId);
							}
							da = evt.addDataInputAssociation(cell.getId(), sCell.getId(), data.getId());
						}
					} else if (isItemAwareElement(tCell)) {
						dataId = "Dout" + sCell.getId() + tCell.getId();
						XMLElement actOrEvent = (XMLElement) sCell.getValue();
						if (actOrEvent instanceof Activity) {
							Activity act = (Activity) actOrEvent;
							int size = act.getIoSpecification().getDataOutputs().size();
							if (size > 0) {
								opt = JOptionPane.showConfirmDialog(null, Resources.get("InfoYesToCreateNewInputOutputOrNoToSelectExistedInputOutput"),
										Resources.get("InfoCreateOrSelect"), JOptionPane.YES_NO_OPTION);
							}
							if (opt == JOptionPane.NO_OPTION) {
								data = (ItemAwareElement) JOptionPane.showInputDialog(null, Resources.get("dataOutput"), Resources.get("selectDataOutput"),
										JOptionPane.PLAIN_MESSAGE, null, BPMNModelUtils.getDataInOuts(actOrEvent, "selectDataOutput").toArray(), null);
							}
							if (data == null) {
								data = act.getIoSpecification().addDataOutput(dataId, null, false);
							}
							da = act.addDataOutputAssociation(cell.getId(), data.getId(), tCell.getId());
						} else if (actOrEvent instanceof CatchEvent) {
							CatchEvent evt = (CatchEvent) actOrEvent;
							int size = evt.getDataOutputs().size();
							if (size > 0) {
								opt = JOptionPane.showConfirmDialog(null, Resources.get("InfoYesToCreateNewInputOutputOrNoToSelectExistedInputOutput"),
										Resources.get("InfoCreateOrSelect"), JOptionPane.YES_NO_OPTION);
							}
							if (opt == JOptionPane.NO_OPTION) {
								data = (ItemAwareElement) JOptionPane.showInputDialog(null, Resources.get("dataOutput"), Resources.get("selectDataOutput"),
										JOptionPane.PLAIN_MESSAGE, null, BPMNModelUtils.getDataInOuts(actOrEvent, "selectDataOutput").toArray(), null);

							}
							if (data == null) {
								data = evt.addDataOutput(dataId);
							}
							da = evt.addDataOutputAssociation(cell.getId(), data.getId(), tCell.getId());
						}
					}
					cell.setValue(da);
				} else if ((source instanceof ConversationNode) || (target instanceof ConversationNode)) {
					ConversationLink conversationLink = null;
					Collaboration collaboration = BPMNModelUtils.getCollaboration(bpmnModel);
					if (!(value instanceof ConversationLink)) {
						conversationLink = collaboration.addConversationLink(cell.getId(), ((BaseElement) source).getId(), ((BaseElement) target).getId());
						cell.setValue(conversationLink);
					}
				} else if (source instanceof Participant || target instanceof Participant || !hasSameParentPool(cell.getSource(), cell.getTarget())) {
					Collaboration collaboration = BPMNModelUtils.getCollaboration(bpmnModel);
					MessageFlow messageFlow = collaboration.addMessageFlow(cell.getId(), cell.getSource().getId(), cell.getTarget().getId());
					cell.setValue(messageFlow);
				} else if ((source instanceof FlowNode) && (target instanceof FlowNode)) {
					SequenceFlow sequenceFlow = null;
					FlowElements parent = ((FlowNode) source).getParent();
					if (value instanceof SequenceFlow) {
						sequenceFlow = (SequenceFlow) value;
						FlowElements previousParent = sequenceFlow.getParent();
						if (previousParent != parent) {
							if (previousParent != null) {
								previousParent.remove(cell.getId());
								removeEmptyProcess(previousParent);
							}
						}
					} else {
						for (XMLElement outgoing : ((FlowNode) source).getOutgoings().getXMLElements()) {
							for (XMLElement incoming : ((FlowNode) target).getIncomings().getXMLElements()) {
								if (incoming.toValue() == outgoing.toValue()) {
									sequenceFlow = (SequenceFlow) parent.getFlowElement(incoming.toValue());
									getCells().remove(cell.getId());
									cell.setId(incoming.toValue());
									getCells().put(incoming.toValue(), cell);
									break;
								}
							}
						}
						sequenceFlow = new SequenceFlow(parent);
					}
					sequenceFlow.setId(cell.getId());
					sequenceFlow.setSourceRef(((FlowNode) source).getId());
					sequenceFlow.setTargetRef(((FlowNode) target).getId());
					if (parent != null) {
						parent.add(sequenceFlow);
					}
					cell.setValue(sequenceFlow);
					// for (SequenceFlow outgoing : ((FlowNode) source).getOutgoingSequenceFlows()) {
					// if (outgoing != null && outgoing.getSourceFlowNode() != source) {
					// ((FlowNode) source).removeOutgoing(outgoing.getId());
					// }
					// }
					// for (SequenceFlow incoming : ((FlowNode) target).getIncomingSequenceFlows()) {
					// if (incoming != null && incoming.getTargetFlowNode() != target) {
					// ((FlowNode) target).removeIncoming(incoming.getId());
					// }
					// }
					((FlowNode) source).addOutgoing(sequenceFlow.getId());
					((FlowNode) target).addIncoming(sequenceFlow.getId());
				}
			}
		} else if (previous != null) {
			previous.removeEdge(cell, isSource);
			if (isSource) {
				if (value instanceof SequenceFlow) {
					FlowNode source = (FlowNode) getValue(getCell(((SequenceFlow) value).getSourceRef()));
					if (source != null) {
						source.removeOutgoing(((SequenceFlow) value).getId());
					}
					FlowNode target = (FlowNode) getValue(getCell(((SequenceFlow) value).getTargetRef()));
					if (target != null) {
						target.removeIncoming(((SequenceFlow) value).getId());
					}
				} else if (value instanceof DataAssociation) {
					String sourceRef = ((DataAssociation) value).getSourceRef();
					String targetRef = ((DataAssociation) value).getTargetRef();
					XMLComplexElement parentElement = (XMLComplexElement) ((DataAssociation) value).getParent().getParent();
					if (parentElement instanceof Activity) {
						InputOutputSpecification ios = ((Activity) parentElement).getIoSpecification();
						ios.removeDataInput(targetRef);
						ios.removeDataOutput(sourceRef);
					} else if (parentElement instanceof CatchEvent) {
						((CatchEvent) parentElement).removeDataOutput(sourceRef);
					} else if (parentElement instanceof ThrowEvent) {
						((ThrowEvent) parentElement).removeDataInput(targetRef);
					}
				}
			}
		}

		return previous;
	}

	protected Object valueForCellChanged(Object cell, Object value) {
		Object oldValue = ((mxICell) cell).getValue();
		((mxICell) cell).setValue(value);
		if (oldValue instanceof BaseElement && value instanceof BaseElement) {
			XMLElement parent = ((BaseElement) oldValue).getParent();
			if (parent instanceof XMLCollection) {
				((XMLCollection) parent).add((XMLElement) value);
			}
			if (value instanceof DataOutput) {
				((InputOutputSpecification) parent.getParent()).addDataOutputRef(((BaseElement) value).getId());
			} else if (value instanceof DataInput) {
				((InputOutputSpecification) parent.getParent()).addDataInputRef(((BaseElement) value).getId());
			}
			if (oldValue instanceof DataOutput) {
				((InputOutputSpecification) parent.getParent()).removeDataOutputRef(((BaseElement) oldValue).getId());
			} else if (oldValue instanceof DataInput) {
				((InputOutputSpecification) parent.getParent()).removeDataInputRef(((BaseElement) oldValue).getId());
			}
		}
		return oldValue;
	}

	private void addNodeElements(mxICell child, Object parent) {
		addElement(child, parent);
		for (Object c : getChildVertices(this, child)) {
			addNodeElements((mxICell) c, child);
		}
	}

	private void addElement(mxICell child, Object parent) {
		Object value = getValue(child);
		if (value instanceof BaseElement) {
			XMLElement parentElement = ((BaseElement) value).getParent();
			if (parentElement == null) {
				if (value instanceof Participant) {
					if (child.getStyle().startsWith("participant")) {
						int idx = child.getId().indexOf("_part_");
						String actId = child.getId().substring(0, idx);
						String partId = child.getId().substring(idx + 6);
						Choreography choreography = BPMNModelUtils.getChoreography(bpmnModel);
						if (choreography == null) {
							choreography = bpmnModel.createChoreography();
						}
						((Participant) value).setId(partId);
						choreography.addParticipant((Participant) value);
						XMLElement act = (XMLElement) getValue(getCell(actId));
						if (act instanceof ChoreographyActivity) {
							((ChoreographyActivity) act).addParticipantRef(partId);
						}
						if (act instanceof ChoreographyTask) {
							addMessageFlowForChoreographyTask(choreography, (ChoreographyTask) act);
						}
					} else {
						Collaboration collaboration = BPMNModelUtils.getCollaboration(bpmnModel);
						if (collaboration == null) {
							collaboration = bpmnModel.createCollaboration();
						}
						collaboration.addParticipant((Participant) value);
					}
				} else if (value instanceof ConversationNode) {
					Collaboration collaboration = BPMNModelUtils.getCollaboration(bpmnModel);
					if (collaboration == null) {
						collaboration = bpmnModel.createCollaboration();
					}
					collaboration.addConversationNode((ConversationNode) value);
				} else if (value instanceof Lane) {
					if (getValue(parent) instanceof Participant) {
						BPMNProcess process = bpmnModel.getProcess(((Participant) getValue(parent)).getProcessRef());
						if (process == null) {
							process = bpmnModel.createProcess(false);
							((Participant) getValue(parent)).setProcessRef(process.getId());
						}
						process.addLane((Lane) value);
					} else if (getValue(parent) instanceof Lane) {
						((Lane) getValue(parent)).addChildLane((Lane) value);
					}
				} else if (value instanceof ChoreographyActivity) {
					Choreography choreography = BPMNModelUtils.getChoreography(bpmnModel);
					if (choreography == null) {
						choreography = bpmnModel.createChoreography();
					}
					choreography.addFlowElement((XMLElement) value);
				} else if (value instanceof Message) {
					bpmnModel.addRootElement((XMLElement) value);
					if (isAttachedMessage(child)) {
						MessageFlow messageFlow = (MessageFlow) getValue(child.getParent());
						messageFlow.setMessageRef(child.getId());
					}
				} else if (value instanceof Artifact) {
					Artifacts artifacts = BPMNModelUtils.getArtifacts(bpmnModel);
					if (value instanceof Group) {
						CategoryValue categoryValue = bpmnModel.getDefaultCategoryValue();
						if (categoryValue == null) {
							Category category = null;
							if (bpmnModel.getCategories().isEmpty()) {
								category = (Category) bpmnModel.generateRootElement(RootElements.TYPE_CATEGORY);
								bpmnModel.addRootElement(category);
							} else {
								category = (Category) bpmnModel.getCategories().get(0);
							}
							categoryValue = category.addCategoryValue(Resources.get("group"));
						}
						((Group) value).setCategoryValueRef(categoryValue.getId());
					}
					artifacts.add((XMLElement) value);
				} else if (value instanceof DataInput || value instanceof DataOutput) {
					FlowElementsContainer container = null;
					if (getParent(parent) == getRoot()) {
						container = bpmnModel.getProcess(((mxICell) parent).getId());
						if (container == null) {
							container = BPMNModelUtils.getDefaultProcess(bpmnModel);
						}
						if (container == null) {
							container = bpmnModel.createProcess(BPMNModelUtils.getCollaboration(bpmnModel) == null);
						}
					} else if (getValue(parent) instanceof FlowElementsContainer) {
						container = (FlowElementsContainer) getValue(parent);
					}
					InputOutputSpecification ioSpec = null;
					if (container instanceof BPMNProcess) {
						ioSpec = ((BPMNProcess) container).getIoSpecification();
					} else if (container instanceof SubProcess) {
						ioSpec = ((SubProcess) container).getIoSpecification();
					}
					if (value instanceof DataInput) {
						ioSpec.addDataInput((DataInput) value);
					} else {
						ioSpec.addDataOutput((DataOutput) value);
					}
				} else {
					FlowElementsContainer container = null;
					if (value instanceof BoundaryEvent) {
						container = BPMNModelUtils.getParentProcess((XMLElement) getValue(parent));
						((BoundaryEvent) value).setAttachedToRef(((mxICell) parent).getId());
					} else if (getParent(parent) == getRoot()) {
						container = bpmnModel.getProcess(((mxICell) parent).getId());
						if (container == null) {
							container = BPMNModelUtils.getDefaultProcess(bpmnModel);
						}
						if (container == null) {
							container = bpmnModel.createProcess(BPMNModelUtils.getCollaboration(bpmnModel) == null);
						}
					} else if (getValue(parent) instanceof FlowElementsContainer) {
						container = (FlowElementsContainer) getValue(parent);
					} else if (getValue(parent) instanceof Participant) {
						Participant participant = (Participant) getValue(parent);
						container = bpmnModel.getProcess(participant.getProcessRef());
						if (container == null) {
							container = bpmnModel.createProcess(false);
							participant.setProcessRef(((BaseElement) container).getId());
						}
					} else if (getValue(parent) instanceof Lane) {
						container = BPMNModelUtils.getParentProcess((XMLElement) getValue(parent));
						if (value instanceof FlowNode) {
							((Lane) getValue(parent)).addFlowNodeRef(child.getId());
						}
					}
					if (value instanceof DataStoreReference) {
						DataStore dataStore = null;
						if (bpmnModel.getDataStores().isEmpty()) {
							dataStore = bpmnModel.createDataStore(Resources.get("dataStore"));
						} else {
							dataStore = (DataStore) bpmnModel.getDataStores().get(0);
						}
						((DataStoreReference) value).setDataStoreRef(dataStore.getId());
					} else if (value instanceof CallActivity) {
						String calledElement = ((CallActivity) value).getCalledElement();
						if (child.getStyle().startsWith("callTask")) {
							GlobalTask task = null;
							for (XMLElement gt : bpmnModel.getGlobalTasks(calledElement)) {
								task = (GlobalTask) gt;
								break;
							}
							if (task == null) {
								task = bpmnModel.createGlobalTask(calledElement);
							}
							((CallActivity) value).setCalledElement(task.getId());
						} else {

						}
					} else if (value instanceof DataObject) {
						DataObjectReference dataObjectRef = (DataObjectReference) container.generateFlowElement(FlowElements.TYPE_DATAOBJECT_REFERENCE);
						DataObject dataObject = null;
						for (DataObject obj : container.getFlowElements().getAccessibleDataObjects(((DataObject) value).isCollection())) {
							dataObject = obj;
							break;
						}
						if (dataObject == null) {
							dataObject = (DataObject) value;
							dataObject.setId(dataObjectRef.getId());
						}
						dataObjectRef.setId(child.getId());
						dataObjectRef.setDataObjectRef(dataObject.getId());
						container.addFlowElement(dataObject);
						value = dataObjectRef;
						child.setValue(value);
					}

					if (value instanceof FlowNode) {
						((FlowNode) value).removeIncomingOutgoings();
					}
					container.addFlowElement((XMLElement) value);
				}
			} else if (parentElement instanceof XMLCollection) {
				BPMNProcess process = BPMNModelUtils.getParentProcess(parentElement);
				if (process != null && !((XMLCollection) process.getParent()).contains(process.getId())) {
					((XMLCollection) process.getParent()).add(process);
				}
				if (getValue(parent) instanceof Participant) {
					Participant participant = (Participant) getValue(parent);
					if (participant.getProcessRef().length() == 0) {
						participant.setProcessRef(process.getId());
					}
				} else if (getValue(parent) instanceof Lane) {
					if (value instanceof FlowNode) {
						((Lane) getValue(parent)).addFlowNodeRef(child.getId());
					}
				}
				if (value instanceof Participant) {
					if (child.getStyle().startsWith("participant")) {
						int idx = child.getId().indexOf("_part_");
						String partId = child.getId().substring(idx + 6);
						String actId = child.getId().substring(0, idx);
						((Participant) value).setId(partId);

						Choreography choreography = BPMNModelUtils.getChoreography(bpmnModel);
						XMLElement act = (XMLElement) getValue(getCell(actId));
						if (act instanceof ChoreographyActivity) {
							((ChoreographyActivity) act).addParticipantRef(partId);
						}
						if (act instanceof ChoreographyTask) {
							addMessageFlowForChoreographyTask(choreography, (ChoreographyTask) act);
						}
					}
					if (child.getChildCount() > 0) {
						Object childValue = child.getChildAt(0).getValue();
						if (childValue instanceof BaseElement) {
							bpmnModel.addRootElement(BPMNModelUtils.getParentProcess((XMLElement) childValue));
						}
					}
				} else if (value instanceof Lane) {
					addFlowElementsToProcess(child, process);
				} else if (value instanceof DataInput || value instanceof DataOutput) {
					InputOutputSpecification ioSpec = null;
					FlowElementsContainer container = null;
					if (getParent(parent) == getRoot()) {
						container = bpmnModel.getProcess(((mxICell) parent).getId());
						if (container == null) {
							container = BPMNModelUtils.getDefaultProcess(bpmnModel);
						}
					} else if (getValue(parent) instanceof FlowElementsContainer) {
						container = (FlowElementsContainer) getValue(parent);
					}
					if (container instanceof BPMNProcess) {
						ioSpec = ((BPMNProcess) container).getIoSpecification();
					} else if (container instanceof SubProcess) {
						ioSpec = ((SubProcess) container).getIoSpecification();
					}
					if (value instanceof DataInput) {
						ioSpec.addDataInputRef(((DataInput) value).getId());
					} else {
						ioSpec.addDataOutputRef(((DataOutput) value).getId());
					}
				} else if (value instanceof DataObject) {
					DataObjectReference dataObjectRef = (DataObjectReference) process.generateFlowElement(FlowElements.TYPE_DATAOBJECT_REFERENCE);
					DataObject dataObject = null;
					for (DataObject obj : process.getFlowElements().getAccessibleDataObjects(((DataObject) value).isCollection())) {
						dataObject = obj;
						break;
					}
					if (dataObject == null) {
						dataObject = (DataObject) value;
						dataObject.setId(dataObjectRef.getId());
					}
					dataObjectRef.setId(child.getId());
					dataObjectRef.setDataObjectRef(dataObject.getId());
					process.addFlowElement(dataObject);
					value = dataObjectRef;
					child.setValue(value);
				}
				((XMLCollection) parentElement).add((XMLElement) value);
			}
		}
	}

	private void addMessageFlowForChoreographyTask(Choreography choreography, ChoreographyTask ct) {
		String initPartId = ct.getInitiatingParticipantRef();
		ct.clearMessageFlowRefs();

		if (initPartId.length() != 0) {
			for (XMLElement participantRef : ct.getParticipantRefList()) {
				if (!initPartId.equals(participantRef.toValue())) {
					String id = choreography.getId() + initPartId + participantRef.toValue();
					choreography.addMessageFlow(id, initPartId, participantRef.toValue());
					ct.addMessageFlowRef(id);
					id = choreography.getId() + participantRef.toValue() + initPartId;
					choreography.addMessageFlow(id, participantRef.toValue(), initPartId);
					ct.addMessageFlowRef(id);
				}
			}
		}

		for (XMLElement mf : choreography.getMessageFlowList()) {
			if (!BPMNModelUtils.hasMessageFlowRef(choreography, ((MessageFlow) mf).getId())) {
				choreography.getMessageFlows().remove(((MessageFlow) mf).getId());
			}
		}
	}

	private void addFlowElementsToProcess(Object child, BPMNProcess process) {
		for (Object c : getChildren(this, child)) {
			Object v = getValue(c);
			if (v instanceof Lane) {
				addFlowElementsToProcess(c, process);
			} else if (v instanceof BaseElement) {
				process.addFlowElement((XMLElement) v);
			}
		}
	}

	private void removeEmptyProcess(XMLElement bpmnElement) {
		BPMNProcess process = BPMNModelUtils.getParentProcess(bpmnElement);
		if (process != null && process.isEmptyProcess() && !BPMNModelUtils.hasProcessRef(bpmnModel, process.getId())) {
			((XMLCollection) process.getParent()).remove(process.getId());

			Participant participant = BPMNModelUtils.getParticipantByProcessId(process.getId(), bpmnModel);
			if (participant != null) {
				participant.setProcessRef("");
			}
		}
	}

}