Newer
Older
MagnetRON / src / org / ntlab / deltaViewer / DeltaViewer.java
package org.ntlab.deltaViewer;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JFrame;

import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.DirectedWeightedPseudograph;
import org.ntlab.deltaExtractor.Alias;
import org.ntlab.deltaExtractor.Delta;
import org.ntlab.deltaExtractor.ExtractedStructure;
import org.ntlab.deltaViewer.Edge.TypeName;
import org.ntlab.deltaExtractor.Alias.AliasType;
import org.ntlab.trace.ArrayAccess;
import org.ntlab.trace.FieldAccess;
import org.ntlab.trace.FieldUpdate;
import org.ntlab.trace.MethodExecution;
import org.ntlab.trace.MethodInvocation;
import org.ntlab.trace.Reference;
import org.ntlab.trace.Statement;

import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxICell;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxPoint;
import com.mxgraph.view.mxGraphView;

/**
 * Make and display JGraph of extracted delta.
 * 
 * @author Nitta Lab.
 */
//TASK: bArray O
//Careful: Parent
//BUG: methodExecution Id. O
//BUG: Move ObjectVertex position sometimes. O
//BUG: Resize ObjectVertex sometimes. O
//BUG: finally field refrence.
//BUG: edge drawing order. -> parent
public class DeltaViewer {
    private static Dimension DEFAULT_SIZE = new Dimension(700, 700);
    private static String WINDOW_TITLE = "Delta Viewer";

    private ExtractedStructure eStructure;
    private DeltaAliasCollector deltaAliasCollector;
    private List<Alias> aliasList;
	
	private Map<String, VertexObject> objectToVertexMap = new HashMap<>();
	private Map<MethodExecution, VertexMethodExecution> methodExecToVertexMap = new LinkedHashMap<>();
	private Map<String, Edge> edgeMap = new HashMap<>();
	
	private JFrame frame;
	private DeltaGraphAdapter mxgraph;
	// No clue what this does but it is needed.
	private mxICell mxDefaultParent;

	private mxGraphComponent mxgraphComponent;
	
	private int curNumFrame = 0;
    private static Dimension VERTEX_OBJECT_SIZE = new Dimension(70, 70);
    private static Dimension VERTEX_METHOD_EXECUTION_SIZE = new Dimension(55, 20);
    private mxPoint coordinatorPoint = new mxPoint(DEFAULT_SIZE.getWidth() / 2 - 50, 100);

    private DeltaAnimation deltaAnimation;
    
    private double scale = 1;
    
	public DeltaViewer() {
    	mxgraph = new DeltaGraphAdapter(new DirectedWeightedPseudograph(DefaultEdge.class));
    	mxDefaultParent = (mxCell)mxgraph.getDefaultParent();
    	mxgraphComponent = new mxGraphComponent(mxgraph);    
    	deltaAnimation = new DeltaAnimation(mxgraph, mxgraphComponent);
	}

	public DeltaViewer(ExtractedStructure extractedStructure, DeltaAliasCollector deltaAliasCollector) {
		this();
		this.eStructure = extractedStructure;
		this.deltaAliasCollector = deltaAliasCollector;
		aliasList = new ArrayList<>(deltaAliasCollector.getAliasList());
//    	init();
	}
	
	/** Initialize JFrame, make vertex object and edge object. */
	public void init() {
		// Build a frame, create a graph, and add the graph to the frame so you can actually see the graph.
		if(eStructure != null) {
			WINDOW_TITLE = "extract delta of:" + eStructure.getDelta().getSrcSide().get(0).getDstClassName() + "(" + eStructure.getDelta().getSrcSide().get(0).getDstObjectId() + ")" + " -> " + eStructure.getDelta().getDstSide().get(0).getDstClassName()  + "(" + eStructure.getDelta().getDstSide().get(0).getDstObjectId() + ")";
		}

    	frame = new JFrame(WINDOW_TITLE);
    	frame.setSize(DEFAULT_SIZE);
    	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    	frame.add(mxgraphComponent, BorderLayout.CENTER);
    	frame.setVisible(true);
    	
		System.out.println(eStructure.getDelta().getDstSide());

		while(coordinatorPoint.getX() - (150 * (eStructure.getDelta().getDstSide().size())) < 0) {
			coordinatorPoint.setX(coordinatorPoint.getX() + 150);
		}
		
    	makeVertexObjects();
		makeEdgeObject();

		// Fit graph size in visible JFrame.
		mxGraphView view = mxgraphComponent.getGraph().getView();
		int componentWidth = mxgraphComponent.getWidth();
		int viewWidth = (int) view.getGraphBounds().getWidth();
		scale = (double)componentWidth/viewWidth;
		view.setScale(scale);
		deltaAnimation.setScale(scale);
		System.out.println(componentWidth + ", " + viewWidth + ", " + scale);
		update();
	}
	
	/** Display graph on JFrame. */
	public void update() {
		setCellStyles();
    	mxgraphComponent.refresh();
		try {
			System.out.println("updateThread.sleep()");
			Thread.sleep(1000);
			System.out.println("updateThread.start()");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
    }
	
	public void setExtractedStructure(ExtractedStructure extractedStructure) {
		this.eStructure = extractedStructure;
	}
	
	public void setDeltaAliasCollector(DeltaAliasCollector deltaAliasCollector) {
		this.deltaAliasCollector = deltaAliasCollector;
	}
	
	public void setFrameSize(int width, int height) {
		DEFAULT_SIZE.setSize(width, height);
	}

	public void setCoordinatorPoint(double x, double y) {
		coordinatorPoint.setX(x);
		coordinatorPoint.setY(y);
	}
	
	/** Set cell styles. */
    private void setCellStyles() {
    	List<Object> vertexObject = new ArrayList<>();
    	List<Object> alignMiddleVertex = new ArrayList<>();
    	List<Object> alignTopVertex = new ArrayList<>();
    	List<Object> edgeObject = new ArrayList<>();
    	List<Object> edgeMethodExec = new ArrayList<>();
    	List<Object> roundEdge = new ArrayList<>();

    	for (VertexObject vertex: objectToVertexMap.values()) {
			vertexObject.add(vertex.getCell());
			if(vertex.getVertexMethodExecutions().size() == 0) {
				alignMiddleVertex.add(vertex.getCell());
			} else {
				alignTopVertex.add(vertex.getCell());
			}
    	}
    	
    	List<VertexMethodExecution> vertexMethodExecList = new ArrayList<>(methodExecToVertexMap.values());
    	Collections.reverse(vertexMethodExecList);
    	for (int i = 0; i < vertexMethodExecList.size(); i++) {
    		switch(i) {
			case 0:
	        	((mxICell)vertexMethodExecList.get(i).getCell()).setStyle("fillColor=#ff7fbf");
				break;
			case 1:
	        	((mxICell)vertexMethodExecList.get(i).getCell()).setStyle("fillColor=#ff99cc");
				break;
			case 2:
	        	((mxICell)vertexMethodExecList.get(i).getCell()).setStyle("fillColor=#ffb2d8");
				break;
			case 3:
	        	((mxICell)vertexMethodExecList.get(i).getCell()).setStyle("fillColor=#ffcce5");
				break;
			case 4:
	        	((mxICell)vertexMethodExecList.get(i).getCell()).setStyle("fillColor=#ffe0ef");
				break;
			default:
				break;
    		}
    	}
    	
    	for (Edge edge: edgeMap.values()) {
    		roundEdge.add(edge.getCell());
    		switch(edge.getTypeName()) {
    		case Reference:
    			edgeObject.add(edge.getCell());
    			break;
    		case Call:
    			edgeMethodExec.add(edge.getCell());
    			break;
    		default:
    			break;
    		}
    	}
    	/*Given a cell, we can change it's style attributes, for example the color. NOTE that you have to call the graphComponent.refresh() function, otherwise you won't see the difference! */
    	mxgraph.setCellStyles(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_ELLIPSE, vertexObject.toArray(new Object[vertexObject.size()]));
    	mxgraph.setCellStyles(mxConstants.STYLE_PERIMETER, mxConstants.PERIMETER_ELLIPSE, vertexObject.toArray(new Object[vertexObject.size()]));
    	mxgraph.setCellStyleFlags(mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_UNDERLINE, true, vertexObject.toArray(new Object[vertexObject.size()]));
    	mxgraph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE, alignMiddleVertex.toArray(new Object[alignMiddleVertex.size()]));
    	mxgraph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_TOP, alignTopVertex.toArray(new Object[alignTopVertex.size()]));
    	mxgraph.setCellStyles(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_TOPTOBOTTOM, edgeObject.toArray(new Object[edgeObject.size()]));
//    	mxgraph.setCellStyles(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_ENTITY_RELATION, edgeObject.toArray(new Object[edgeObject.size()]));
//    	mxgraph.setCellStyles(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_ORTHOGONAL, edgeObject.toArray(new Object[edgeObject.size()]));
    	mxgraph.setCellStyleFlags(mxConstants.STYLE_ROUNDED, 1, true, roundEdge.toArray(new Object[roundEdge.size()]));
    	mxgraph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_TOP, roundEdge.toArray(new Object[roundEdge.size()]));
    	mxgraph.setCellStyles(mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_BOTTOM, roundEdge.toArray(new Object[roundEdge.size()]));
