CHESSIoT_Dev_old-master/org.polarsys.chess.m2m/src/org/polarsys/chess/m2m/handlers/QVToUIHandlerVERDE.java
/*
-----------------------------------------------------------------------
--          			CHESS M2M plugin							 --
--                                                                   --
--                    Copyright (C) 2011-2012                        --
--                 University of Padova, ITALY                       --
--                                                                   --
-- Authors: -Alessandro Zovi         azovi@math.unipd.it 
--          -Intecs
--                                                                   --
-- All rights reserved. This program and the accompanying materials  --
-- are made available under the terms of the Eclipse Public License  --
-- v1.0 which accompanies this distribution, and is available at     --
-- http://www.eclipse.org/legal/epl-v20.html                         --
-----------------------------------------------------------------------
 */

package org.polarsys.chess.m2m.handlers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.Resource.Diagnostic;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.m2m.internal.qvt.oml.emf.util.ModelContent;
import org.eclipse.papyrus.MARTE.MARTE_AnalysisModel.GQAM.GaResourcesPlatform;
import org.eclipse.papyrus.MARTE.MARTE_AnalysisModel.SAM.SaAnalysisContext;
import org.eclipse.papyrus.editor.PapyrusMultiDiagramEditor;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Stereotype;
import org.polarsys.chess.chessmlprofile.Core.CHGaResourcePlatform;
import org.polarsys.chess.chessmlprofile.Predictability.DeploymentConfiguration.HardwareBaseline.CH_HwProcessor;
import org.polarsys.chess.chessmlprofile.Predictability.RTComponentModel.CHRtPortSlot;
import org.polarsys.chess.chessmlprofile.util.Constants;
import org.polarsys.chess.core.util.AnalysisResultData;
import org.polarsys.chess.core.util.CHESSProjectSupport;
import org.polarsys.chess.core.util.HWAnalysisResultData;
import org.polarsys.chess.core.util.uml.ModelError;
import org.polarsys.chess.core.util.uml.ResourceUtils;
import org.polarsys.chess.core.util.uml.UMLUtils;
import org.polarsys.chess.core.views.ViewUtils;
import org.polarsys.chess.m2m.Activator;
import org.polarsys.chess.m2m.transformations.PIMPSMTransformationVERDE;
import org.polarsys.chess.m2m.transformations.TransUtil;
import org.polarsys.chess.m2m.transformations.TransformationResultsData;
import org.polarsys.chess.m2m.ui.AnalysisContextSelectionDialog;
import org.polarsys.chess.m2m.ui.SchedResultDialog;
import org.polarsys.chess.service.gui.utils.CHESSEditorUtils;
import org.polarsys.chess.validator.command.ChessGenericValidateCommand;


// TODO: Auto-generated Javadoc
/**
 * The Class QVToUIHandlerVERDErealizes the handler for the scehdulability analysis command.
 * @since 0.9
 */
public class QVToUIHandlerVERDE extends AbstractHandler {

	/** The active shell. */
	private Shell activeShell = null;

	/** The in resource. */
	private Resource inResource = null;

	/** The context class. */
	//	private Class contextClass;

	/** The sa analysis name. */
	private String saAnalysisName;

	/** The psm package name. */
	private String psmPackageName;

	/**
	 * Gets the active project.
	 *
	 * @param editor the editor
	 * @return the active project
	 */
	private IProject getActiveProject(IEditorPart editor) {
		IFileEditorInput input = (IFileEditorInput) editor.getEditorInput();
		IFile file = input.getFile();
		return file.getProject(); 
	}

