CHESSIoT_Dev_old-master/org.polarsys.chess.core/src/org/polarsys/chess/core/views/DiagramStatus.java
/*
-----------------------------------------------------------------------
--          			CHESS core plugin							 --
--                                                                   --
--                    Copyright (C) 2016                             --
--                 University of Padova, ITALY                       --
--                                                                   --
-- Authors: Alessandro Zovi          azovi@math.unipd.it             --
--          Laura Baracchi           laura.baracchi@intecs.it        --
--          Stefano Puri             stefano.puri@intecs.it          --
--                                                                   --
-- 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.core.views;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Stack;

import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.papyrus.editor.PapyrusMultiDiagramEditor;
import org.eclipse.papyrus.emf.facet.custom.metamodel.v0_2_0.internal.treeproxy.EObjectTreeElement;
import org.eclipse.papyrus.infra.core.sasheditor.editor.IPage;
import org.eclipse.papyrus.infra.core.sashwindows.di.PageRef;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Stereotype;
import org.polarsys.chess.chessmlprofile.Core.CHESS;
import org.polarsys.chess.chessmlprofile.Core.Domain;
import org.polarsys.chess.chessmlprofile.util.Constants;
import org.polarsys.chess.core.internal.views.InternalViewUtils;
import org.polarsys.chess.core.internal.views.ViewPermissions;
import org.polarsys.chess.core.internal.views.permissions.PermissionEntry;
import org.polarsys.chess.core.internal.views.permissions.PermissionList;
import org.polarsys.chess.core.profiles.CHESSProfileManager;
import org.polarsys.chess.core.util.CHESSProjectSupport;
import org.polarsys.chess.core.util.uml.ResourceUtils;



/**
 * This class is registered as a CHESS service and allow the programmer to know
 * at any time the diagram that the user is working on. This is mandatory to
 * know the current view and thus to execute view-specific constraints during
 * the editing of the model.
 * 
 * @author Alessandro Zovi
 * 
 */
public class DiagramStatus {


	/**
	 * The DesignView must be treated as a singleton service class. It is an integral part of DiagramStatus service.
	 *
	 */
	public static class DesignView {

		/** The views. */
		Hashtable<String, Boolean> views;
		//		Hashtable<String, PermissionList> permissions = ViewPermissions.permissions;
		//		Hashtable<String, PermissionList> permissions = new Hashtable<String, PermissionList>(
		//				CHESSProfileManager.CHESS_VIEWS_LIST.size());

		/** The concur num. */
		short enabledNum = 0, concurNum = 0;

		/** The current diagram. */
		String currentDiagram = null;

		/**
		 * Instantiates a new design view.
		 */
		private DesignView() {

			views = new Hashtable<String, Boolean>(
					CHESSProfileManager.CHESS_VIEWS_LIST.size());
			//Force loading of permissions
			try {
				Class.forName(ViewPermissions.class.getName());
			} catch (Exception e) {
				// TODO: handle exception
			}
			clearAll();
		}

		/**
		 * Clear all.
		 */
		private void clearAll() {
			for (String v : CHESSProfileManager.CHESS_VIEWS_LIST) {
				views.put(v, false);
			}
			enabledNum = 0;
			concurNum = 0;
		}

		/**
		 * Clear not concurrent.
		 *
		 * @param view the view
		 */
		private void clearNotConcurrent(String view) {
			//disable all non-concurrent views.
			for (String v : CHESSProfileManager.CHESS_VIEWS_LIST) {
				if (!CHESSProfileManager.CONCURRENT_VIEWS.contains(v)) {
					views.put(v, false);
				}
			}
			//disable all the concurrent views of top of others view
			for (String k : CHESSProfileManager.CONCURRENT_VIEWS_ASSOCIATION.keySet()) {
				if (!CHESSProfileManager.CONCURRENT_VIEWS_ASSOCIATION.get(k).contains(view)) {
					for(String l : CHESSProfileManager.CONCURRENT_VIEWS_ASSOCIATION.get(k)){
						views.put(l, false);
					}
				}
			}

			enabledNum = 0;
		}

		/**
		 * Enable view.
		 *
		 * @param view the view
		 */
		void enableView(String view) {
			if (view == null) {
				clearAll();
			} else if (CHESSProfileManager.CONCURRENT_VIEWS.contains(view)) {
				clearNotConcurrent(view);
				views.put(view, true);
				++concurNum;
			} else {
				clearAll();
				views.put(view, true);
				++enabledNum;
				assert (enabledNum == 1);
			}
		}