//    	mxgraph.setCellStyles(mxConstants.STYLE_EDGE, mxConstants.SHAPE_CURVE, edgeObject.toArray(new Object[edgeObject.size()]));
    	mxgraph.setCellStyles(mxConstants.STYLE_STROKECOLOR, "#008000", edgeMethodExec.toArray(new Object[edgeMethodExec.size()]));
    	mxgraph.setCellStyleFlags(mxConstants.STYLE_DASHED, 1, true, edgeMethodExec.toArray(new Object[edgeMethodExec.size()]));
//    	mxgraph.setCellStyleFlags(mxConstants.STYLE_AUTOSIZE, 1, true, vertexObject.toArray(new Object[vertexObject.size()]));
//    	mxgraph.setCellStyles(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_ORTHOGONAL, edgeMethodExec.toArray(new Object[edgeMethodExec.size()]));
//    	mxgraph.setCellStyles(mxConstants.STYLE_ELBOW, mxConstants.ELBOW_VERTICAL, edgeMethodExec.toArray(new Object[edgeMethodExec.size()]));
    }

	private double getXForCell(String id) {
        double res = -1;
        if (objectToVertexMap.containsKey(id)) {
		    Object cell = objectToVertexMap.get(id).getCell();
		    res = mxgraph.getCellGeometry(cell).getX();
        }
        return res;
    }
	
	private double getYForCell(String id) {
        double res = -1;
        if (objectToVertexMap.containsKey(id)) {
	        Object cell = objectToVertexMap.get(id).getCell();
	        res = mxgraph.getCellGeometry(cell).getY();
        }
        return res;
    }

	private mxICell getRootParentCell(Object object) {
		mxICell cell = (mxICell) object;
		if(cell.getParent().getValue() == null) {
			return cell;
		}
		return getRootParentCell(cell.getParent());
	}
	
	private Point getAbsolutePointforCell(Object object) {
		mxICell cell = (mxICell) object;
		Point p1 = cell.getGeometry().getPoint();
		if(cell.getParent().getValue() == null) {
			return p1;
		}
		Point p2 = getAbsolutePointforCell(cell.getParent());
		return new Point((int) (p1.getX() + p2.getX()), (int) (p1.getY() + p2.getY()));
	}
	
	/**
	 * Step to animation of specified alias. 
	 * 
	 * @param alias Alias type and occurance point etc.
	 */
	public void stepToAnimation(Alias alias) {
	     try {
	 		stepToAnimation(aliasList.indexOf(alias));
	    } catch (IndexOutOfBoundsException e) {
	    	stepToAnimation(-1);	
	    }
	}

	/**
	 * Parent : Step to animation of specified numFrame.
	 * 
	 * @param numFrame Current animation frame.
	 */
	public void stepToAnimation(int numFrame) {
	     try {
	    	 Alias alias = aliasList.get(numFrame);
	 		doAnimation(aliasList.get(curNumFrame), alias);
			curNumFrame = aliasList.indexOf(alias) + 1;
	    } catch (IndexOutOfBoundsException e) {
	    	if (numFrame == - 1) {
	    		System.out.println("ERROR : Not exist alias.");
	    	} else {
				System.out.println("\r\nLast Animation.");
	    		doLastAnimation(aliasList.get(aliasList.size() - 1));	
	    	}
	    }
	}
	
	/**
	 * Do animation from fromAlias to toAlias.
	 * 
	 * @param fromAlias 
	 * @param toAlias
	 */
	private void doAnimation(Alias fromAlias, Alias toAlias) {
		for (int i = aliasList.indexOf(fromAlias); i <= aliasList.indexOf(toAlias); i++) {
			Alias alias = aliasList.get(i);
			System.out.println("\r\n" + i + ": " + alias.getObjectId() + ", " + alias.getMethodSignature() + " l." + alias.getLineNo() + " : " + alias.getAliasType().toString());
			switch(alias.getAliasType()) {
			case RETURN_VALUE:
				moveObjectVertex(alias);
				update();
				break;
			case METHOD_INVOCATION:
				removeVertexMethodExecution(alias);
				moveObjectVertex(alias);
				update();
				break;
			case CONSTRACTOR_INVOCATION:
				Object vertex = objectToVertexMap.get(alias.getObjectId()).getCell();
				((mxICell)vertex).setStyle("fillColor=#ffffff;strokeColor=#194bff;");
				((mxICell)vertex).setValue(((mxICell)vertex).getId());	
				update();
				break;
			case FORMAL_PARAMETER:
				moveObjectVertex(alias);
				update();
				break;
			case ACTUAL_ARGUMENT:
				moveObjectVertex(alias);
				update();
				break;
			case THIS:
				if (curNumFrame == 0) {
					makeVertexMethodExecution(alias);
					update();
				}
				break;
			case RECEIVER:
				// Make VertexMethodExecution of called method execution.
				MethodExecution calledMethodExec = ((MethodInvocation) alias.getOccurrencePoint().getStatement()).getCalledMethodExecution();
				if (!methodExecToVertexMap.containsKey(calledMethodExec)) {
					makeVertexMethodExecution(alias, calledMethodExec.getSignature(), calledMethodExec);
					update();
				}
				break;
			default:
				break;
			}
		}
	}
	
	/**
	 * Make last animation of extracted delta.
	 * 
	 * @param alias Last index alias.
	 */
	private void doLastAnimation(Alias alias) {
		// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
		mxgraph.getModel().beginUpdate();
		try {
			// Make ObjectEdge and reset position of vertexObject, remove vertexMethodExecution.
			for(Statement statement: alias.getMethodExecution().getStatements()) {
				if(statement instanceof FieldUpdate) {
					FieldUpdate fieldUpdateStatement = (FieldUpdate) statement;
//					String fieldNames[] = fieldUpdateStatement.getFieldName().split("\\.");
//					String fieldName = fieldNames[fieldNames.length-1];
					String fieldNames[] = formatFieldName(fieldUpdateStatement.getFieldName());
					String fieldName = fieldNames[fieldNames.length-1];
					String sourceObjectId = fieldUpdateStatement.getContainerObjId();
					String targetObjectId = fieldUpdateStatement.getValueObjId();
					mxICell sourceCell = (mxICell)objectToVertexMap.get(sourceObjectId).getCell();
					mxICell targetCell = (mxICell)objectToVertexMap.get(targetObjectId).getCell();
					Point absolutePointTargetCell = getAbsolutePointforCell(targetCell);
					show(mxDefaultParent);
					targetCell.getParent().remove(targetCell);
					targetCell.setParent(mxDefaultParent);
					targetCell.getGeometry().setX(absolutePointTargetCell.getX());
					targetCell.getGeometry().setY(absolutePointTargetCell.getY());
					Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, fieldUpdateStatement.getFieldName(), fieldName, objectToVertexMap.get(sourceObjectId).getCell(), objectToVertexMap.get(targetObjectId).getCell());
	    			((mxCell)edge).setStyle("exitX=0;exitY=0.5;exitPerimeter=1;entryX=1;entryY=0.5;entryPerimeter=1;");
	    			edgeMap.put(fieldUpdateStatement.getFieldName(), new Edge(fieldName, TypeName.Reference, edge));
//					System.out.println("last" + objectToVertexMap.get(targetObjectId).getInitialX() + ", " + objectToVertexMap.get(targetObjectId).getInitialY());
					deltaAnimation.setVertexAnimation(targetCell, new mxPoint(objectToVertexMap.get(targetObjectId).getInitialX(), objectToVertexMap.get(targetObjectId).getInitialY()));
					deltaAnimation.startVertexAnimation();
					targetCell.getGeometry().setX(objectToVertexMap.get(targetObjectId).getInitialX());
					targetCell.getGeometry().setY(objectToVertexMap.get(targetObjectId).getInitialY());
		    		removeCalledVertexMethodExecution(objectToVertexMap.get(sourceObjectId), alias.getMethodExecution().getCallerMethodExecution(), alias.getMethodExecution());
		    		updateVertexObjectSize();
				}
			}
		} finally {
			  mxgraph.getModel().endUpdate();
		}

		// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
		mxgraph.getModel().beginUpdate();
		try {
			List<MethodExecution> methodExecList = new ArrayList<>(methodExecToVertexMap.keySet());
			System.out.println(methodExecToVertexMap.size());
	    	Collections.reverse(methodExecList);
	    	for(int i = 0; i < methodExecList.size(); i++) {
	    		String objectId = methodExecList.get(i).getThisObjId();
	    		VertexObject sourceVertexObject = objectToVertexMap.get(objectId); // sourceVertex
	    		MethodExecution methodExec = methodExecList.get(i);
	    		if (i != methodExecList.size()-1) {
	    			for(Statement statement: methodExec.getStatements()) {
		    			if(statement instanceof MethodInvocation) {
		    	    		MethodExecution calledMethodExec = ((MethodInvocation) statement).getCalledMethodExecution();
		    	    		String calledObjectId = calledMethodExec.getThisObjId();
							mxICell calledCell = (mxICell)objectToVertexMap.get(calledObjectId).getCell();
							Point absolutePointCalledCell = getAbsolutePointforCell(calledCell);
							System.out.println(objectId + ", " + methodExec.getSignature());
	//	    	    		objectToVertexMap.get(calledObjectId).resetCellPosition();
							if (methodExecToVertexMap.get(methodExec).getArguments().contains(objectToVertexMap.get(calledObjectId)) || methodExecToVertexMap.get(methodExec).getLocals().contains(objectToVertexMap.get(calledObjectId))) {
			    				calledCell.getParent().remove(calledCell);
								calledCell.setParent(mxDefaultParent);
								calledCell.getGeometry().setX(absolutePointCalledCell.getX());
								calledCell.getGeometry().setY(absolutePointCalledCell.getY());
								deltaAnimation.setVertexAnimation(calledCell, new mxPoint(objectToVertexMap.get(calledObjectId).getInitialX(), objectToVertexMap.get(calledObjectId).getInitialY()));
								deltaAnimation.startVertexAnimation();
							}
				    		removeCalledVertexMethodExecution(sourceVertexObject, methodExec.getCallerMethodExecution(), methodExec);
				    		updateVertexObjectSize();
	//			    		removeVertexMethodExecution(sourceVertexObject, methodExec);
	//	    				update();
		    				break;
		    			}
		    		}
	    		}  else {
	    			List<VertexObject> arguments = new ArrayList<>(methodExecToVertexMap.get(methodExec).getArguments());
	    			List<VertexObject> locals = new ArrayList<>(methodExecToVertexMap.get(methodExec).getLocals());
	    			if (arguments.size() != 0) {
	    				for (VertexObject vo: arguments) {
	    					mxICell cell = (mxICell)vo.getCell();
	    					Point absolutePointCell = getAbsolutePointforCell(cell);
	    					cell.getParent().remove(cell);
	    					cell.setParent(mxDefaultParent);
	    					cell.getGeometry().setX(absolutePointCell.getX());
	    					cell.getGeometry().setY(absolutePointCell.getY());
							deltaAnimation.setVertexAnimation(cell, new mxPoint(vo.getInitialX(), vo.getInitialY()));
							deltaAnimation.startVertexAnimation();
							methodExecToVertexMap.get(methodExec).getArguments().remove(vo);
	    				}
	    			}else if (locals.size() != 0) {
	    				for (VertexObject vo: locals) {
	    					mxICell cell = (mxICell)vo.getCell();
	    					Point absolutePointCell = getAbsolutePointforCell(cell);
	    					cell.getParent().remove(cell);
	    					cell.setParent(mxDefaultParent);
	    					cell.getGeometry().setX(absolutePointCell.getX());
	    					cell.getGeometry().setY(absolutePointCell.getY());
							deltaAnimation.setVertexAnimation(cell, new mxPoint(vo.getInitialX(), vo.getInitialY()));
							deltaAnimation.startVertexAnimation();
							methodExecToVertexMap.get(methodExec).getLocals().remove(vo);
	    				}
	    			}
		    		updateVertexObjectSize();	    			
	    		}
	    	}
		} finally {
			  mxgraph.getModel().endUpdate();
		}
		update();
	}

	/** Make VertexObjects. */
	private void makeVertexObjects() {    	
    	//Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
		// ����(0, 0)
    	double xCor = coordinatorPoint.getX();
		double yCor = coordinatorPoint.getY();
		double time = 150;

		mxgraph.getModel().beginUpdate();
    	try {
			// Draw vertex object.
    		// srcSide
			Delta delta = eStructure.getDelta();
			int srcSideSize = delta.getSrcSide().size();
			for (int i = srcSideSize - 1; i >= 0; i--) {
				Reference ref = delta.getSrcSide().get(i);
				System.out.println("srcSide: " + ref.getSrcClassName() + ", " + ref.isCreation());
				if (!ref.isCreation() && !ref.getSrcObjectId().equals(ref.getDstObjectId())) {
					if(!objectToVertexMap.containsKey(ref.getSrcObjectId())) {
						String srcClassName = ref.getSrcClassName();
						if (srcClassName.contains("[L")) {
							srcClassName = formatArrayName(srcClassName);
						}
						Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, ref.getSrcClassName(), srcClassName, xCor + (time * ((srcSideSize - 1) - i)), yCor + (time * ((srcSideSize - 1) - i)), VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 
				    	objectToVertexMap.put(ref.getSrcObjectId(), new VertexObject(ref.getSrcClassName(), vertex, xCor + (time * ((srcSideSize - 1) - i)), yCor + (time * ((srcSideSize - 1) - i))));
					}
					if(!objectToVertexMap.containsKey(ref.getDstObjectId())) {
//						System.out.println(ref.getDstClassName() + ", " + ref.isCreation());
						String dstClassName = ref.getDstClassName();
						if (dstClassName.contains("[L")) {
							dstClassName = formatArrayName(dstClassName);
						}
						Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, ref.getDstClassName(), dstClassName, xCor + (time * (srcSideSize - i)), yCor + (time * (srcSideSize - i)), VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 		
						objectToVertexMap.put(ref.getDstObjectId(), new VertexObject(ref.getDstClassName(), vertex, xCor + (time * (srcSideSize - i)), yCor + (time * (srcSideSize - i))));
					}
				}
			}

			// dstSide
			int dstSideSize = delta.getDstSide().size();
			for (int i = dstSideSize - 1; i >= 0; i--) {
				Reference ref = delta.getDstSide().get(i);
//				System.out.println("dstSide: " + ref.getDstClassName() + ", " + ref.isCreation());
				if (!ref.isCreation() && !ref.getSrcObjectId().equals(ref.getDstObjectId())) {
					String dstClassName = ref.getDstClassName();
					if (dstClassName.contains("[L")) {
						dstClassName = formatArrayName(dstClassName);
					}
					Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, ref.getDstClassName(), dstClassName, xCor - (time * (dstSideSize - i)), yCor + (time * (dstSideSize - i)), VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 
					objectToVertexMap.put(ref.getDstObjectId(), new VertexObject(ref.getDstClassName(), vertex, xCor - (time * (dstSideSize - i)), yCor + (time * (dstSideSize - i))));
				} else {
					Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, ref.getDstClassName(), ref.getDstClassName(), xCor - (time * (dstSideSize - i)), yCor + (time * (dstSideSize - i)), VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 
					objectToVertexMap.put(ref.getDstObjectId(), new VertexObject(ref.getDstClassName(), vertex, xCor - (time * (dstSideSize - i)), yCor + (time * (dstSideSize - i))));
					((mxICell)vertex).setStyle("fillColor=none;strokeColor=none;");
					((mxICell)vertex).setValue(null);					
				}
			}
    	} finally {
    		  mxgraph.getModel().endUpdate();
      	}
    }
		
	/**
	 * SourceVertex move targetVertex.
	 * 
	 * @param alias
	 */
	private void moveObjectVertex(Alias alias) {
		// sourceVertex
		VertexObject sourceVertexObject = objectToVertexMap.get(alias.getObjectId());
		// targetVertex
		VertexMethodExecution targetVertexMethodExec = methodExecToVertexMap.get(alias.getMethodExecution());
		
		moveObjectVertex(alias, sourceVertexObject, targetVertexMethodExec);
		updateVertexObjectSize();
	}

	/**
	 * Parent : Source VertexObject move target VertexMethodExecution.
	 * 
	 * @param alias
	 * @param sourceVertexObject Source VertexObject.
	 * @param targetVertexMethodExec Target VertexMethodExecution.
	 */
	private void moveObjectVertex(Alias alias, VertexObject sourceVertexObject, VertexMethodExecution targetVertexMethodExec) {
		MethodExecution methodExec = alias.getMethodExecution();
		if (alias.getAliasType().equals(AliasType.RETURN_VALUE) || alias.getAliasType().equals(AliasType.METHOD_INVOCATION)) {
			moveLocalObjectVertex(methodExec, sourceVertexObject, targetVertexMethodExec);
		} else if (alias.getAliasType().equals(AliasType.FORMAL_PARAMETER)) {
			moveArgumentObjectVertex(methodExec, sourceVertexObject, targetVertexMethodExec);
		} else if (alias.getAliasType().equals(AliasType.ACTUAL_ARGUMENT)) {
			moveActualArgumentObjectVertex(methodExec, sourceVertexObject, targetVertexMethodExec);			
		}
	}

	/**
	 * Source VertexObject move target VertexMethodExecution to Local position from caller MethodExecution.
	 * 
	 * @param callerMethodExec Caller MethodExecution.
	 * @param sourceVertexObject
	 * @param targetVertexMethodExec
	 */
	private void moveLocalObjectVertex(MethodExecution callerMethodExec, VertexObject sourceVertexObject, VertexMethodExecution targetVertexMethodExec) {
		mxICell sourceCell = (mxICell)sourceVertexObject.getCell();
		mxICell targetCell = (mxICell) targetVertexMethodExec.getCell();
//		mxICell parentTargetMethodExecCell = targetMethodExecCell.getParent();

		//  Remove sourceVertex from Locals and Arguments Vertex of MethodExecution's Vertex.  
//		MethodExecution callercallerMethodExec = callerMethodExec.getCallerMethodExecution();	
		System.out.println(callerMethodExec.getSignature());
//		if (methodExecToVertexMap.containsKey(callercallerMethodExec) && methodExecToVertexMap.get(callercallerMethodExec).getLocals().contains(sourceVertexObject)) {
//			methodExecToVertexMap.get(callercallerMethodExec).getLocals().remove(sourceVertexObject);
//			System.out.println(methodExecToVertexMap.get(callercallerMethodExec).getLabel() + " :removeLocal: " + sourceVertexObject.getLabel());
//		}
//
//		if (methodExecToVertexMap.containsKey(callercallerMethodExec) && methodExecToVertexMap.get(callercallerMethodExec).getArguments().contains(sourceVertexObject)) {
//			methodExecToVertexMap.get(callercallerMethodExec).getArguments().remove(sourceVertexObject);
//			System.out.println(methodExecToVertexMap.get(callercallerMethodExec).getLabel() + " :removeArgument: " + sourceVertexObject.getLabel());
//		}
		if (methodExecToVertexMap.containsKey(callerMethodExec) && methodExecToVertexMap.get(callerMethodExec).getLocals().contains(sourceVertexObject)) {
			methodExecToVertexMap.get(callerMethodExec).getLocals().remove(sourceVertexObject);
			System.out.println(methodExecToVertexMap.get(callerMethodExec).getLabel() + " :removeLocal: " + sourceVertexObject.getLabel());
		}

		if (methodExecToVertexMap.containsKey(callerMethodExec) && methodExecToVertexMap.get(callerMethodExec).getArguments().contains(sourceVertexObject)) {
			methodExecToVertexMap.get(callerMethodExec).getArguments().remove(sourceVertexObject);
			System.out.println(methodExecToVertexMap.get(callerMethodExec).getLabel() + " :removeArgument: " + sourceVertexObject.getLabel());
		}

		// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.   	
		mxgraph.getModel().beginUpdate();
		try {
			int time = targetVertexMethodExec.getLocals().size() + 1;
			double sourceX = sourceCell.getGeometry().getX();
			double sourceY = sourceCell.getGeometry().getY();

//			System.out.println(time);
			
			if(sourceCell.getParent().getValue() != null) {
				Point absolutePointSourceCell = getAbsolutePointforCell(sourceCell);
				sourceX = absolutePointSourceCell.getX();
				sourceY = absolutePointSourceCell.getY();
				sourceCell.getParent().remove(sourceCell);
			}
			
			sourceCell.setParent(targetCell.getParent());
			targetCell.getParent().insert(sourceCell);
			
			Point absolutePointTargetCell = getAbsolutePointforCell(sourceCell.getParent());
			sourceCell.getGeometry().setX(sourceX - absolutePointTargetCell.getX());
			sourceCell.getGeometry().setY(sourceY - absolutePointTargetCell.getY());

			double sourceWidth = sourceCell.getGeometry().getWidth();
			double sourceHeight = sourceCell.getGeometry().getHeight();
			double overlapWidth = sourceWidth - (sourceWidth * Math.sqrt(2) * 0.1);
			double overlapHeight = sourceHeight  - (sourceHeight * Math.sqrt(2) * 0.1);

			deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() - overlapWidth, targetCell.getGeometry().getY()  - overlapHeight + (sourceHeight * time)));
			deltaAnimation.startVertexAnimation();

			sourceCell.setParent(targetCell.getParent());
			targetCell.getParent().insert(sourceCell);
			sourceCell.getGeometry().setX(targetCell.getGeometry().getX() - overlapWidth);
			sourceCell.getGeometry().setY(targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time));
			targetVertexMethodExec.getLocals().add(sourceVertexObject);
			System.out.println("moveLocalObjectVertex: " + targetVertexMethodExec.getLabel() + " :Local: " + sourceVertexObject.getLabel());
		} finally {
			  mxgraph.getModel().endUpdate();
		}
	}
	
	/**
	 * Source VertexObject move target VertexMethodExecution to Argument position from MethodExecution.
	 * 
	 * @param methodExec MethodExecution.
	 * @param sourceVertexObject
	 * @param targetVertexMethodExec
	 */
	private void moveArgumentObjectVertex(MethodExecution methodExec, VertexObject sourceVertexObject, VertexMethodExecution targetVertexMethodExec) {
		mxICell sourceCell = (mxICell)sourceVertexObject.getCell();
		mxICell targetCell = (mxICell) targetVertexMethodExec.getCell();
//		mxICell parentTargetMethodExecCell = targetMethodExecCell.getParent();

		//  Remove sourceVertex from Locals and Arguments Vertex of MethodExecution's Vertex.  
		MethodExecution callerMethodExecution = methodExec.getCallerMethodExecution();
		if (methodExecToVertexMap.containsKey(callerMethodExecution) && methodExecToVertexMap.get(callerMethodExecution).getLocals().contains(sourceVertexObject)) {
			methodExecToVertexMap.get(callerMethodExecution).getLocals().remove(sourceVertexObject);
			System.out.println(methodExecToVertexMap.get(callerMethodExecution).getLabel() + " :removeLocal: " + sourceVertexObject.getLabel());
		}

		if (methodExecToVertexMap.containsKey(callerMethodExecution) && methodExecToVertexMap.get(callerMethodExecution).getArguments().contains(sourceVertexObject)) {
			methodExecToVertexMap.get(callerMethodExecution).getArguments().remove(sourceVertexObject);
			System.out.println(methodExecToVertexMap.get(callerMethodExecution).getLabel() + " :removeArgument: " + sourceVertexObject.getLabel());
		}

		// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
		mxgraph.getModel().beginUpdate();
		try {
			int time = targetVertexMethodExec.getArguments().size();
			double sourceX = sourceCell.getGeometry().getX();
			double sourceY = sourceCell.getGeometry().getY();

//			System.out.println(time);

			if(sourceCell.getParent().getValue() != null) {
				Point absolutePointSourceCell = getAbsolutePointforCell(sourceCell);
				sourceX = absolutePointSourceCell.getX();
				sourceY = absolutePointSourceCell.getY();
				sourceCell.getParent().remove(sourceCell);
			}
			
			sourceCell.setParent(targetCell.getParent());
			targetCell.getParent().insert(sourceCell);
			sourceCell.getGeometry().setX(sourceX - sourceCell.getParent().getGeometry().getX());
			sourceCell.getGeometry().setY(sourceY - sourceCell.getParent().getGeometry().getY());

			double sourceWidth = sourceCell.getGeometry().getWidth();
			double sourceHeight = sourceCell.getGeometry().getHeight();
			double overlapWidth = sourceWidth - (sourceWidth * Math.sqrt(2) * 0.1);
			double overlapHeight = sourceHeight - (sourceHeight * Math.sqrt(2) * 0.1);
			
			deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() - overlapWidth, targetCell.getGeometry().getY()  - overlapHeight + (sourceHeight * time)));
			deltaAnimation.startVertexAnimation();

