public class Logger {
	private ILog log;

	public Logger(ILog iLog) {
		this.log = iLog;
	}

	public void info(String msg) {
		log(Status.INFO, msg);
	}

	public void warn(String msg) {
		log(Status.WARNING, msg);
	}

	public void warn(String msg, Throwable exception) {
		log(Status.WARNING, msg, exception);
	}

	public void error(String msg) {
		log(Status.ERROR, msg);
	}

	public void error(String msg, Throwable exception) {
		log(Status.ERROR, msg, exception);
	}

	private void log(int level, String msg) {
		log.log(new Status(level, Visuflow.getDefault().getBundle().getSymbolicName(), msg));
	}

	private void log(int level, String msg, Throwable exception) {
		log.log(new Status(level, Visuflow.getDefault().getBundle().getSymbolicName(), msg, exception));
	}
} @SuppressWarnings("restriction")
public class ProjectPreferences {

	public void createPreferences() {
		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(GlobalSettings.get("AnalysisProject"));
		IScopeContext projectScope = new ProjectScope(project);
		IEclipsePreferences pref = projectScope.getNode(Activator.PLUGIN_ID);
		for (String stmt : getStatementTypes()) {
//			pref.putInt(stmt, -16743169);
			pref.putInt(stmt, -6037505);
		}
		try {
			pref.flush();
		} catch (BackingStoreException e) {
			e.printStackTrace();
		}
	}

	public void updateColorPreferences(String stmtType, int color) {
		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(GlobalSettings.get("AnalysisProject"));
		IScopeContext projectScope = new ProjectScope(project);
		IEclipsePreferences pref = projectScope.getNode(Activator.PLUGIN_ID);
		pref.putInt(stmtType, color);
		try {
			pref.flush();
		} catch (BackingStoreException e) {
			e.printStackTrace();
		}
	}

	public Map<String, Integer> getAllNodeColors() {
		HashMap<String, Integer> res = new HashMap<>();
		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(GlobalSettings.get("AnalysisProject"));
		IScopeContext projectScope = new ProjectScope(project);
		IEclipsePreferences pref = projectScope.getNode(Activator.PLUGIN_ID);
		for (String stmt : getStatementTypes()) {
			res.put(stmt, pref.getInt(stmt, 0));
		}
		return res;
	}
	