		/**
		 * Disable view.
		 *
		 * @param view the view
		 */
		void disableView(String view){
			views.put(view, false);
			--concurNum;
		}


		/**
		 * Gets the names of the active design views.
		 * 
		 * If more that one design view is active then this method concatenates the names.
		 * 
		 * @return the resulting name.
		 */
		public String getName() {
			ArrayList<String> names = new ArrayList<String>();

			for (String v : CHESSProfileManager.CHESS_VIEWS_LIST) {
				if (views.get(v)) {
					names.add(v);
				}
			}

			if (names.size()==0)
				return CHESSProfileManager.NULL_VIEW;
			if (names.size()==1)
				return names.get(0);


			Collections.sort(names);

			StringBuffer name = new StringBuffer();

			for (int i = 0; i < names.size() - 1; i++) {
				name.append(names.get(i)).append('-');
			}
			name.append(names.get(names.size()-1));

			return name.toString();
		}

		/**
		 * Checks is a view is enabled by providing its name.
		 * 
		 * @param view  the view name
		 * @return true if it is enable
		 */
		public boolean isEnabled(String view) {
			return views.get(view);
		}

		/**
		 * Returns the current active diagram name.
		 *
		 * @return the name of the active diagram
		 */
		public String getCurrentDiagramName(){
			return currentDiagram;
		}

		/**
		 * Returns the permissions associated with the view and the diagram provided by name.
		 * 
		 * @param view  the name of the view
		 * @param diagram  the name of the diagram
		 * @return the {@link PermissionList} associated with the view and the diagram
		 */
		private PermissionList getViewPermissions(String view, String diagram) {

			if (diagram.equals(ViewDiagramAssociations.ANYDIAGRAM)){
				return ViewPermissions.permissions.get(view).get(diagram);
			}else{
				PermissionList list = new PermissionList();
				PermissionList d = ViewPermissions.permissions.get(view).get(ViewDiagramAssociations.ANYDIAGRAM);
				if (d != null)
					list.addAll(d);
				String actualDiagram = ViewDiagramAssociations.papyrusNames2Standard.get(diagram);
				HashMap<String, PermissionList> viewPermissions = ViewPermissions.permissions.get(view);
				d = viewPermissions.get(actualDiagram);
				if (d != null)
					list.addAll(d);
				return list;
			}
		}


		/**
		 * Returns the permissions associated with the view and the diagram provided by name.
		 * 
		 * @param view  the name of the view
		 * @param diagram  the name of the diagram
		 * @param domain the domain
		 * @return the {@link PermissionList} associated with the view and the diagram
		 */
		private PermissionList getViewPermissionsPerDomain(String view, String diagram, Domain domain) {

			PermissionList list = new PermissionList();			

			PermissionList d = ViewPermissions.permissions.get(view).get(ViewDiagramAssociations.ANYDIAGRAM);
			if (d != null) {
				for (PermissionEntry pe: d) {
					if (pe.getDomain().equals(Domain.CROSS_DOMAIN) || 
							pe.getDomain().equals(domain)) {
						list.add(pe);
					}
				}
			}

			String actualDiagram = ViewDiagramAssociations.papyrusNames2Standard.get(diagram);
			HashMap<String, PermissionList> viewPermissions = ViewPermissions.permissions.get(view);
			d = viewPermissions.get(actualDiagram);
			if (d != null) {
				for (PermissionEntry pe: d) {
					if (pe.getDomain().equals(Domain.CROSS_DOMAIN) || 
							pe.getDomain().equals(domain)) {
						list.add(pe);
					}
				}
			}
			
			return list;
		}

		/**
		 * Returns all the enabled permissions based on the enabled views.
		 *
		 * @param theDomain the the domain
		 * @return the {@link PermissionList} with all the enabled permissions
		 */
		public PermissionList getEnabledPermissions(Domain theDomain) {
			//TODO code must be refactored to avoid continuous generation of permissions!

			if (concurNum > 1) {
				PermissionList union = new PermissionList();
				for (String v : CHESSProfileManager.CONCURRENT_VIEWS) {
					if (views.get(v)) {
						//union.addAll(getViewPermissions(v, currentDiagram));
						union.addAll(getViewPermissionsPerDomain(v, currentDiagram, theDomain));
					}
				}
				return union;
			}
			for (String v : CHESSProfileManager.CHESS_VIEWS_LIST) {
				if (views.get(v)) {
					//return getViewPermissions(v, currentDiagram);
					return getViewPermissionsPerDomain(v, currentDiagram, theDomain);
				}
			}
			return null;
		}