//			sourceCell.setParent(targetCell.getParent());
//			targetCell.getParent().insert(sourceCell);
			sourceCell.getGeometry().setX(targetCell.getGeometry().getX() - overlapWidth);
			sourceCell.getGeometry().setY(targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time));
			targetVertexMethodExec.getArguments().add(sourceVertexObject);			
			System.out.println("moveArgumentObejctVertex" + targetVertexMethodExec.getLabel() + " :Argument: " + sourceVertexObject.getLabel());
		} finally {
			  mxgraph.getModel().endUpdate();
		}
	}
	
	/**
	 * Source VertexObject move target VertexMethodExecution to Argument position from MethodExecution.
	 * 
	 * @param methodExec MethodExecution.
	 * @param sourceVertexObject
	 * @param targetVertexMethodExec
	 */
	private void moveActualArgumentObjectVertex(MethodExecution methodExec, VertexObject sourceVertexObject, VertexMethodExecution targetVertexMethodExec) {
		mxICell sourceCell = (mxICell)sourceVertexObject.getCell();
		mxICell targetCell = (mxICell) targetVertexMethodExec.getCell();
//		mxICell parentTargetMethodExecCell = targetMethodExecCell.getParent();

		//  Remove sourceVertex from Locals and Arguments Vertex of MethodExecution's Vertex.  
//		MethodExecution callerMethodExecution = methodExec.getCallerMethodExecution();
		System.out.println(methodExec.getSignature());
		System.out.println(sourceVertexObject.getLabel());
//		if (methodExecToVertexMap.containsKey(callerMethodExecution) && methodExecToVertexMap.get(callerMethodExecution).getLocals().contains(sourceVertexObject)) {
//			methodExecToVertexMap.get(callerMethodExecution).getLocals().remove(sourceVertexObject);
//			System.out.println(methodExecToVertexMap.get(callerMethodExecution).getLabel() + " :removeLocal: " + sourceVertexObject.getLabel());
//		}
//
//		if (methodExecToVertexMap.containsKey(callerMethodExecution) && methodExecToVertexMap.get(callerMethodExecution).getArguments().contains(sourceVertexObject)) {
//			methodExecToVertexMap.get(callerMethodExecution).getArguments().remove(sourceVertexObject);
//			System.out.println(methodExecToVertexMap.get(callerMethodExecution).getLabel() + " :removeArgument: " + sourceVertexObject.getLabel());
//		}
		if (methodExecToVertexMap.containsKey(methodExec) && methodExecToVertexMap.get(methodExec).getLocals().contains(sourceVertexObject)) {
			methodExecToVertexMap.get(methodExec).getLocals().remove(sourceVertexObject);
			System.out.println(methodExecToVertexMap.get(methodExec).getLabel() + " :removeLocal: " + sourceVertexObject.getLabel());
		}

		if (methodExecToVertexMap.containsKey(methodExec) && methodExecToVertexMap.get(methodExec).getArguments().contains(sourceVertexObject)) {
			methodExecToVertexMap.get(methodExec).getArguments().remove(sourceVertexObject);
			System.out.println(methodExecToVertexMap.get(methodExec).getLabel() + " :removeArgument: " + sourceVertexObject.getLabel());
		}

		// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
		mxgraph.getModel().beginUpdate();
		try {
//			int time = targetVertexMethodExec.getArguments().size();
			int time = targetVertexMethodExec.getLocals().size() + 1;
			double sourceX = sourceCell.getGeometry().getX();
			double sourceY = sourceCell.getGeometry().getY();

			System.out.println(time + ", " + targetVertexMethodExec.getLocals().size());
//			if (time == 0) time = 1;

			if(sourceCell.getParent().getValue() != null) {
				Point absolutePointSourceCell = getAbsolutePointforCell(sourceCell);
				sourceX = absolutePointSourceCell.getX();
				sourceY = absolutePointSourceCell.getY();
				sourceCell.getParent().remove(sourceCell);
			}
			
			sourceCell.setParent(targetCell.getParent());
			targetCell.getParent().insert(sourceCell);
			sourceCell.getGeometry().setX(sourceX - sourceCell.getParent().getGeometry().getX());
			sourceCell.getGeometry().setY(sourceY - sourceCell.getParent().getGeometry().getY());

			double sourceWidth = sourceCell.getGeometry().getWidth();
			double sourceHeight = sourceCell.getGeometry().getHeight();
			double overlapWidth = sourceWidth - (sourceWidth * Math.sqrt(2) * 0.1);
			double overlapHeight = sourceHeight - (sourceHeight * Math.sqrt(2) * 0.1);
			
			deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() - overlapWidth, targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time)));
			deltaAnimation.startVertexAnimation();
			sourceCell.getGeometry().setX(targetCell.getGeometry().getX() - overlapWidth);
			sourceCell.getGeometry().setY(targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time));
			targetVertexMethodExec.getArguments().add(sourceVertexObject);			
			System.out.println("moveActualArgumentObjectVertex: " + targetVertexMethodExec.getLabel() + " :Argument: " + sourceVertexObject.getLabel());
		} finally {
			  mxgraph.getModel().endUpdate();
		}
	}
	
	/** Update VertexObject size. */
	private void updateVertexObjectSize() {
			// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology    	
//			mxgraph.getModel().beginUpdate();
//			try {
			for (VertexObject vertexObject: objectToVertexMap.values()) {
				mxCell vertexObjectCell = ((mxCell) vertexObject.getCell());
		    	int time = vertexObjectCell.getChildCount();
		    	if (time == 0) {
		    		time = 1;
		    	}
//	    		System.out.println("updateVertexObjectSize: " + vertexObjectCell.getGeometry().getWidth() + "->" + VERTEX_OBJECT_SIZE.getWidth() * time+ ", " + vertexObjectCell.getId());
		    	if(vertexObjectCell.getGeometry().getWidth() != VERTEX_OBJECT_SIZE.getWidth() * time) {
		    		System.out.println("updateVertexObjectSize: " + vertexObjectCell.getGeometry().getWidth() + "->" + VERTEX_OBJECT_SIZE.getWidth() * time+ ", " + vertexObjectCell.getId());
		    		Dimension targetDimension = new Dimension();
		    		targetDimension.setSize(VERTEX_OBJECT_SIZE.getWidth() * time, VERTEX_OBJECT_SIZE.getHeight() * time);
		    		deltaAnimation.setResizeVertexAnimation(vertexObjectCell, targetDimension);
		    		deltaAnimation.startResizeVertexAnimation();
		    	}
			}
//			}finally {
//				  mxgraph.getModel().endUpdate();
//			}
	
			show(mxDefaultParent);
	}

	/**
	 * Update VertexObject of targetMethodExecCell size have sourceObjectCell.
	 * 
	 * @param sourceObjectCell
	 * @param targetMethodExecCell
	 */
	private void updateVertexObjectSize(mxICell sourceObjectCell, mxICell targetMethodExecCell) {
		mxICell parentTargetMethodExecCell = targetMethodExecCell.getParent();	    	
		
		//Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
		mxgraph.getModel().beginUpdate();
		try {
	    	double preX = parentTargetMethodExecCell.getGeometry().getX();
	    	double preY = parentTargetMethodExecCell.getGeometry().getY();
	    	double preCenterX = parentTargetMethodExecCell.getGeometry().getCenterX();
	    	double preCenterY = parentTargetMethodExecCell.getGeometry().getCenterY();
	    	parentTargetMethodExecCell.getGeometry().setWidth(parentTargetMethodExecCell.getGeometry().getWidth() * 1.8);
	    	parentTargetMethodExecCell.getGeometry().setHeight(parentTargetMethodExecCell.getGeometry().getHeight() * 1.8);
	    	parentTargetMethodExecCell.getGeometry().setX(preX - (parentTargetMethodExecCell.getGeometry().getCenterX() - preCenterX));
	    	parentTargetMethodExecCell.getGeometry().setY(preY - (parentTargetMethodExecCell.getGeometry().getCenterY() - preCenterY));
		} finally {
			  mxgraph.getModel().endUpdate();
		}
	}
		
	private void show(mxICell cell) {
		for (Object object: mxgraph.getChildCells(cell)) {
			System.out.println(object);
			for (int i = 0; i < ((mxICell)object).getChildCount(); i++) {
				System.out.println("   " + ((mxICell)object).getChildAt(i));
			}
		}
		for (VertexObject vo: objectToVertexMap.values()) {
			System.out.println(vo.getLabel());
			for (VertexMethodExecution vme: vo.getVertexMethodExecutions()) {
				System.out.println("   " + vme.getLabel());
				for (VertexObject vmevo: vme.getArguments()) {
					System.out.println("   Argument: " + vmevo.getLabel());					
				}
				for (VertexObject vmevo: vme.getLocals()) {
					System.out.println("   Local: " + vmevo.getLabel());					
				}
			}
		}
		for (Edge e: edgeMap.values()) {
			System.out.println(e.getLabel() + ", " + e.getCell() + ", " + ((mxICell)e.getCell()).getParent());
		}
	}

	/** Make edge object in JGraphT and draw this in JGraphX. */
    private void makeEdgeObject() {
    	Map<String, Collection<String>> fieldNameMap = new HashMap<>();
    	Map<String, SimpleEntry<String, String>> aliasEntryMap = new HashMap<>();

    	// Format field name. 
		for (int i = 0; i < aliasList.size()-1; i++) {
			Alias curAlias = aliasList.get(i);
			Alias nextAlias = aliasList.get(i+1);

			if (curAlias.getAliasType().equals(AliasType.THIS) /*&& nextAlias.getAliasType().equals(AliasType.FIELD)*/) {
				String className = null;
				String fieldName = null;
				if (nextAlias.getAliasType().equals(AliasType.RETURN_VALUE)) {
					className = curAlias.getMethodExecution().getThisClassName();
					fieldName = curAlias.getOccurrencePoint().getMethodExecution().getArguments().get(0).getId();
					System.out.println("rTHIS " + className + ", " +curAlias.getOccurrencePoint().getMethodExecution().getArguments().get(0).getId()); 
				} else {
					Statement statement = curAlias.getOccurrencePoint().getStatement();
					if(statement instanceof FieldAccess) {
						String fieldNames[] = formatFieldName(((FieldAccess)statement).getFieldName());
						className = fieldNames[0];
						fieldName = fieldNames[1];
					}
				}
				if (className != null && fieldName != null) {
					if(fieldNameMap.get(className) == null) {
						fieldNameMap.put(className, new HashSet<String>());
					}
					fieldNameMap.get(className).add(fieldName);
					aliasEntryMap.put(fieldName, new SimpleEntry<String, String>(curAlias.getObjectId(), nextAlias.getObjectId()));
					System.out.println("THIS " + className + ", " + fieldName);
					System.out.println("THIS " + curAlias.getObjectId() + ", " + nextAlias.getObjectId());
				}
			}
			if(curAlias.getAliasType().equals(AliasType.ARRAY)) {
				Statement statement= curAlias.getOccurrencePoint().getStatement();
				if(statement instanceof ArrayAccess) {
					System.out.println("ARRAY " + ((ArrayAccess)statement).getArrayClassName() + ", " + ((ArrayAccess)statement).getIndex());
					String arrayClassName = ((ArrayAccess)statement).getArrayClassName();
					int index = ((ArrayAccess)statement).getIndex();
					String arrayIndex = formatArrayIndex(index);
					if(fieldNameMap.get(arrayClassName) == null) {
						fieldNameMap.put(arrayClassName, new HashSet<String>());
					}
					fieldNameMap.get(arrayClassName).add(arrayIndex);
					aliasEntryMap.put(arrayIndex, new SimpleEntry<String, String>(curAlias.getObjectId(), nextAlias.getObjectId()));
					System.out.println("ARRAY " + arrayClassName + ", " + arrayIndex);
					System.out.println("ARRAY " + curAlias.getObjectId() + ", " + nextAlias.getObjectId());
				}
			}
		}
		
		mxgraph.getModel().beginUpdate();
		try {
			// Make object edge in JGraphT and draw this in JGraphX.
			Delta delta = eStructure.getDelta();
			int srcSideSize = delta.getSrcSide().size();
			int dstSideSize = delta.getDstSide().size();
			for (int i = srcSideSize - 1; i >= 0; i--) {
				Reference ref = delta.getSrcSide().get(i);
				String srcObjId = ref.getSrcObjectId();
				String dstObjId = ref.getDstObjectId();
				if (!ref.isCreation() || !srcObjId.equals(dstObjId)) {
					String srcClassName = ref.getSrcClassName();
					String dstClassName = ref.getDstClassName();
					for(String fieldName: fieldNameMap.get(srcClassName)) {
						System.out.println(fieldName + ", " + srcClassName + ", " + dstClassName);
						// ?BUG : contains -> equals
						if(srcObjId.contains(aliasEntryMap.get(fieldName).getKey()) && dstObjId.contains(aliasEntryMap.get(fieldName).getValue())) {
							System.out.println("makeEdgeObject: " + fieldName + ", " + srcClassName + ", " + dstClassName);
							Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, fieldName, fieldName, objectToVertexMap.get(srcObjId).getCell(), objectToVertexMap.get(dstObjId).getCell());
			    			((mxCell)edge).setStyle("exitX=1;exitY=1;exitPerimeter=1;entryX=0;entryY=0;entryPerimeter=1;");
							edgeMap.put(srcClassName + "." + fieldName, new Edge(fieldName, TypeName.Reference, edge));
							break;
						}
					}
				}
			}

			for (int i = dstSideSize - 1; i >= 0; i--) {
				Reference ref = delta.getDstSide().get(i);
				String srcObjId = ref.getSrcObjectId();
				String dstObjId = ref.getDstObjectId();
				if ((!ref.isCreation() || !srcObjId.equals(dstObjId)) /*&& fieldNameMap.containsKey(ref.getSrcClassName())*/) {
					String srcClassName = ref.getSrcClassName();
					String dstClassName = ref.getDstClassName();
					if (fieldNameMap.get(srcClassName) != null) {
					for (String fieldName: fieldNameMap.get(srcClassName)) {
						System.out.println(fieldName + ", " + srcClassName + ", " + dstClassName);
						// ?BUG : contains -> equals
						if (srcObjId.contains(aliasEntryMap.get(fieldName).getKey()) && dstObjId.contains(aliasEntryMap.get(fieldName).getValue())) {
							System.out.println("makeEdgeObject: " + fieldName + ", " + srcObjId + ", " + dstObjId);
							Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, fieldName, fieldName, objectToVertexMap.get(srcObjId).getCell(), objectToVertexMap.get(dstObjId).getCell());
			    			((mxCell)edge).setStyle("exitX=0;exitY=1;exitPerimeter=1;entryX=1;entryY=0;entryPerimeter=1;");
			    			edgeMap.put(ref.getSrcClassName() + "." + fieldName, new Edge(fieldName, TypeName.Reference, edge));
							break;
						}
					}
					}
				}
			}
    	} finally {
  		  mxgraph.getModel().endUpdate();
    	}
	}

	/**
     * Make VertexMethodExecution.
     * 
     * @param alias
     */
	private void makeVertexMethodExecution(Alias alias) {
		makeVertexMethodExecution(alias, alias.getMethodSignature(), alias.getMethodExecution());
	}
	
	/**
	 * Parent : Make VertexMethodExecution.
	 * 
	 * @param alias
	 * @param methodSignature Called or this MethodSignature.
	 * @param methodExec Called or this MethodExecution.
	 */
	private void makeVertexMethodExecution(Alias alias, String methodSignature, MethodExecution methodExec) {
    	
    	if (methodSignature.contains(" ")) {
    		System.out.println(methodSignature);
    		methodSignature = formatMethodSignature(methodSignature);
    	}

		// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
    	mxgraph.getModel().beginUpdate();
    	try {
    		String objectId = alias.getObjectId();
    		Object object = objectToVertexMap.get(objectId).getCell();
    		double xCor = VERTEX_OBJECT_SIZE.getWidth() * 0.1;
    		double yCor =  VERTEX_OBJECT_SIZE.getHeight() * 0.5;
    		int time = objectToVertexMap.get(objectId).getVertexMethodExecutions().size();
    		
			Object vertex = mxgraph.insertDeltaVertex(object, methodSignature, methodSignature, "fillColor=white"); //creates a white vertex. 
			System.out.println("makeVertexMethodExecution: " + ((mxICell)vertex).getId());

			VertexMethodExecution vertexMethodExecution =  new VertexMethodExecution(methodSignature, vertex, xCor * (time + 1), yCor * (time + 1), VERTEX_METHOD_EXECUTION_SIZE.getWidth(), VERTEX_METHOD_EXECUTION_SIZE.getHeight());
//			Object vertex = mxgraph.insertVertex(object, methodSignature, methodSignature, 0, 0, 0, 0, "fillColor=white", true); //creates a white vertex.
//			Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, methodSignature, methodSignature, "fillColor=white"); //creates a white vertex. 
//			VertexMethodExecution vertexMethodExecution =  new VertexMethodExecution(methodSignature, vertex, getXForCell(objectId) + (xCor * (time + 1)), getYForCell(objectId) + (yCor * (time + 1)), VERTEX_METHOD_EXECUTION_SIZE.getWidth(), VERTEX_METHOD_EXECUTION_SIZE.getHeight());
			methodExecToVertexMap.put(methodExec, vertexMethodExecution);
			if(methodExecToVertexMap.size() > 1) {
				((mxICell)vertex).setVisible(false);
		    	makeEdgeMethodExecution();
		    	show(mxDefaultParent);
			}
			objectToVertexMap.get(objectId).addMethodExecution(vertexMethodExecution);
    	} finally {
    		  mxgraph.getModel().endUpdate();
      	}
	}
	
	/**
	 * Remove VertexMethodExecution on AliasType is MethodInvocation of alias.
	 * 
	 * @param alias
	 */
	private void removeVertexMethodExecution(Alias alias) {
		// sourceVertex
		VertexObject sourceVertexObject = objectToVertexMap.get(alias.getObjectId());
		MethodExecution methodExec = alias.getMethodExecution();
		
		if(alias.getAliasType().equals(AliasType.METHOD_INVOCATION)) {
			MethodExecution calledMethodExec = ((MethodInvocation) alias.getOccurrencePoint().getStatement()).getCalledMethodExecution();
			removeCalledVertexMethodExecution(sourceVertexObject, methodExec, calledMethodExec);
		} else {
			removeVertexMethodExecution(sourceVertexObject, methodExec);
		}
	}

	/**
	 * Remove VertexMethodExecution on AliasType is MethodInvocation of alias.
	 * 
	 * @param sourceVertexObject
	 * @param methodExec
	 */
	private void removeVertexMethodExecution(VertexObject sourceVertexObject, MethodExecution methodExec) {	
		//  Remove sourceVertex from Locals and Arguments Vertex of CalledMethodExecution's Vertex.  
		if (methodExecToVertexMap.containsKey(methodExec)) {
			mxCell targetVertexCell = (mxCell)methodExecToVertexMap.get(methodExec).getCell();
			targetVertexCell.getParent().remove(targetVertexCell);
			targetVertexCell.setParent(mxDefaultParent); 
			mxgraph.removeCells(new Object[] {targetVertexCell});
			objectToVertexMap.get(methodExec.getThisObjId()).getVertexMethodExecutions().remove(methodExecToVertexMap.get(methodExec));
			methodExecToVertexMap.remove(methodExec);
			edgeMap.remove(methodExec.getSignature());
			updateVertexObjectSize();
		}
	}

	/**
	 * Remove CalledVertexMethodExecution on AliasType is MethodInvocation of alias.
	 * 
	 * @param sourceVertexObject
	 * @param methodExec
	 * @param calledMethodExec
	 */
	private void removeCalledVertexMethodExecution(VertexObject sourceVertexObject, MethodExecution methodExec, MethodExecution calledMethodExec) {	

		//  Remove sourceVertex from Locals and Arguments Vertex of CalledMethodExecution's Vertex.  
		if (methodExecToVertexMap.containsKey(calledMethodExec)) {
			mxICell sourceVertexCell = (mxICell)methodExecToVertexMap.get(methodExec).getCell();
			mxCell targetVertexCell = (mxCell)methodExecToVertexMap.get(calledMethodExec).getCell();
			Point absolutPointSourceVertexCell = getAbsolutePointforCell(sourceVertexCell);

			// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
			mxgraph.getModel().beginUpdate();
			try {
				mxgraph.removeCells(mxgraph.getEdgesBetween(sourceVertexCell, targetVertexCell));
					try {
						mxICell cloneTargetVertexCell = (mxICell) mxgraph.addCell(targetVertexCell.clone());
						Point absolutPointTargetVertexCell = getAbsolutePointforCell(targetVertexCell);
						cloneTargetVertexCell.getGeometry().setX(absolutPointTargetVertexCell.getX());
						cloneTargetVertexCell.getGeometry().setY(absolutPointTargetVertexCell.getY());
						cloneTargetVertexCell.setStyle("fillColor=none;strokeColor=none;fontColor=#008000;");
						cloneTargetVertexCell.setValue(null);
						Object tempEdge = mxgraph.insertEdge(mxDefaultParent, null, null, sourceVertexCell, cloneTargetVertexCell);
		    			((mxCell)tempEdge).setStyle("dashed=1;strokeColor=#008000;exitX=0.5;exitY=1;exitPerimeter=1;entryX=0.5;entryY=0;entryPerimeter=1;endArrow=none");
						deltaAnimation.setReductionEdgeAnimation(cloneTargetVertexCell, new mxPoint(absolutPointSourceVertexCell.getX(), absolutPointSourceVertexCell.getY() + sourceVertexCell.getGeometry().getHeight()));
						deltaAnimation.startReductionEdgeAnimation();
//		    			deltaAnimation.setReductionEdgeAnimation(new mxPoint(absolutPointSourceVertexCell.getX() + (sourceVertexCell.getGeometry().getWidth() / 2), absolutPointSourceVertexCell.getY() + sourceVertexCell.getGeometry().getHeight()), new mxPoint(absolutPointTargetVertexCell.getX() + (targetVertexCell.getGeometry().getWidth() / 2), absolutPointTargetVertexCell.getY()));
//		    			deltaAnimation.startReductionEdgeAnimation();
		    			mxgraph.removeCells(new Object[]{cloneTargetVertexCell});
					} catch (CloneNotSupportedException e) {
						e.printStackTrace();
					}
			} finally {
				  mxgraph.getModel().endUpdate();
			}

			targetVertexCell.getParent().remove(targetVertexCell);
			targetVertexCell.setParent(mxDefaultParent); 
			mxgraph.removeCells(new Object[] {targetVertexCell});
			objectToVertexMap.get(calledMethodExec.getThisObjId()).getVertexMethodExecutions().remove(methodExecToVertexMap.get(calledMethodExec));
			methodExecToVertexMap.get(calledMethodExec).getLocals().remove(sourceVertexObject);
			methodExecToVertexMap.remove(calledMethodExec);
			edgeMap.remove(methodExec.getSignature());
//			updateVertexObjectSize();
		}
	}


	/** Make EdgeMethodExecution. */
	private void makeEdgeMethodExecution() {
		List<MethodExecution> methodExecList = new ArrayList<>(methodExecToVertexMap.keySet());
	
		// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology    	
		mxgraph.getModel().beginUpdate();
		try {
			// BUG : Edge Orientation Reverse.
			for (int i = 0; i < methodExecList.size() - 1; i++) {
				MethodExecution sourceMethodExec = methodExecList.get(i);
				MethodExecution targetMethodExec = methodExecList.get(i + 1);
				String methodSignature = sourceMethodExec.getSignature();
				if (!edgeMap.containsKey(methodSignature)) {
	    			mxICell sourceVertexCell = (mxICell)methodExecToVertexMap.get(sourceMethodExec).getCell();
	    			mxICell targetVertexCell = (mxICell)methodExecToVertexMap.get(targetMethodExec).getCell();
	    			Point absolutPointSourceVertexCell = getAbsolutePointforCell(sourceVertexCell);
	    			Point absolutPointTargetVertexCell = getAbsolutePointforCell(targetVertexCell);

//	    			System.out.println("start : " + sourceVertexCell.getGeometry().getCenterX() + ", " + (sourceVertexCell.getGeometry().getY() + sourceVertexCell.getGeometry().getHeight()) +  ", " + targetVertexCell.getGeometry().getCenterX() + ", " + targetVertexCell.getGeometry().getY());
//	    			deltaAnimation.setEdgeAnimation(new mxPoint(sourceVertexCell.getGeometry().getCenterX(), sourceVertexCell.getGeometry().getY() + sourceVertexCell.getGeometry().getHeight()), new mxPoint(targetVertexCell.getGeometry().getCenterX(), targetVertexCell.getGeometry().getY()));
	    			deltaAnimation.setExpandEdgeAnimation(new mxPoint(absolutPointSourceVertexCell.getX() + (sourceVertexCell.getGeometry().getWidth() / 2), absolutPointSourceVertexCell.getY() + sourceVertexCell.getGeometry().getHeight()), new mxPoint(absolutPointTargetVertexCell.getX() + (targetVertexCell.getGeometry().getWidth() / 2), absolutPointTargetVertexCell.getY()));
	    			deltaAnimation.startExpandEdgeAnimation();
	    			targetVertexCell.setVisible(true);
	    			Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, methodSignature, null, sourceVertexCell, targetVertexCell);
	    			((mxCell)edge).setStyle("exitX=0.5;exitY=1;exitPerimeter=1;entryX=0.5;entryY=0;entryPerimeter=1;");
	    			edgeMap.put(methodSignature, new Edge(methodSignature, TypeName.Call, edge));
					}
				}
		} finally {
			  mxgraph.getModel().endUpdate();
		}
	}
	
	private int countChildVertex(VertexObject vertexObject) {
    	int time = vertexObject.getVertexMethodExecutions().size();
    	if(time == 0) {
    		return 1;
    	}
    	for(VertexMethodExecution vertexMethodExecution: vertexObject.getVertexMethodExecutions()) {
    		for(VertexObject vo: vertexMethodExecution.getLocals()) {
    			time += countChildVertex(vo);
    		}
    		for(VertexObject vo: vertexMethodExecution.getArguments()) {
    			return countChildVertex(vo);
    		}
    	}
    	System.out.println(vertexObject.getLabel() + ": " + time);
		return time;
	}
	
	private String[] formatFieldName(String fieldName) {
		String fieldNames[] = fieldName.split("\\.");
		String names[] = new String[] {fieldNames[0], fieldNames[fieldNames.length - 1]};
		for(int i = 1; i < fieldNames.length - 1; i++) {
			names[0] += "." + fieldNames[i];
		}
		return names;
	}
		
	private String formatMethodSignature(String methodSignature) {
		// Step1 : split "("
		String[] methodSignatures = methodSignature.split("\\(");
		methodSignature = methodSignatures[0];
		// Step2 : split " "
		methodSignatures = methodSignature.split(" ");
		StringBuffer sb = new StringBuffer();
		sb.append(methodSignatures[methodSignatures.length-1]);
		sb.append("()");
		return sb.toString();
	}

	private String formatArrayName(String srcClassName) {
		// Step1 : remove "[L"
		StringBuffer sb = new StringBuffer();
		sb.append(srcClassName.substring(2, srcClassName.length()-1));
		sb.append("[]");
		return sb.toString();		
	}

	private String formatArrayIndex(int index) {
		StringBuffer sb = new StringBuffer();
		sb.append("[");
		sb.append(index);
		sb.append("]");
		return sb.toString();
	}
}