/*******************************************************************************
 * Copyright (c) 2005 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.bpel.ui.editparts;

import org.eclipse.bpel.common.ui.markers.IModelMarkerConstants;
import org.eclipse.bpel.ui.BPELUIPlugin;
import org.eclipse.bpel.ui.IBPELUIConstants;
import org.eclipse.bpel.ui.adapters.ILabeledElement;
import org.eclipse.bpel.ui.adapters.IMarkerHolder;
import org.eclipse.bpel.ui.editparts.borders.DrawerBorder;
import org.eclipse.bpel.ui.editparts.borders.LeafBorder;
import org.eclipse.bpel.ui.editparts.figures.GradientFigure;
import org.eclipse.bpel.ui.editparts.policies.BPELSelectionEditPolicy;
import org.eclipse.bpel.ui.editparts.util.BPELDecorationLayout;
import org.eclipse.bpel.ui.figures.CenteredConnectionAnchor;
import org.eclipse.bpel.ui.util.BPELUtil;
import org.eclipse.bpel.ui.util.marker.BPELEditPartMarkerDecorator;
import org.eclipse.core.resources.IMarker;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.FlowLayout;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPolicy;
import org.eclipse.swt.graphics.Image;


/**
 * This is the superclass of BPEL activities that are leaves. That is, activities
 * which don't contain other activities. Leaf activities currently are laid out
 * in a horizontal manner with icon and label, with a simple border surrounding.
 */
public class LeafEditPart extends ActivityEditPart {

	protected Image image, topImage, bottomImage;
	protected Label imageLabel, nameLabel;
	protected LeafBorder border;

	// Marker support
	protected IFigure contentFigure;
	protected BPELEditPartMarkerDecorator editPartMarkerDecorator;
		
	/**
	 * 
	 * @author IBM
	 * @author Michal Chmielewski (michal.chmielewski@oracle.com)
	 * @date May 23, 2007
	 *
	 */
	public static class LeafDecorationLayout extends BPELDecorationLayout {
		
		@Override
		protected Point calculateLocation(int locationHint, IFigure container, Dimension childDimension) {
			Point result = super.calculateLocation(locationHint, container, childDimension);
			// if it is somewhere on the left we need to add the drawer space
			if ((locationHint & PositionConstants.LEFT) != 0) {
				result.x += DrawerBorder.DRAWER_WIDTH;
			}
			// if it is somewhere on the right we need to remove the drawer space
			if ((locationHint & PositionConstants.RIGHT) != 0) {
				result.x -= DrawerBorder.DRAWER_WIDTH;
			}
			return result;
		}
	}
	
	
	@Override
	protected void createEditPolicies() {
		super.createEditPolicies();
		
		// Show the selection rectangle
		installEditPolicy(EditPolicy.SELECTION_FEEDBACK_ROLE, new BPELSelectionEditPolicy(false, true) {
			@Override
			protected int getDrawerInset() {
				return DrawerBorder.DRAWER_WIDTH;
			}
			@Override
			protected int getWestInset() {
				return DrawerBorder.DRAWER_WIDTH ;
			}
			@Override
			protected int getEastInset() {
				return DrawerBorder.DRAWER_WIDTH ;
			}
			@Override
			protected int getNorthInset() {
				return 0;
			}
			@Override
			protected int getSouthInset() {
				return 0;
			}
		});
	}
	
	
	@Override
	protected IFigure createFigure() {
		if (image == null) {
			// Create the actual figure for the edit part
			ILabeledElement element = BPELUtil.adapt(getActivity(), ILabeledElement.class);
			image = element.getSmallImage(getActivity());
		}
		IFigure gradient = new GradientFigure(getModel());
		FlowLayout layout = new FlowLayout();
		layout.setMinorAlignment(FlowLayout.ALIGN_CENTER);
		gradient.setLayoutManager(layout);
		
		gradient.setForegroundColor(BPELUIPlugin.INSTANCE.getColorRegistry().get(IBPELUIConstants.COLOR_BLACK));

		this.imageLabel = new Label(image);
		gradient.add(imageLabel);
		this.nameLabel = new Label(getLabel());
		gradient.add(nameLabel);
		
		this.contentFigure = gradient;
		
		if (editPartMarkerDecorator == null) {
			editPartMarkerDecorator = new BPELEditPartMarkerDecorator(
				(EObject)getModel(),
				new LeafDecorationLayout()
			);
			editPartMarkerDecorator.addMarkerMotionListener(getMarkerMotionListener());
		}

		IFigure result = editPartMarkerDecorator.createFigure(gradient);
		
		this.border = new LeafBorder(editPartMarkerDecorator.getDecorationLayer());
		this.border.setEditPart(this);
		gradient.setBorder(border);
		gradient.addMouseMotionListener(getMouseMotionListener());
		refreshDrawerImages();
		return result;
	}  
	