		/**
		 * Returns all the enabled permissions based on the given view.
		 *
		 * @param viewName the view name
		 * @param theDomain the the domain
		 * @return the {@link PermissionList} with all the enabled permissions
		 */
		public PermissionList getEnabledPermissions(String viewName, Domain theDomain) {

			if (concurNum > 1) {
				PermissionList union = new PermissionList();
				for (String v : CHESSProfileManager.CONCURRENT_VIEWS) {
					if (v.equals(viewName))
						//union.addAll(getViewPermissions(v, currentDiagram));
						union.addAll(getViewPermissionsPerDomain(v, currentDiagram, theDomain));
				}
				return union;
			}
			for (String v : CHESSProfileManager.CHESS_VIEWS_LIST) {
				if (v.equals(viewName)) {
					//return getViewPermissions(v, currentDiagram);
					return getViewPermissionsPerDomain(v, currentDiagram, theDomain);
				}
			}
			return null;
		}

		/**
		 * Checks if the diagram passed as a parameter is allowed in the enabled views.
		 * 
		 * A diagram is allowed in a view if that view contains a permissions list for the diagram.
		 * 
		 * @param diagram  the diagram
		 * @return true if the diagram is allowed
		 */
		public boolean isDiagramAllowed(final Diagram diagram) {
			if (concurNum > 1) {
				for (String v : CHESSProfileManager.CONCURRENT_VIEWS) {
					HashSet<String> h;
					if (views.get(v) &&
							null != (h = ViewDiagramAssociations.viewDiagramsAssociation.get(v))) {
						if (h.contains(diagram.getType())) {
							return true;
						}
					}
				}
				return false;
			} else {
				for (String v : CHESSProfileManager.CHESS_VIEWS_LIST) {
					HashSet<String> h;
					if (views.get(v) &&
							null != (h = ViewDiagramAssociations.viewDiagramsAssociation.get(v))) {
						return (h.contains(diagram.getType()));
					}
				}
				return false;
			}
		}


	}

	// private IPage currentDiagram;

	/**
	 * Represents the concrete view, that is the design view associated to the root Package
	 * containing all the elements that model a specific concern.
	 */
	private Package actualView;

	/** The current design view. */
	private DesignView currentDesignView = new DesignView();

	/** The concurrent toggles. */
	private HashMap<String, Boolean> concurrentToggles = new HashMap<String, Boolean>(CHESSProfileManager.CONCURRENT_VIEWS.size());

	/** The is user. */
	private boolean isUser = true;

	/** The superuser. */
	private boolean superuser = false;

	/** The last toggled view. */
	private Stack<String> lastToggledView = new Stack<String>();

	/**
	 * Instantiates a new diagram status.
	 */
	public DiagramStatus() {
		disableAllToggles();
	}

	/**
	 * Creates the DiagramStatus service given the initial {@link IPage} that corresponds to a Papyrus diagram.
	 *
	 * @param initialDiagram  the initial IPage that corresponds to a Papyrus diagram
	 */
	public DiagramStatus(IPage initialDiagram) {
		disableAllToggles();
		setActualView(initialDiagram);

	}

	/**
	 * Disable all toggles.
	 */
	private void disableAllToggles() {
		for (String view : CHESSProfileManager.CONCURRENT_VIEWS) {
			concurrentToggles.put(view, false);
		}
	}

	/*@Deprecated
	public Package getActualView() {
		return actualView;
	}*/

	/**
	 * Gets the current view.
	 *
	 * @return the current view
	 */
	public synchronized DesignView getCurrentView() {
		if (actualView == null)
			return null;
		return currentDesignView;
	}

	/**
	 * Request the extra-functional view, and return whether the extra functional
	 * view is being activated or not.
	 *
	 * @param view  the name of the requested view
	 * @param activate  true to request the view and activate it, false to deactivate it
	 * @return true, if successful
	 */
	private boolean requestConcurrentView(String view, boolean activate) {
		concurrentToggles.put(view, activate);
		if (activate)
			lastToggledView.push(view);
		else if (lastToggledView.peek().equals(view))
			lastToggledView.pop();
		setCurrentView();
		return concurrentToggles.get(view);
	}

	/**
	 * Returns the name of the active view.
	 * 
	 * @return the name of the active view
	 */
	public String getActiveView(){
		return lastToggledView.peek();
	}