	public Integer getColorForNode(String node) {
		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(GlobalSettings.get("AnalysisProject"));
		IScopeContext projectScope = new ProjectScope(project);
		IEclipsePreferences pref = projectScope.getNode(Activator.PLUGIN_ID);
		return pref.getInt(node, 0);
	}
	private List<String> getStatementTypes() {
		List<String> stmtTypes = new ArrayList<String>();
		stmtTypes.add("soot.jimple.internal.JNopStmt");
		stmtTypes.add("soot.jimple.internal.JIdentityStmt");
		stmtTypes.add("soot.jimple.internal.JAssignStmt");
		stmtTypes.add("soot.jimple.internal.JIfStmt");
		stmtTypes.add("soot.jimple.internal.JGotoStmt");
		stmtTypes.add("soot.jimple.internal.JTableSwitchStmt");
		stmtTypes.add("soot.jimple.internal.JLookupSwitchStmt");
		stmtTypes.add("soot.jimple.internal.JInvokeStmt");
		stmtTypes.add("soot.jimple.internal.JReturnStmt");
		stmtTypes.add("soot.jimple.internal.JReturnVoidStmt");
		stmtTypes.add("soot.jimple.internal.JThrowStmt");
		stmtTypes.add("soot.jimple.internal.JRetStmt");
		stmtTypes.add("soot.jimple.internal.JEnterMonitorStmt");
		stmtTypes.add("soot.jimple.internal.JExitMonitorStmt");
		return stmtTypes;
	}

} public class Visuflow extends AbstractUIPlugin {
	public static Visuflow plugin;
	public static BundleContext context;
	private Logger logger;

	/**
	 * A resource listener, which observes the workspace for projects
	 * to become available. A new project is then build (full build) immediately.
	 */
	private ProjectListener projectListener = new ProjectListener();

	/* (non-Javadoc)
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
	 */
	@Override
	public void start(BundleContext context) {

		Visuflow.context = context;
		plugin = this;
		logger = new Logger(getLog());
		logger.info("Visuflow plug-in starting...");
		JimpleBreakpointManager.getInstance();

		// iterate over all projects in the workspace to find projects with the
		// visuflow nature. for these projects we trigger a full build to fill
		// the data model directly after the launch. there is also the ProjectListener,
		// which triggers a build for newly opened projects (e.g. opening a closed one or
		// importing a project etc.)
		// the builds are only executed, if the workspace is set to auto build
		IWorkspace workspace = ResourcesPlugin.getWorkspace();
		workspace.addResourceChangeListener(projectListener, IResourceChangeEvent.POST_CHANGE);
		if(workspace.isAutoBuilding()) {
			IWorkspaceRoot root = workspace.getRoot();
			try {
				root.accept(new IResourceVisitor() {
					@Override
					public boolean visit(IResource resource) throws CoreException {
						if(resource.getType() == IResource.PROJECT) {
							IProject project = (IProject) resource;
							projectListener.triggerBuild(project);
							return false;
						}
						return true;
					}
				});
			} catch (CoreException e) {
				logger.error("Error while trying to build visuflow projects", e);
			}
		}
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
	 */
	@Override
	public void stop(BundleContext context) {
		ResourcesPlugin.getWorkspace().removeResourceChangeListener(projectListener);
		Visuflow.context = null;
	}

	public static Visuflow getDefault() {
		return plugin;
	}

	public Logger getLogger() {
		return logger;
	}
} public final class GlobalSettings {
	
	/**
	 * Filename of the settings xml that stores settings.
	 */
	final static String fileName = "settings.xml";
	/**
	 * Creates a dialogsettings object.
	 */
	private static DialogSettings settings = new DialogSettings("ProjectOutputFolder");
	
	/**
	 * Gets the execution path of the plugin.
	 */
	IPath path = Visuflow.getDefault().getStateLocation();
	
	/**
	 * The filename of the settings file appended to the path.
	 */
	String filename = path.append(fileName).toOSString();

	protected GlobalSettings() {
		System.out.println("Settings filename is" + filename);
	}

	/**
	 * This function writes a key/value pair to the settings file
	 * @param key The key name.
	 * @param value The value for the key.
	 */
	public static void put(String key, String value) {
		IPath path = Visuflow.getDefault().getStateLocation();
		String filename = path.append(fileName).toOSString();
		try {
			settings.load(filename);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		settings.put(key, value);
		try {
			settings.save(filename);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * Get the value of the key being passed.
	 * @param key The key whose value is required.
	 * @return The value as a string.
	 */
	public static String get(String key) {
		IPath path = Visuflow.getDefault().getStateLocation();
		String filename = path.append(fileName).toOSString();
		try {
			settings.load(filename);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		return settings.get(key);
	}

}
 public class NavigationHandler extends AbstractHandler {

	/* (non-Javadoc)
	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
	 */
	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {

		//Get the editor part object
		IEditorPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
		IFileEditorInput input = (IFileEditorInput) part.getEditorInput();
		//Get a handle of the current file. This is used further in the code below.
		IFile file = input.getFile();
		if (part instanceof ITextEditor) {
			final ITextEditor editor = (ITextEditor) part;
			//Get a handle to the vertical rulebar of the text editor.
			IVerticalRulerInfo ruleInfo = editor.getAdapter(IVerticalRulerInfo.class);
			IDocumentProvider provider = editor.getDocumentProvider();
			//Grab the document currently being edited.
			IDocument document = provider.getDocument(editor.getEditorInput());
			try {
				//Get the line number of the line on which the user clicked last.
				int lineNumber = ruleInfo.getLineOfLastMouseButtonActivity();
				int offset = document.getLineOffset(lineNumber);
				int length = document.getLineInformation(lineNumber).getLength();
				String content = document.get(offset, length).trim();
				if (content.trim().length() > 0) {
					//Since the classname of a java source file is the same as it's file name, we use the filename as the classname.
					String className = file.getName().substring(0, file.getName().lastIndexOf('.'));
					HashMap<VFUnit, VFMethod> resultantUnit = getSelectedUnit(className, document, content.trim().substring(0, content.length() - 1),
							lineNumber);
					List<VFNode> unit = new ArrayList<>();
					if (resultantUnit.size() > 0) {
						unit.add(new VFNode((VFUnit) resultantUnit.keySet().toArray()[0], 0));
					}
					//The below conditions check for events.
					if (event.getCommand().getId().equals("JimpleEditor.NavigateToCFG")) {
						try {
							ServiceUtil.getService(DataModel.class).filterGraph(unit, true, true, null);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}

					else if (event.getCommand().getId().equals("JimpleEditor.NavigateToUnitView")) {
						try {
							ServiceUtil.getService(DataModel.class).filterGraph(unit, true, true, null);
						} catch (Exception e) {
							e.printStackTrace();
						}
					} else if (event.getCommand().getId().equals("JimpleEditor.VariablePath")) {
						try {
							List<VFNode> unitList = prepareVariablePath(className, document, content.trim().substring(0, content.length() - 1), lineNumber);
							ServiceUtil.getService(DataModel.class).filterGraph(unitList, true, true, null);
						} catch (Exception e) {
							e.printStackTrace();
						}
					} else if (event.getCommand().getId().equals("JimpleEditor.sourceCodeCommand")) {
						if (unit.size() > 0) {

							LineNumberTag ln = (LineNumberTag) unit.get(0).getUnit().getTag("LineNumberTag");
							if (ln != null) {
								highLightJavaSourceCode(ln.getLineNumber(), className);

							} else {
								IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
								MessageDialog.openInformation(window.getShell(), "Error", "No equivalent java source line found");
							}
						}

					}
				}
			} catch (BadLocationException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * This functions highlights units in a jimple file.
	 * @param units The units which need to be highlighted
	 */
	public void highlightJimpleSource(List<VFUnit> units) {

		Display.getDefault().asyncExec(new Runnable() {
			@Override
			public void run() {
				removeJimpleHighlight(true);
				IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
				for (VFUnit unit : units) {
					// Get the current page
					String className = unit.getVfMethod().getVfClass().getSootClass().getName();
					// IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();

					IWorkbenchPage page = window.getActivePage();
					String projectName = GlobalSettings.get("AnalysisProject");

					IPath path = new Path(projectName + "/sootOutput/" + className);
					path = path.addFileExtension("jimple");

					IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
					// Open default editor for the file

					try {
						IDE.openEditor(page, file, true);
						IDocumentProvider provider = new TextFileDocumentProvider();
						try {
							provider.connect(file);
						} catch (CoreException e) {
							e.printStackTrace();
						}
						IDocument document = provider.getDocument(file);
						Integer methodOffset = getMethodOffset(document, unit.getVfMethod());
						FindReplaceDocumentAdapter findReplaceDocumentAdapter = new FindReplaceDocumentAdapter(document);

						try {
							IRegion region = findReplaceDocumentAdapter.find(methodOffset,
									FindReplaceDocumentAdapter.escapeForRegExPattern(unit.getUnit().toString()), true, true, false, true);
							// IRegion region = findReplaceDocumentAdapter.find(methodLine, unit.getUnit().toString(), true, true, true, false);
							if (region != null) {
								ITextEditor editor = (ITextEditor) IDE.openEditor(page, file);
								// the 1 added is to include the semi colon
								editor.selectAndReveal(region.getOffset(), region.getLength() + 1);
							}
						} catch (BadLocationException e) {
							e.printStackTrace();
						}
					} catch (PartInitException e) {
						e.printStackTrace();
					}
				}
			}
		});

	}

	/**
	 * Highlights units in java source.
	 * @param unit The unit which needs to be highlighted.
	 */
	public void highlightJavaSource(VFUnit unit) {
		try {
			ServiceUtil.getService(DataModel.class).filterGraph(new ArrayList<VFNode>(), false, true, null);
		} catch (Exception e) {
			e.printStackTrace();
		}
		LineNumberTag ln = (LineNumberTag) unit.getUnit().getTag("LineNumberTag");
		String className = unit.getVfMethod().getVfClass().getSootClass().getName();
		if (ln != null) {
			highLightJavaSourceCode(ln.getLineNumber(), className);
		}
	}

	/**
	 * Removes highligghting from jimple/java files.
	 * @param isJimple Flag to differenciate between java and jimple files.
	 */
	public void removeJimpleHighlight(boolean isJimple) {
		Display.getDefault().asyncExec(() -> {
			try {
				IEditorReference[] references = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getEditorReferences();
				for (int i = 0; i < references.length; i++) {
					IEditorPart editorpart = references[i].getEditor(false);
					if (editorpart instanceof ITextEditor) {
						final ITextEditor editor = (ITextEditor) editorpart;
						IEditorInput input = editorpart.getEditorInput();
						IPath path = ((FileEditorInput) input).getPath();
						boolean extensionJimple = path.getFileExtension().equals("jimple");
						boolean extensionJava = path.getFileExtension().equals("java");
						if (isJimple && extensionJava) {
							ISelection selection = editor.getSelectionProvider().getSelection();
							if (selection != null) {
								ITextSelection textSelection = (ITextSelection) selection;
								editor.selectAndReveal(textSelection.getOffset(), 0);
							}

						} else if (extensionJimple && !isJimple) {
							ISelection selection = editor.getSelectionProvider().getSelection();
							if (selection != null) {
								ITextSelection textSelection = (ITextSelection) selection;
								editor.selectAndReveal(textSelection.getOffset(), 0);
							}
						}

					}
				}
			} catch (NullPointerException e) {
				e.printStackTrace();
			}
		});
	}

	/**
	 * This function filters the units of a class according to the function name and class name and content.
	 * We need to filter this based on methods, because different function might contain similar lines of code and
	 * hence their contents will be similar.
	 * @param className The name of the class.
	 * @param document The document which the user is currently interacting with
	 * @param content The contents of the document.
	 * @param lineNumber The linenumber on which the user has right-clicked.
	 * @return Map of filtered unit and the function it belongs to.
	 */
	private HashMap<VFUnit, VFMethod> getSelectedUnit(String className, IDocument document, String content, int lineNumber) {
		//Get the VFClass which contains all the VFMethods which inturn contains VFUnits
		DataModel dataModel = ServiceUtil.getService(DataModel.class);
		HashMap<VFUnit, VFMethod> map = new HashMap<>();
		//Iterate over all classes
		for (VFClass vfClass : dataModel.listClasses()) {
			//Filter by the class that is passed.
			if (vfClass.getSootClass().getName().equals(className)) {
				//Get all methods of the class.
				List<VFMethod> vfMethods = vfClass.getMethods();
				Map<String, Integer> methodLines = getMethodLineNumbers(document, vfMethods);
				Collection<Integer> allMethodLines = methodLines.values();
				List<Integer> lesserThanCuurent = allMethodLines.stream().filter(x -> x.intValue() < lineNumber).collect(Collectors.toList());
				int toBeCompared = lesserThanCuurent.get(lesserThanCuurent.size() - 1);
				for (VFMethod method : vfMethods) {
					int methodLine = methodLines.get(method.getSootMethod().getDeclaration());
					if (toBeCompared == methodLine) {
						for (VFUnit unit : method.getUnits()) {
							if (unit.getUnit().toString().trim().equals(content)) {
								map.put(unit, method);

							}
						}
					}
				}
			}
		}
		return map;
	}

	/**
	 * This method returns the line numbers of all the methods passed to it.
	 * @param document The document with which the user is interacting.
	 * @param vfMethods The list of methods for which the line numbers are required.
	 * @return Map containing method names and their starting line numbers.
	 */
	private Map<String, Integer> getMethodLineNumbers(IDocument document, List<VFMethod> vfMethods) {
		FindReplaceDocumentAdapter findReplaceDocumentAdapter = new FindReplaceDocumentAdapter(document);
		TreeMap<String, Integer> result = new TreeMap<>();
		for (VFMethod method : vfMethods) {
			try {
				method.getSootMethod().getBytecodeSignature();
				IRegion region = findReplaceDocumentAdapter.find(0, method.getSootMethod().getDeclaration(), true, true, false, false);
				result.put(method.getSootMethod().getDeclaration(), document.getLineOfOffset(region.getOffset()));
			} catch (BadLocationException e) {
				e.printStackTrace();
			}
		}
		return MapUtil.sortByValue(result);
	}

	private List<VFNode> prepareVariablePath(String className, IDocument document, String content, int lineNumber) {
		DataModel dataModel = ServiceUtil.getService(DataModel.class);
		List<VFNode> unitList = new ArrayList<>();
		// Map<VFUnit,Value> map = new LinkedHashMap<VFUnit,Value>();
		for (VFClass vfClass : dataModel.listClasses()) {
			if (vfClass.getSootClass().getName().equals(className)) {
				List<VFMethod> vfMethods = vfClass.getMethods();
				Map<String, Integer> methodLines = getMethodLineNumbers(document, vfMethods);
				Collection<Integer> allMethodLines = methodLines.values();
				List<Integer> lesserThanCuurent = allMethodLines.stream().filter(x -> x.intValue() < lineNumber).collect(Collectors.toList());
				int toBeCompared = lesserThanCuurent.get(lesserThanCuurent.size() - 1);
				for (VFMethod method : vfMethods) {
					int methodLine = methodLines.get(method.getSootMethod().getDeclaration());
					if (toBeCompared == methodLine) {
						unitList = createPointsToSet(method, content);
					}
				}
			}
		}
		return unitList;
	}

	private List<VFNode> createPointsToSet(VFMethod method, String content) {
		List<VFNode> unitList = new ArrayList<>();
		List<Value> valueList = new ArrayList<>();
		for (VFUnit unit : method.getUnits()) {
			Unit u = unit.getUnit();
			for (ValueBox db : u.getDefBoxes()) {
				for (ValueBox ub : u.getUseBoxes()) {
					if (!valueList.contains(ub.getValue())) {
						valueList.remove(db.getValue());
					}
				}
			}
			if (unit.getUnit().toString().trim().equals(content)) {
				for (ValueBox db : u.getDefBoxes()) {
					unitList.add(new VFNode(unit, 0));
					valueList.add(db.getValue());
				}
			}
			for (ValueBox ub : u.getUseBoxes()) {
				if (valueList.contains(ub.getValue())) {
					if (u.getDefBoxes().isEmpty()) {
						unitList.add(new VFNode(unit, 0));
					}
					for (ValueBox db : u.getDefBoxes()) {
						if (db.getValue() instanceof JInstanceFieldRef) {
							JInstanceFieldRef jirf = (JInstanceFieldRef) db.getValue();
							if (!jirf.getBase().equals(ub.getValue())) {
								unitList.add(new VFNode(unit, 0));
								valueList.add(db.getValue());
							}
						} else {
							unitList.add(new VFNode(unit, 0));
							valueList.add(db.getValue());
						}
					}
				}
			}
		}
		return unitList;
	}

	/**
	 * This method returns the offset of the method passed to it.
	 * @param document The document user is interacting with.
	 * @param method The method whose offset is required.
	 * @return The offset of the method.
	 */
	private Integer getMethodOffset(IDocument document, VFMethod method) {

		FindReplaceDocumentAdapter findReplaceDocumentAdapter = new FindReplaceDocumentAdapter(document);
		try {
			IRegion region = findReplaceDocumentAdapter.find(0, FindReplaceDocumentAdapter.escapeForRegExPattern(method.getSootMethod().getDeclaration()), true,
					true, false, true);
			return region.getOffset();
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * This functions highlights the contents of a java source file.
	 * @param lineNumber The line number which needs to be highlighted.
	 * @param className The name of the class which the line which needs to be highlighted is present in.
	 */
	private void highLightJavaSourceCode(int lineNumber, String className) {
		Display.getDefault().asyncExec(new Runnable() {
			@Override
			public void run() {
				removeJimpleHighlight(false);
				IWorkspaceRoot myWorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
				IProject analysisProject = myWorkspaceRoot.getProject(GlobalSettings.get("TargetProject"));
				if (analysisProject.exists()) {
					IJavaProject javaProj = JavaCore.create(analysisProject);
					try {
						IType classType = javaProj.findType(className);
						IFile classFile = ResourcesPlugin.getWorkspace().getRoot().getFile(classType.getPath());
						IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
						IWorkbenchPage page = window.getActivePage();
						try {

							ITextEditor javaEditor = (ITextEditor) IDE.openEditor(page, classFile, true);
							IDocument javaDocument = javaEditor.getDocumentProvider().getDocument(javaEditor.getEditorInput());
							if (javaDocument != null) {
								IRegion lineInfo = null;
								try {
									lineInfo = javaDocument.getLineInformation(lineNumber - 1);
								} catch (BadLocationException e) {
								}
								if (lineInfo != null) {
									javaEditor.selectAndReveal(lineInfo.getOffset(), lineInfo.getLength());
								}
							}

						} catch (PartInitException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					} catch (JavaModelException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		});
	}

} public interface DataModel {
	public static final String EA_TOPIC_DATA = "de/unipaderborn/visuflow/DataModel";
	public static final String EA_TOPIC_DATA_MODEL_CHANGED = EA_TOPIC_DATA + "/ModelChanged";
	public static final String EA_TOPIC_DATA_CLASS_ADDED = EA_TOPIC_DATA + "/ClassAdded";
	public static final String EA_TOPIC_DATA_CLASS_CHANGED = EA_TOPIC_DATA + "/ClassChanged";
	public static final String EA_TOPIC_DATA_CLASS_REMOVED = EA_TOPIC_DATA + "/ClassRemoved";
	public static final String EA_TOPIC_DATA_METHOD_ADDED = EA_TOPIC_DATA + "/MethodAdded";
	public static final String EA_TOPIC_DATA_METHOD_CHANGED = EA_TOPIC_DATA + "/MethodChanged";
	public static final String EA_TOPIC_DATA_METHOD_REMOVED = EA_TOPIC_DATA + "/MethodRemoved";
	public static final String EA_TOPIC_DATA_UNIT_ADDED = EA_TOPIC_DATA + "/UnitAdded";
	public static final String EA_TOPIC_DATA_UNIT_CHANGED = EA_TOPIC_DATA + "/UnitChanged";
	public static final String EA_TOPIC_DATA_UNIT_REMOVED = EA_TOPIC_DATA + "/UnitRemoved";
	public static final String EA_TOPIC_DATA_FILTER_GRAPH = EA_TOPIC_DATA + "/UnitFiltered";
	public static final String EA_TOPIC_DATA_VIEW_REFRESH = EA_TOPIC_DATA + "/refresh";

	public static final String EA_TOPIC_DATA_SELECTION = EA_TOPIC_DATA + "/SelectionChanged";

	/**
	 * Returns the ICFG.
	 * @return - ICFG of the target
	 */
	public ICFGStructure getIcfg();
	/**
	 * Lists all of the classes from the model.
	 * @return list of all the classes of the target code
	 */
	public List<VFClass> listClasses();
	/**
	 * Returns all the methods of a given class.
	 * @param vfClass - class
	 * @return list of all methods 
	 */
	public List<VFMethod> listMethods(VFClass vfClass);
	/**
	 * Returns all the units of a given method.
	 * @param vfMethod - method
	 * @return list of all units
	 */
	public List<VFUnit> listUnits(VFMethod vfMethod);
	public VFUnit getVFUnit(String fqn);
	/**
	 * Updates the model to hold the updated class list and triggers the {@value #EA_TOPIC_DATA_MODEL_CHANGED} event.
	 * @param classList list of updated classes
	 * @author Shashank B S
	 */
	public void setClassList(List<VFClass> classList);
	/**
	 * Returns the currently selected class.
	 * @return currently selected class
	 * @author Shashank B S
	 */
	public VFClass getSelectedClass();
	/**
	 * Returns the list of methods of the currently selected class.
	 * @return list of selected class methods
	 */
	public List<VFMethod> getSelectedClassMethods();
	/**
	 * Returns the list of units of the currently selected method.
	 * @return list of units of the currently selected method
	 * @author Shashank B S
	 */
	public List<VFUnit> getSelectedMethodUnits();
	/**
	 * Updates the currently selected class, sets the currently selected method to the first method of the class and triggers the {@link #EA_TOPIC_DATA_SELECTION} with the selected class.
	 * @param selectedClass
	 * @author Shashank B S
	 */
	public void setSelectedClass(VFClass selectedClass);
	/**
	 * Updates the currently selected method and triggers the {@link #EA_TOPIC_DATA_SELECTION} event with the selected method and panToNode flag.
	 * @param selectedMethod - the method to be selected
	 * @param panToNode flag to determine whether the graph needs to be panned
	 * @author Shashank B S
	 */
	public void setSelectedMethod(VFMethod selectedMethod, boolean panToNode);
	/**
	 * Triggers the {@link #EA_TOPIC_DATA_FILTER_GRAPH} event with the nodesToFilter, selection, panToNode, uiClassName properties.
	 * @param nodesToFilter nodes to be filtered on the graph
	 * @param selection flag to determine whether the nodes have to be highlighted
	 * @param panToNode flag to determine whether the graph has to be panned to the filtered node
	 * @param uiClassName css class to be set on the filtered nodes
	 * @author Shashank B S
	 */
	public void filterGraph(List<VFNode> nodesToFilter, boolean selection, boolean panToNode, String uiClassName);
	/**
	 * Returns the currently selected method.
	 * @return currently selected method
	 * @author Shashank B S
	 */
	public VFMethod getSelectedMethod();
	/**
	 * Returns the {@code VFMethod} of the corresponding {@code SootMethod} 
	 * @param method
	 * @return
	 * @author Shashank B S
	 */
	public VFMethod getVFMethodByName(SootMethod method);
	/**
	 * Sets the <b>ICFG</b> of the model.
	 * @param icfg
	 * @author Shashank B S
	 */
	public void setIcfg(ICFGStructure icfg);
	/**
	 * Trigger a project rebuild explicitly after changes to the model.
	 * @author Shashank B S
	 */
	public void triggerProjectRebuild();
	public void refreshView();

	public void setInSet(String unitFqn, String name, String value);
	public void setOutSet(String unitFqn, String name, String value);
	public void HighlightJimpleUnit(VFNode node);
} public class VFClass {

	private SootClass wrapped;

	private List<VFMethod> methods = new ArrayList<VFMethod>();

	public VFClass(SootClass sootClass) {
		this.wrapped = sootClass;
	}

	public SootClass getSootClass() {
		return wrapped;
	}

	public List<VFMethod> getMethods() {
		return methods;
	}
} public class VFEdge {

	int id;
	VFNode source;
	VFNode destination;

	public VFEdge(int id, VFNode source, VFNode destination)
	{
		this.id=id;
		this.source=source;
		this.destination=destination;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public VFNode getSource() {
		return source;
	}

	public void setSource(VFNode source) {
		this.source = source;
	}

	public VFNode getDestination() {
		return destination;
	}

	public void setDestination(VFNode destination) {
		this.destination = destination;
	}

}
 public class VFMethod {

	protected SootMethod wrapped;
	private List<VFUnit> units = new ArrayList<>();
	private List<VFUnit> incomingEdges = new ArrayList<>();
	private Body body;
	private ControlFlowGraph controlFlowGraph;
	private int id;
	private VFClass vfClass;

	public VFClass getVfClass() {
		return vfClass;
	}

	public void setVfClass(VFClass vfClass) {
		this.vfClass = vfClass;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public VFMethod(SootMethod wrapped) {
		this.wrapped = wrapped;
	}

	public VFMethod(int methodcount, SootMethod wrapped) {
		this.id = methodcount;
		this.wrapped = wrapped;
	}

	public SootMethod getSootMethod() {
		return wrapped;
	}

	public List<VFUnit> getUnits() {
		return units;
	}

	public Body getBody() {
		return body;
	}

	public void setBody(Body body) {
		this.body = body;
	}

	public ControlFlowGraph getControlFlowGraph() {
		return controlFlowGraph;
	}

	public void setControlFlowGraph(ControlFlowGraph controlFLowGraph) {
		this.controlFlowGraph = controlFLowGraph;
	}

	@Override
	public String toString() {
		return wrapped != null ? /*wrapped.getDeclaringClass().getName()+"."+*/ wrapped.getName() : super.toString();
	}

	public List<VFUnit> getIncomingEdges() {
		return incomingEdges;
	}

	public void setIncomingEdges(List<VFUnit> incomingEdges) {
		this.incomingEdges = incomingEdges;
	}

	public boolean addIncomingEdge(VFUnit incomingEdge){
		if(incomingEdges.contains(incomingEdge)){
			return false;
		}
		return incomingEdges.add(incomingEdge);
	}

	/**
	 * Returns a unit after the given unit. The offset determines how
	 * many units to skip. Offset 1 means the next unit (direct sibling).
	 * @param unit
	 * @param offset
	 * @return
	 */
	public VFUnit getUnitAfter(VFUnit unit, int offset) {
		boolean returnNext = false;
		int lastIndex = units.size() - 1;
		for (int i = 0; i < units.size(); i++) {
			VFUnit current = units.get(i);
			if(returnNext) {
				int requestedIndex = i - 1 + offset;
				if(requestedIndex <= lastIndex) {
					return units.get(requestedIndex);
				} else {
					throw new NoSuchElementException("There is no unit after " + unit.getFullyQualifiedName());
				}
			} else if(current.getFullyQualifiedName().equals(unit.getFullyQualifiedName())) {
				if(i == lastIndex) {
					throw new NoSuchElementException("There is no unit after " + unit.getFullyQualifiedName());
				} else {
					returnNext = true;
				}
			}
		}
		throw new UnitNotFoundException("There is no unit after " + unit.getFullyQualifiedName());
	}
} public class VFMethodEdge {
	int id;
	VFMethod sourceMethod;
	VFMethod destMethod;
	
	public VFMethodEdge(int id, VFMethod sourceMethod, VFMethod destinationMethod) {
		this.id = id;
		this.sourceMethod = sourceMethod;
		this.destMethod = destinationMethod;
	}

	public int getId() {
		return id;
	}
	
	public void setId(int id) {
		this.id = id;
	}
	
	public VFMethod getSourceMethod() {
		return sourceMethod;
	}
	
	public void setSourceMethod(VFMethod sourceMethod) {
		this.sourceMethod = sourceMethod;
	}
	
	public VFMethod getDestMethod() {
		return destMethod;
	}
	
	public void setDestMethod(VFMethod destMethod) {
		this.destMethod = destMethod;
	}
	
	public String toString(){
		return "Source: " + sourceMethod + " | Destination: " + destMethod;
	}
} public class VFNode {
	
	VFUnit vfUnit;
	int id;
	
	public VFNode(VFUnit label, int id)
	{
		this.vfUnit=label;
		this.id=id;
	}

	public void setLabel(VFUnit label)
	{
		this.vfUnit = label;
	}
	
	public Unit getUnit()
	{
		return this.vfUnit.getUnit();
	}
	
	public VFUnit getVFUnit()
	{
		return this.vfUnit;
	}
	
	public void setId(int id)
	{
		this.id=id;
	}
	
	public int getId()
	{
		return this.id;
	}

} public class VFUnit {

	private String fullyQualifiedName;
	protected Unit wrapped;

	private Object inSet;
	private Object outSet;

	private VFMethod vfMethod;

	private Map<String, String> hmCustAttr = new HashMap<>();
	private List<VFUnit> outgoingEdges = new ArrayList<>();

	public List<VFUnit> getOutgoingEdges() {
		return outgoingEdges;
	}

	public void setOutgoingEdges(List<VFUnit> outgoingEdges) {
		this.outgoingEdges = outgoingEdges;
	}

	public boolean addOutgoingEdge(VFUnit outgoingEdge){
		if(outgoingEdges.contains(outgoingEdge)){
			return false;
		}
		return outgoingEdges.add(outgoingEdge);
	}
	public VFMethod getVfMethod() {
		return vfMethod;
	}

	public void setVfMethod(VFMethod vfMethod) {
		this.vfMethod = vfMethod;
	}

	public VFUnit(Unit wrapped) {
		this.wrapped = wrapped;
		setFullyQualifiedName(wrapped);
	}

	public Unit getUnit() {
		return wrapped;
	}

	public Object getInSet() {
		return inSet;
	}

	public void setInSet(Object inSet) {
		this.inSet = inSet;
	}

	public Object getOutSet() {
		return outSet;
	}

	public void setOutSet(Object outSet) {
		this.outSet = outSet;
	}

	private void setFullyQualifiedName(Unit u) {
		Tag fqn = u.getTag("Fully Qualified Name");
		if (fqn != null) {
			String fullyQualifiedName = new String(fqn.getValue());
			this.fullyQualifiedName = fullyQualifiedName;
		} else {
			System.out.println("WARN fqn tag not found on unit " + u);
		}
	}

	public String getFullyQualifiedName() {
		return fullyQualifiedName;
	}

	public Map<String, String> getHmCustAttr() {
		return hmCustAttr;
	}

	public void setHmCustAttr(Map<String, String> hmCustAttr) {
		this.hmCustAttr = hmCustAttr;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((fullyQualifiedName == null) ? 0 : fullyQualifiedName.hashCode());
		return result;
	}

	@Override
	public String toString(){
		return getFullyQualifiedName();
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		VFUnit other = (VFUnit) obj;
		if (fullyQualifiedName == null) {
			if (other.fullyQualifiedName != null)
				return false;
		} else if (!fullyQualifiedName.equals(other.fullyQualifiedName))
			return false;
		return true;
	}
} public class ControlFlowGraph {
	public List<VFNode> listNodes = new ArrayList<VFNode>();
	public List<VFEdge> listEdges = new ArrayList<VFEdge>();

} public class ICFGStructure {
	public List<VFMethod> listMethods = new ArrayList<VFMethod>();
	public List<VFMethodEdge> listEdges = new ArrayList<VFMethodEdge>();
}
 public interface UnitFormatter {
	public String format(Unit u, int maxLength);
} public class UnitFormatterFactory {

	public static UnitFormatter createFormatter(Unit u) {
		if(u instanceof AssignStmt) {
			return new AssignStmtFormatter();
		} else if (u instanceof InvokeStmt) {
			return new InvokeStmtFormatter();
		}

		// no special formatter found, return the default one
		return new DefaultFormatter();
	}
} public class ReturnPathFilter extends FilteredItemsSelectionDialog {
	
	List<VFUnit> paths = new ArrayList<>();
	
	public void setPaths(List<VFUnit> paths){
		this.paths = paths;
	}
	
	public ReturnPathFilter(Shell shell) {
		   super(shell);
		   setTitle("Return Path Selection");
		   setSelectionHistory(new PathSelectionHistory());
	}
	
	protected Control createExtendedContentArea(Composite arg0) {
		return null;
	}

	@Override
	protected ItemsFilter createFilter() {
		return new ItemsFilter() {
	         public boolean matchItem(Object item) {
	            return matches(item.toString());
	         }
	         public boolean isConsistentItem(Object item) {
	            return true;
	         }
	      };
	}

	@Override
	protected void fillContentProvider(AbstractContentProvider contentProvider, ItemsFilter itemsFilter, IProgressMonitor progressMonitor) throws CoreException {
		      progressMonitor.beginTask("Searching", paths.size());
		      for (Iterator<VFUnit> iter = paths.iterator(); iter.hasNext();) {
		         contentProvider.add(((VFUnit)iter.next()), itemsFilter);
		         progressMonitor.worked(1);
		      }
		      progressMonitor.done();
	}
	
	   protected IDialogSettings getDialogSettings() {
	      	IDialogSettings settings = Visuflow.getDefault().getDialogSettings();
			return settings;
	   }

	@Override
	public String getElementName(Object item) {
		return item.toString();
	}

	protected Comparator<?> getItemsComparator() {
	      return new Comparator<Object>() {
	         public int compare(Object arg0, Object arg1) {
	            return arg0.toString().compareTo(arg1.toString());
	         }
	      };
	   }

	@Override
	protected IStatus validateItem(Object item) {
		return Status.OK_STATUS;
	}
	
	private class PathSelectionHistory extends SelectionHistory {
		   protected Object restoreItemFromMemento(IMemento element) {
			  return null; 
		   }
		   protected void storeItemToMemento(Object item, IMemento element) {
		   }
	}

} public class ServiceUtil {

    /**
     * @see {@link ServiceUtil#getService(Class, long)}
     */
    public static <T> T getService(Class<T> serviceClass) {
        return getService(serviceClass, TimeUnit.SECONDS.toMillis(60));
    }

    /**
     * Looks up an OSGi service. If the service is not yet available, this method will wait for 60 seconds for the service to become available. If the service
     * does not appear in this period, a ServiceException is thrown.
     *
     * @param serviceClass
     *            The service interface of the service to look up
     * @param timeoutInMillis
     *            The amount of time in milliseconds to wait for the service to become available
     * @return an implementation of the given service interface
     * @throws a
     *             ServiceException, if the service couldn't be found in the OSGi service registry
     */
    public static <T> T getService(Class<T> serviceClass, long timeoutInMillis) {
        BundleContext ctx = FrameworkUtil.getBundle(ServiceUtil.class).getBundleContext();
        ServiceTracker<T, T> tracker = new ServiceTracker<>(ctx, serviceClass, null);
        tracker.open();
        T service = null;
        try {
            service = tracker.waitForService(timeoutInMillis);
        } catch (InterruptedException e) {
            throw new ServiceException("Interrupted while waiting for the service " + serviceClass.getName(), e);
        }

        tracker.close();
        if (service != null) {
            return service;
        } else {
            throw new ServiceException("Service " + serviceClass.getName() + " not available");
        }
    }

    /**
     * Registers a service implementation at the OSGi service registry.
     *
     * @param serviceClass
     *            The interface class of the service
     * @param service
     *            The service implementation
     * @param properties
     *            Additional properties assigned to this implementation
     * @see BundleContext#registerService(Class, Object, Dictionary)
     */
    public static <T> void registerService(Class<T> serviceClass, T service, Dictionary<String, ?> properties) {
        BundleContext ctx = FrameworkUtil.getBundle(ServiceUtil.class).getBundleContext();
        ctx.registerService(serviceClass, service, properties);
    }
}
import static de.unipaderborn.visuflow.model.DataModel.EA_TOPIC_DATA_FILTER_GRAPH;
import static de.unipaderborn.visuflow.model.DataModel.EA_TOPIC_DATA_MODEL_CHANGED;
import static de.unipaderborn.visuflow.model.DataModel.EA_TOPIC_DATA_SELECTION;
import static de.unipaderborn.visuflow.model.DataModel.EA_TOPIC_DATA_UNIT_CHANGED;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Label;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import org.apache.commons.lang.StringEscapeUtils;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.graphstream.algorithm.Toolkit;
import org.graphstream.graph.Edge;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
import org.graphstream.graph.implementations.MultiGraph;
import org.graphstream.ui.geom.Point3;
import org.graphstream.ui.graphicGraph.GraphicElement;
import org.graphstream.ui.layout.Layout;
import org.graphstream.ui.layout.springbox.implementations.SpringBox;
import org.graphstream.ui.swingViewer.ViewPanel;
import org.graphstream.ui.view.Viewer;
import org.graphstream.ui.view.ViewerListener;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import com.google.common.base.Optional;
import de.unipaderborn.visuflow.Logger;
import de.unipaderborn.visuflow.ProjectPreferences;
import de.unipaderborn.visuflow.Visuflow;
import de.unipaderborn.visuflow.builder.GlobalSettings;
import de.unipaderborn.visuflow.debug.handlers.NavigationHandler;
import de.unipaderborn.visuflow.model.DataModel;
import de.unipaderborn.visuflow.model.VFClass;
import de.unipaderborn.visuflow.model.VFEdge;
import de.unipaderborn.visuflow.model.VFMethod;
import de.unipaderborn.visuflow.model.VFMethodEdge;
import de.unipaderborn.visuflow.model.VFNode;
import de.unipaderborn.visuflow.model.VFUnit;
import de.unipaderborn.visuflow.model.graph.ControlFlowGraph;
import de.unipaderborn.visuflow.model.graph.ICFGStructure;
import de.unipaderborn.visuflow.ui.graph.formatting.UnitFormatter;
import de.unipaderborn.visuflow.ui.graph.formatting.UnitFormatterFactory;
import de.unipaderborn.visuflow.ui.view.filter.ReturnPathFilter;
import de.unipaderborn.visuflow.util.ServiceUtil;
import scala.collection.mutable.HashSet;
import soot.Unit;
import soot.jimple.ReturnStmt;
import soot.jimple.ReturnVoidStmt;
import soot.jimple.Stmt;

	 * creates JMenuItems {@link #navigateToJimple}, {@link #navigateToJava}, {@link #showInUnitView}, {@link #setCustomAttribute}, {@link #followCall}, {@link #followReturn}, {@link #cha}, {@link #spark} and their handlers.
	 * @author Shashank B S
	 */
	private void createPopUpMenuItemsAndListeners() {
		navigateToJimple = new JMenuItem("Navigate to Jimple");
		navigateToJava = new JMenuItem("Navigate to Java");
		showInUnitView = new JMenuItem("Highlight on Units view");
		setCustomAttribute = new JMenuItem("Set custom attribute");
		followCall = new JMenuItem("Follow the Call");
		followReturn = new JMenuItem("Follow the Return");

		callGraphOption = new JMenu("Call Graph Option");
		cha = new JMenuItem("CHA");
		spark = new JMenuItem("SPARK");

		callGraphOption.add(cha);
		callGraphOption.add(spark);

		followCall.setVisible(false);
		followReturn.setVisible(false);

		navigateToJimple.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				GraphicElement curElement = view.findNodeOrSpriteAt(x, y);
				if (curElement == null)
					return;
				Node curr = graph.getNode(curElement.getId());
				Object node = curr.getAttribute("nodeUnit");
				NavigationHandler handler = new NavigationHandler();
				if (node instanceof VFNode) {
					ArrayList<VFUnit> units = new ArrayList<>();
					units.add(((VFNode) node).getVFUnit());
					handler.highlightJimpleSource(units);
				}
			}
		});

		setCustomAttribute.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				GraphicElement curElement = view.findNodeOrSpriteAt(x, y);
				if (curElement == null) {
					return;
				}
				Node curr = graph.getNode(curElement.getId());
				Object node = curr.getAttribute("nodeUnit");
				if (node instanceof VFNode) {
					VFUnit selectedVF = ((VFNode) node).getVFUnit();
					setCustomAttribute(selectedVF, curr);
					// curr.setAttribute("ui.color", jcc.getColor());
				}
			}
		});

		navigateToJava.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				GraphicElement curElement = view.findNodeOrSpriteAt(x, y);
				if (curElement == null)
					return;
				Node curr = graph.getNode(curElement.getId());
				Object node = curr.getAttribute("nodeUnit");
				NavigationHandler handler = new NavigationHandler();
				if (node instanceof VFNode) {
					ArrayList<VFUnit> units = new ArrayList<>();
					units.add(((VFNode) node).getVFUnit());
					handler.highlightJavaSource(units.get(0));
				}
			}
		});

		showInUnitView.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				DataModel dataModel = ServiceUtil.getService(DataModel.class);
				GraphicElement curElement = view.findNodeOrSpriteAt(x, y);
				if (curElement == null)
					return;
				Node curr = graph.getNode(curElement.getId());
				Object node = curr.getAttribute("nodeUnit");
				if (node instanceof VFNode) {
					ArrayList<VFUnit> units = new ArrayList<>();
					units.add(((VFNode) node).getVFUnit());

					ArrayList<VFNode> nodes = new ArrayList<>();
					nodes.add((VFNode) node);
					try {
						dataModel.filterGraph(nodes, true, true, null);
					} catch (Exception e1) {
						e1.printStackTrace();
					}
				}
			}
		});

		followCall.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				GraphicElement curElement = view.findNodeOrSpriteAt(x, y);
				if(curElement == null)
					return;
				Node curr = graph.getNode(curElement.getId());
				Object node = curr.getAttribute("nodeUnit");
				if (node instanceof VFNode) {
					if (((Stmt) ((VFNode) node).getUnit()).containsInvokeExpr()){
						List<VFUnit> list = new ArrayList<>();
						for(VFUnit edge : ((VFNode) node).getVFUnit().getOutgoingEdges()){
							list.add(edge);
						}
						if(list.size() == 1) {
							jumpToCallee(list.get(0));
						} else {
							Display.getDefault().syncExec(new Runnable() {
								@Override
								public void run() {

									ReturnPathFilter callFilter = new ReturnPathFilter(Display.getDefault().getActiveShell());