	protected void refreshDrawerImages() {
		if (topImage != null) {
			topImage.dispose();
			topImage = null;
		}
		if (bottomImage != null) {
			bottomImage.dispose();
			bottomImage = null;
		}
		
		IMarkerHolder holder = BPELUtil.adapt(getActivity(), IMarkerHolder.class);
		
		int topMarkerPriority = Integer.MIN_VALUE;
		int bottomMarkerPriority = Integer.MIN_VALUE;
		
		IMarker topMarker = null;
		IMarker bottomMarker = null;
		
		for(IMarker marker : holder.getMarkers(getActivity()))  {
			
			if (marker.getAttribute(IModelMarkerConstants.DECORATION_MARKER_VISIBLE_ATTR, true) == false) {
				continue;
			}
			
			String value = marker.getAttribute(IModelMarkerConstants.DECORATION_GRAPHICAL_MARKER_ANCHOR_POINT_ATTR, EMPTY_STRING); 
			
			if (value.equals(IBPELUIConstants.MARKER_ANCHORPOINT_DRAWER_TOP)) {
				int priority = marker.getAttribute(IModelMarkerConstants.DECORATION_MARKER_PRIORITY_ATTR, 0);
				if (priority > topMarkerPriority) {
					topMarkerPriority = priority;
					topImage = BPELUtil.getImage(marker);
					topMarker = marker;
				}
			} else if (value.equals(IBPELUIConstants.MARKER_ANCHORPOINT_DRAWER_BOTTOM)) {
				int priority = marker.getAttribute(IModelMarkerConstants.DECORATION_MARKER_PRIORITY_ATTR, 0);
				if (priority > bottomMarkerPriority) {
					bottomMarkerPriority = priority;
					bottomImage = BPELUtil.getImage(marker);
					bottomMarker = marker;
				}
			}
		}
		
		border.setTopImage(topImage);
		border.setBottomImage(bottomImage);
		border.setTopMarker(topMarker);
		border.setBottomMarker(bottomMarker);
	}
	
	/**
	 * Overrides for direct edit 
	 */
	@Override
	public Label getLabelFigure() {
		return nameLabel;
	}
	
	/**
	 * @see org.eclipse.bpel.ui.editparts.BPELEditPart#getLabelContent()
	 */
	@Override
	public String getLabelContent() {
		return getLabel();
	}
		
	
	/**
	 * @see org.eclipse.gef.editparts.AbstractEditPart#refreshVisuals()
	 */
	@Override
	public void refreshVisuals() {
		refreshDrawerImages();
		super.refreshVisuals();
		// The name has changed, change the corresponding label
		nameLabel.setText(getLabel());
		editPartMarkerDecorator.refresh();
		// Force a repaint, as the drawer images may have changed.
		getFigure().repaint();
	}
	
	protected String getLabel() {
		ILabeledElement element = BPELUtil.adapt(getActivity(), ILabeledElement.class);
		return element.getLabel(getActivity());
	}
	
	
	@Override
	protected void unregisterVisuals() {
		if (contentFigure != null) {
			contentFigure.removeMouseMotionListener(getMouseMotionListener());
		}
		if (editPartMarkerDecorator != null) {
			editPartMarkerDecorator.removeMarkerMotionListener(markerMotionListener);
		}
		this.image = null;
		this.editPartMarkerDecorator = null;
		this.topImage = null;
		this.bottomImage = null;
		super.unregisterVisuals();
	}
	
	// TODO: Why do we override this?
//	/**
//	 * Returns the connection anchor for the given
//	 * ConnectionEditPart's source. 
//	 *
//	 * @return  ConnectionAnchor.
//	 */
//	@Override
//	public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connEditPart) {
//		// This may be called when the model is disconnected. If so, return null.
//		if (getActivity().eResource() == null) return null;
//
//		// Leaf nodes can be the source of both implicit and link connections.
//		// However, they both anchor at the same part of the edit part.
//		return new CenteredConnectionAnchor(getMainActivityFigure(), CenteredConnectionAnchor.BOTTOM, 0);
//	}
//	
//	
//
//	/**
//	 * Returns the connection anchor for the given 
//	 * ConnectionEditPart's target.
//	 *
//	 * @return  ConnectionAnchor.
//	 */
//	@Override
//	public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connEditPart) {
//		// This may be called when the model is disconnected. If so, return null.
//		if (getActivity().eResource() == null) {
//			return null;
//		}
//		
//		ConnectionAnchor anc = null;
//		
//		// Leaf nodes can be the target of both implicit and link connections.
//		// However, they both anchor at the same part of the edit part.
//		if (anc == null)
//			anc = new CenteredConnectionAnchor(getMainActivityFigure(), CenteredConnectionAnchor.TOP, 0);
//		return anc;
//	}
	@Override
	public ConnectionAnchor getConnectionAnchor(int location) {
		switch(location){
		case CenteredConnectionAnchor.LEFT:
			return new CenteredConnectionAnchor(getFigure(), CenteredConnectionAnchor.LEFT_INNER, 0);
		case CenteredConnectionAnchor.RIGHT:
			return new CenteredConnectionAnchor(getFigure(), CenteredConnectionAnchor.RIGHT_INNER, 0);
		default:
				return super.getConnectionAnchor(location);
		}
	}
	
	
	/**
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getContentPane()
	 */
	
	@Override
	public IFigure getContentPane() {
		return contentFigure;
	}

	
	@Override
	protected DrawerBorder getDrawerBorder() {
		return border;
	}
}