/**
 * Copyright (c) 2016 committers of YAKINDU and others.
 * 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-v10.html
 * Contributors:
 * 	committers of YAKINDU - initial API and implementation
 * 
 */
package org.yakindu.sct.ui.editor.providers;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker;
import org.eclipse.gmf.runtime.diagram.core.listener.NotificationListener;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditDomain;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecorator;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget;
import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.ui.IEditorPart;
import org.yakindu.base.gmf.runtime.decorators.AbstractDecoratorProvider;
import org.yakindu.base.gmf.runtime.decorators.BaseDecorator;
import org.yakindu.sct.model.sgraph.SGraphPackage;
import org.yakindu.sct.model.sgraph.Transition;
import org.yakindu.sct.model.sgraph.Vertex;
import org.yakindu.sct.ui.editor.DiagramActivator;
import org.yakindu.sct.ui.editor.editor.StatechartDiagramEditor;
import org.yakindu.sct.ui.editor.editor.figures.PriorityFigure;
import org.yakindu.sct.ui.editor.editparts.TransitionEditPart;
import org.yakindu.sct.ui.editor.preferences.StatechartPreferenceConstants;

/**
 * @author andreas muelder - Initial contribution and API
 */
public class TransitionPriorityDecorationProvider extends AbstractDecoratorProvider implements IPropertyChangeListener {

	private static final String PRIORITY_ID = TransitionPriorityDecorationProvider.class.getSimpleName();
	private List<IDecorator> decorators;

	public TransitionPriorityDecorationProvider() {
		decorators = new ArrayList<>();
		DiagramActivator.getDefault().getPreferenceStore().addPropertyChangeListener(this);
	}

	@Override
	public void createDecorators(IDecoratorTarget decoratorTarget) {
		EditPart editPart = (EditPart) decoratorTarget.getAdapter(EditPart.class);
		if (editPart instanceof GraphicalEditPart || editPart instanceof AbstractConnectionEditPart) {
			EditDomain ed = editPart.getViewer().getEditDomain();
			if (!(ed instanceof DiagramEditDomain)) {
				return;
			}
			if (shouldInstall(((DiagramEditDomain) ed).getEditorPart()) && editPart instanceof TransitionEditPart) {
				IDecorator decorator = createStatusDecorator(decoratorTarget);
				decorators.add(decorator);
				decoratorTarget.installDecorator(getDecoratorKey(), decorator);
			}
		}
	}

	protected IDecorator createStatusDecorator(IDecoratorTarget decoratorTarget) {
		return new PriorityDecorator(decoratorTarget);
	}

	protected Object getDecoratorKey() {
		return PRIORITY_ID;
	}

	protected boolean shouldInstall(IEditorPart editorPart) {
		return (editorPart instanceof StatechartDiagramEditor);
	}

	public static class PriorityDecorator extends BaseDecorator {

		private Vertex owningElement;

		public PriorityDecorator(IDecoratorTarget decoratorTarget) {
			super(decoratorTarget);
		}

		protected NotificationListener transitionPriorityChangeListener = new NotificationListener() {

			public void notifyChanged(Notification notification) {
				if (notification.getFeatureID(Vertex.class) == SGraphPackage.VERTEX__OUTGOING_TRANSITIONS)
					refresh();
			}
		};

		@Override
		public void activate() {
			super.activate();
			if (!(semanticElement instanceof Transition)
					|| !(((Transition) semanticElement).eContainer() instanceof Vertex)) {
				return;
			}
			if (((Transition) semanticElement).eContainer() != null) {
				owningElement = (Vertex) ((Transition) semanticElement).eContainer();
				DiagramEventBroker.getInstance(gep.getEditingDomain()).addNotificationListener(owningElement,
						transitionPriorityChangeListener);
			}
		}

		@Override
		public void deactivate() {
			if (!(semanticElement instanceof Transition)) {
				return;
			}
			if (owningElement != null) {
				DiagramEventBroker.getInstance(gep.getEditingDomain()).removeNotificationListener(owningElement,
						transitionPriorityChangeListener);
				owningElement = null;
			}
			super.deactivate();
		}

		@Override
		public void refresh() {
			removeDecoration();
			boolean showLabels = DiagramActivator.getDefault().getPreferenceStore()
					.getBoolean(StatechartPreferenceConstants.PREF_PRIORITY_LABELS);
			if (!showLabels)
				return;
			View view = (View) getDecoratorTarget().getAdapter(View.class);
			if (view == null || view.eResource() == null) {
				return;
			}
			EditPart editPart = (EditPart) getDecoratorTarget().getAdapter(EditPart.class);
			if (editPart == null || editPart.getViewer() == null) {
				return;
			}
			if (editPart instanceof TransitionEditPart && (needsDecoration((TransitionEditPart) editPart)))
				createDecorators((TransitionEditPart) editPart);
		}

		public boolean needsDecoration(TransitionEditPart editPart) {
			Transition transition = (Transition) editPart.resolveSemanticElement();
			Vertex container = (Vertex) transition.eContainer();
			return container.getOutgoingTransitions().size() > 1;

		}

		public void createDecorators(TransitionEditPart editPart) {
			PriorityFigure figure = new PriorityFigure(MapModeUtil.getMapMode(), getPriority(editPart));
			figure.setSize(10, 10);
			setDecoration(getDecoratorTarget().addConnectionDecoration(figure, 5, false));
		}

		public int getPriority(TransitionEditPart editPart) {
			Transition transition = ((Transition) editPart.resolveSemanticElement());
			Vertex container = (Vertex) transition.eContainer();
			int indexOf = container.getOutgoingTransitions().indexOf(transition);
			// visible priorities should start with 1
			return indexOf + 1;
		}
	}

	@Override
	public void propertyChange(PropertyChangeEvent event) {
		if (StatechartPreferenceConstants.PREF_PRIORITY_LABELS.equals(event.getProperty())) {
			for (IDecorator decorator : decorators) {
				decorator.refresh();
			}
		}
	}
}