	/**
	 * Request the activation/deactivation of a view given its name.
	 * 
	 * 
	 * @param view  the name of the view
	 * @param activate  true to request the activation, false to request the deactivation
	 * @return  true when the request succeed
	 */
	public boolean requestView(String view, boolean activate) {
		if (CHESSProfileManager.CONCURRENT_VIEWS.contains(view))
			return requestConcurrentView(view, activate);
		return false;
	}

	/**
	 * Set the actual view given a diagram represented by an {@link IPage}.
	 *
	 * @param currentDiagram  the diagram
	 */
	public synchronized void setActualView(IPage currentDiagram) {
		if (currentDiagram != null) {
			if (((PageRef) currentDiagram.getRawModel()).getEmfPageIdentifier() instanceof Diagram) {
				Diagram dg = ((Diagram) ((PageRef) currentDiagram.getRawModel())
						.getEmfPageIdentifier());
				Package newActualView = currentDiagram == null ? null : ViewUtils
						.getView(dg.getElement());
				// System.out.println(actualView == null ? "null view" :
				// actualView.getName());
				currentDesignView.currentDiagram = dg.getType();

				if (actualView != null && 
						newActualView != null){

					String av = InternalViewUtils.getViewName(actualView);
					String nv = InternalViewUtils.getViewName(newActualView);

					if (av!= null && nv!=null && !av.equals(nv)){
						disableAllToggles();
					}
				}


				actualView = newActualView;

				setCurrentView();
			}
		}
	}

	/**
	 * Sets the actual view given the tree selection.
	 * 
	 * @param currentTreeViewSelection  the tree selection
	 */
	public synchronized void setActualView(
			TreeSelection currentTreeViewSelection) {
		TreeSelection tSelection = currentTreeViewSelection;
		EObjectTreeElement elem = (EObjectTreeElement) tSelection.getFirstElement();

		Package newActualView = currentTreeViewSelection == null ? null : ViewUtils
				.getView(elem.getEObject());

		currentDesignView.currentDiagram = ViewDiagramAssociations.ANYDIAGRAM;

		if (actualView != null && newActualView != null && !InternalViewUtils.getViewName(actualView).equals(InternalViewUtils.getViewName(newActualView)))
			disableAllToggles();

		actualView = newActualView;

		setCurrentView();
	}

	/**
	 * Sets the current view.
	 */
	private synchronized void setCurrentView() {
		if (actualView == null) {
			currentDesignView.enableView(null);
			lastToggledView.removeAllElements();
			disableAllToggles();
		} else if (ViewUtils.hasConcurrentViews(InternalViewUtils.getViewName(actualView))) {
			// inspect toggles
			boolean toggled = false;
			for (String concurrentView : CHESSProfileManager.CONCURRENT_VIEWS_ASSOCIATION.get(InternalViewUtils.getViewName(actualView))) {
				if (concurrentToggles.get(concurrentView)){
					currentDesignView.enableView(concurrentView);
					//					if (concurrentView.equals(lastToggledView))
					toggled = true;
				} else {
					currentDesignView.disableView(concurrentView);
				}
			}
			if (!toggled) {

				//lastToggledView = ViewUtils.getViewName(actualView);
				lastToggledView.removeAllElements();
				lastToggledView.push(InternalViewUtils.getViewName(actualView));
				currentDesignView.enableView(InternalViewUtils.getViewName(actualView));
			}
		} else {
			// if this views has no concurrent views,
			// match currentView with actualView and disable toggles
			//lastToggledView = ViewUtils.getViewName(actualView);
			lastToggledView.removeAllElements();
			lastToggledView.push(InternalViewUtils.getViewName(actualView));
			currentDesignView.enableView(InternalViewUtils.getViewName(actualView));
			disableAllToggles();
		}
	}

	/**
	 * Set if the action is done by the user or is done by something else.
	 * 
	 * For example an automated action is not a user action.
	 * An automated action usually undergo less permission checks.
	 * 
	 * @param b  true to set the action to true.
	 */
	public synchronized void setUserAction(boolean b) {
		isUser = b;
	}

	/**
	 * Checks if the action is done by the user or not.
	 *
	 * @return true, if is user action
	 */
	public boolean isUserAction(){
		return isUser;
	}

	/**
	 * Checks if the DiagramStatus service is in superuser mode.
	 * 
	 * In this mode permissions are not checked.
	 * 
	 * @return true if DiagramStatus is in superuser mode.
	 */
	public boolean isSuperuser() {
		return superuser;
	}

	/**
	 * Sets the superuser mode.
	 * 
	 * @param b  true to set the superuser mode, false otherwise
	 */
	public void setSuperuser(boolean b){
		superuser = b;
	}


}