	/**
	 * Executes the schedulability analysis and shows the results.
	 * The analysis context to be analyzed is asked to the user through a dedicated dialog.
	 *
	 * @param event the event resulting from the invocation of the command
	 * @return null 
	 * @throws ExecutionException the execution exception
	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
	 * @see org.polarsys.chess.m2m.ui.AnalysisContextSelectionDialog
	 */
	public Object execute(final ExecutionEvent event) throws ExecutionException {
		final IEditorPart editor = HandlerUtil.getActiveEditor(event);


		if (!(CHESSEditorUtils.isCHESSProject(editor)))
			return null;

		try {
			inResource = ResourceUtils.getUMLResource(((PapyrusMultiDiagramEditor) editor).getServicesRegistry());
		} catch (ServiceException e) {
			e.printStackTrace();
			MessageDialog.openError(activeShell, "CHESS", "Unable to load the model");
		}
		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
		activeShell = window.getShell();

		// run CHESS Validate Core Constraints to validate the model before running analysis
		String label = "Validate model for CHESS Core Constraints";
		final Model model = (Model) inResource.getContents().get(0);		

		ChessGenericValidateCommand chessValidateCommand = new ChessGenericValidateCommand(label, 
				org.polarsys.chess.validator.Activator.PLUGIN_ID, model);	

		boolean go = false;
		if(chessValidateCommand != null) {
			try {
				chessValidateCommand.executeCommand(null, null);
			}
			catch (ExecutionException exception) {
				return null;
			}
			if (chessValidateCommand.getMarkers()) {
				org.eclipse.emf.common.util.Diagnostic diagnostic = chessValidateCommand.getDiagnostic();
				List<org.eclipse.emf.common.util.Diagnostic> diagList = diagnostic.getChildren();
				Boolean validationErrors = false;
				for (org.eclipse.emf.common.util.Diagnostic theDiag : diagList) {
					if (theDiag.getSource().equals(Constants.CHESS_VALIDATOR_PLUGIN) &&
							theDiag.getSeverity()>org.eclipse.emf.common.util.Diagnostic.WARNING) {
						validationErrors = true;
						break;						
					}
				}
				if (validationErrors) {
					go = MessageDialog.openQuestion(activeShell, "Validation Problems", "Errors found while validating the Model. Schedulability Analysis won't be performed correctly. Do you still want to continue?");
					if (!go) {
						return null;
					}
				}
			}
		} 
		else {
			MessageDialog.openError(activeShell, "Schedulability Analysis", "Problems while perfoming model validation before analysis");						
		}
		// end of model validation

		//open a dialog to select the schedulability analysis context to be analyzed
		//first get all the classes stereotyped as SaAnalysisContext
		final List<Class> selection = new ArrayList<Class>();		
		EList<Element> elemList = model.allOwnedElements();
		for (Element elem : elemList) {
			//we're looking for a class stereotyped <<saAnalysisContext>> and NOT in PSM
			if(elem instanceof Class && elem.getAppliedStereotype(TransUtil.SA_ANALYSIS_CTX) != null 
					&& !ViewUtils.isPSMView(ViewUtils.getView(elem))){
				//as additional constraint, no workload is specified
				SaAnalysisContext saAnalysisCtx = (SaAnalysisContext) elem.getStereotypeApplication
						(elem.getAppliedStereotype(TransUtil.SA_ANALYSIS_CTX));		
				if(saAnalysisCtx.getWorkload().size() == 0){
					selection.add((Class) elem);
				}
			}
		}
		if(selection.size() == 0){
			MessageDialog.openWarning(activeShell, "CHESS", "no suitable analysis contexts in the model");
			return null;
		}
		final List<CH_HwProcessor> chHwProcList = new ArrayList<CH_HwProcessor>();
		//then open the dialog
		String contextQN = null;
		AnalysisContextSelectionDialog dialog = new AnalysisContextSelectionDialog(activeShell, selection, "Select Schedulability Context to analyze");
		if (dialog.open() == Window.OK) {

		}else{
			return null;
		}
		contextQN = dialog.getContext();
		if(contextQN == null || contextQN.isEmpty()){
			return null;
		}

		Class contextClassTmp = null;
		for (Element elem : model.allOwnedElements()) {
			Stereotype saAnalysisContextStereo = elem.getAppliedStereotype(TransUtil.SA_ANALYSIS_CTX);
			if(saAnalysisContextStereo != null &&
					((NamedElement) elem).getQualifiedName().equals(contextQN)){
				contextClassTmp = (Class) elem;

				SaAnalysisContext saAnalysisContext = (SaAnalysisContext) elem.getStereotypeApplication(saAnalysisContextStereo);
				List<CH_HwProcessor> tmpList = getPlatformChHwProcessors(saAnalysisContext, model);
				chHwProcList.addAll(tmpList);

				// Check that the Context Platform contains two CHGaResourcePlatform instances, one in ComponentView, one in DeploymentView
				// and that at least on CH_HwPlatform is specified in the Context
				if (chHwProcList.isEmpty() || !UMLUtils.checkPlatformsInContext(saAnalysisContext, model)) {
					MessageDialog.openWarning(activeShell, "CHESS", "Context must specify a SW and a HW instance platform!");
					return null;
				}

				try {
					// Check that at least one Partition or Task is allocated on a Core of a ChHwProcessor specified in the Context
					if(!UMLUtils.checkAllocationToCores(chHwProcList, model)) {
						MessageDialog.openWarning(activeShell, "CHESS", "No partition or task allocated to Core!");
						return null;
					}
				} catch (ModelError e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
		}
		final Class contextClass = contextClassTmp;
		saAnalysisName = contextClass.getQualifiedName();
		psmPackageName = contextClass.getName() +"_PSM";

		final Job job = new Job("Transforming") {
			protected IStatus run(IProgressMonitor monitor) {
				try {

					TransformationResultsData result =null;
					try {
						//CHESSProjectSupport.installMAST();
						result = QVToUIHandlerVERDE.this.executeTimingAnalysis(editor, monitor);
						//Reopen the editor
						CHESSEditorUtils.reopenEditor(editor, false);
					} catch (Exception e) {
						throw e;
					} finally {
						getActiveProject(editor).refreshLocal(IResource.DEPTH_INFINITE, monitor);

					}

					//open sched analysis result

					try {
						//can active editor be different from just reopened CHESS ones? it should be not the case given that it has been just reopened
						//inResource = ResourceUtils.getUMLResource(((CHESSEditor) editor).getServicesRegistry());
						//Model model = (Model) inResource.getContents().get(0);

						ModelContent inModel = TransUtil.loadModel(result.umlFile);
						Model model = (Model) inModel.getContent().get(0);

						openSchedAnalysisReport(model, result.res, chHwProcList, contextClass);
					} catch (Exception e) {
						e.printStackTrace();
						throw new Exception("Unable to load the model and so open the schedAnalysisReport");
					}


				} catch (Exception e) {
					e.printStackTrace();
					return new Status(Status.ERROR, Activator.PLUGIN_ID, 1,
							"Error in transformation "+ e.getMessage(), null);
				}
				if (monitor.isCanceled())
					return Status.CANCEL_STATUS;
				return Status.OK_STATUS;
			}
		};
		job.addJobChangeListener(new JobChangeAdapter() {
			public void done(IJobChangeEvent event) {
				if (event.getResult().isOK())
					CHESSProjectSupport.printlnToCHESSConsole("Job completed successfully");
				else
					CHESSProjectSupport.printlnToCHESSConsole("Job did not complete successfully");
			}
		});
		job.setUser(true);
		job.setPriority(Job.SHORT);
		job.schedule();
		return null;
	}

	/**
	 * Returns the list of CH_HwProcessors in this analysisContext.
	 *
	 * @param saAnalysisContext the sa analysis context
	 * @param model the model
	 * @return the platform ch hw processors
	 */
	public static List<CH_HwProcessor> getPlatformChHwProcessors(
			SaAnalysisContext saAnalysisContext,
			Model model) {
		CH_HwProcessor chHwProcessor = null;
		List<CH_HwProcessor> chHwProcessorList = new ArrayList<CH_HwProcessor>();

		EList<GaResourcesPlatform> platformList = saAnalysisContext.getPlatform();
		for (GaResourcesPlatform theGaResPlatform : platformList) {
			if (theGaResPlatform instanceof CHGaResourcePlatform) {
				CHGaResourcePlatform chGaResPlat = (CHGaResourcePlatform)theGaResPlatform;
				org.eclipse.uml2.uml.Package thePackage = ViewUtils.getView(chGaResPlat.getBase_Package());

				if (ViewUtils.getCHESSDeploymentPackage(model)	== thePackage) {
					EList<Element> allElems = (chGaResPlat.getBase_Package().allOwnedElements());
					for (Element theElement : allElems) {
						if (theElement instanceof InstanceSpecification) {
							InstanceSpecification e = (InstanceSpecification) theElement;
							if (e.getQualifiedName() != null
									&& UMLUtils.isProcessorInstance(e)) {
								chHwProcessor = UMLUtils.getStereotypeApplication(e, CH_HwProcessor.class);	
								chHwProcessorList.add(chHwProcessor);
							}
						}
					}			
				}
			}
		}
		return chHwProcessorList;
	}

	/**
	 * Collects all the needed information and invokes the PIMPSMTransformationVERDE.performTimingAnalysisWithMAST method
	 *
	 * @param editor the editor
	 * @param monitor the monitor
	 * @return the string resulting from the MAST execution (i.e. the system is/not schedulable) and the modified model
	 * @throws Exception the exception
	 * @see org.polarsys.chess.m2m.transformations.PIMPSMTransformationVERDE#performTimingAnalysisWithMAST(PapyrusMultiDiagramEditor, IFile, IProgressMonitor)
	 */
	public TransformationResultsData executeTimingAnalysis(IEditorPart editor, IProgressMonitor monitor) throws Exception {
		monitor.beginTask("Transforming", 4);

		IFile inputFile = CHESSProjectSupport.resourceToFile(inResource);
		PIMPSMTransformationVERDE t = new PIMPSMTransformationVERDE();
		Map<String, String> configProps = new HashMap<String, String>();
		configProps.put("saAnalysis", saAnalysisName);
		configProps.put("analysisType", "Schedulability");
		t.setConfigProperty(configProps);
		t.setPsmPackageName(psmPackageName);
		final TransformationResultsData result = t.performTimingAnalysisWithMAST((PapyrusMultiDiagramEditor) editor, inputFile, monitor);

		//CHESSProjectSupport.fileReplace(newFile, inputFile);
		return result;
	}


	/**
	 * Open a simple, user-friendly report to display the analysis results.
	 *
	 * @param model the model
	 * @param result the result
	 * @param cpus the cpus
	 * @param saAnalysisContextClass the sa analysis context class
	 */
	public void openSchedAnalysisReport(Model model, final String result, 
			final List<CH_HwProcessor> cpus, 
			Class saAnalysisContextClass){

		if (result == null)
			return;

		if (saAnalysisContextClass == null) {
			return;
		}

		if(saAnalysisContextClass.eIsProxy()){
			saAnalysisContextClass = (Class) EcoreUtil.resolve(saAnalysisContextClass, model);
		}

		final List<HWAnalysisResultData> hwResults = UMLUtils.getHWAnalysisResults(saAnalysisContextClass);
		final List<AnalysisResultData> analysisResData = UMLUtils.getAnalysisResults(saAnalysisContextClass);
		//and open a simple, user-friendly report
		//	final List<CHRtPortSlot> specifications = new ArrayList<CHRtPortSlot>();
		//	for (Element elem : model.allOwnedElements()) {
		//		CHRtPortSlot chrtSlot = UMLUtils.getStereotypeApplication(elem, CHRtPortSlot.class);
		//		//if(chrtSlot != null && UMLUtils.getStereotypeApplication(chrtSlot.getBase_Slot().getOwner(), IdentifInstance.class) != null){
		//		if(chrtSlot != null){	
		//			specifications.add(chrtSlot);
		//		}
		//	};

		final Display display = PlatformUI.getWorkbench().getDisplay();
		display.asyncExec(new Runnable() {
			@Override
			public void run() {
				Shell shell = new Shell(display);

				//SchedResultDialog dialog = new SchedResultDialog(shell, result, specifications, cpus, hwResults);
				SchedResultDialog dialog = new SchedResultDialog(shell, result, analysisResData, hwResults);
				if (dialog.open() == Window.OK) {
					System.out.println("OK");
				}
			}
		});
	}

	//	@SuppressWarnings("unused")
	//	private ModelSet getEditorResourceSet(IEditorPart editor)
	//			throws Exception {
	//		ModelSet resourceSet = null;
	//		try {
	//			resourceSet = (ModelSet)((ServicesRegistry)editor.getAdapter(ServicesRegistry.class)).getService(ModelSet.class);
	//		} catch (ServiceException e) {
	//			e.printStackTrace();
	//			throw new Exception("Unable to get the service registry");
	//		}
	//		return resourceSet;
	//	}
}
