// based on GEF ShapesEditor example
/*******************************************************************************
 * Copyright (c) 2004, 2005 Elias Volanakis 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:
 *    Elias Volanakis - initial API and implementation
 *******************************************************************************/
package jp.hasc.hasctool.ui.bdeditor2.parts;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;

import jp.hasc.hasctool.core.blockdiagram.model.BeanBlock;
import jp.hasc.hasctool.ui.bdeditor2.model.BlockDiagramElement;
import jp.hasc.hasctool.ui.bdeditor2.model.BlockElement;
import jp.hasc.hasctool.ui.bdeditor2.model.ConnectionElement;
import jp.hasc.hasctool.ui.bdeditor2.model.ModelElement;
import jp.hasc.hasctool.ui.bdeditor2.model.commands.ConnectionCreateCommand;
import jp.hasc.hasctool.ui.bdeditor2.model.commands.ConnectionReconnectCommand;

import org.eclipse.draw2d.ChopboxAnchor;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.RectangleFigure;
import org.eclipse.draw2d.StackLayout;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.ReconnectRequest;

/**
 * @author iwasaki
 */
@SuppressWarnings("rawtypes")
public class BlockEditPart extends AbstractGraphicalEditPart implements
		PropertyChangeListener, NodeEditPart {

	private ConnectionAnchor anchor;

	/**
	 * Upon activation, attach to the model element as a property change
	 * listener.
	 */
	@Override
	public void activate() {
		if (!isActive()) {
			super.activate();
			((ModelElement) getModel()).addPropertyChangeListener(this);
		}
	}

	@Override
	protected void createEditPolicies() {
		// allow removal of the associated model element
		installEditPolicy(EditPolicy.COMPONENT_ROLE,
				new ModelElementComponentEditPolicy());
		// allow the creation of connections and
		// and the reconnection of connections between Shape instances
		installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE,
				new GraphicalNodeEditPolicy() {
					@Override
					protected Command getConnectionCompleteCommand(
							CreateConnectionRequest request) {
						ConnectionCreateCommand cmd = (ConnectionCreateCommand) request
								.getStartCommand();
						cmd.setTarget((BlockElement) getHost().getModel());
						return cmd;
					}

					@Override
					protected Command getConnectionCreateCommand(
							CreateConnectionRequest request) {
						BlockDiagramElement parent = (BlockDiagramElement) getHost().getParent().getModel();
						BlockElement source = (BlockElement) getHost().getModel();
						ConnectionCreateCommand cmd = new ConnectionCreateCommand(
								this, parent, source);
						request.setStartCommand(cmd);
						return cmd;
					}

					@Override
					protected Command getReconnectSourceCommand(
							ReconnectRequest request) {
						ConnectionElement conn = (ConnectionElement) request
								.getConnectionEditPart().getModel();
						BlockElement newSource = (BlockElement) getHost().getModel();
						ConnectionReconnectCommand cmd = new ConnectionReconnectCommand(
								conn);
						cmd.setNewSource(newSource);
						return cmd;
					}

					@Override
					protected Command getReconnectTargetCommand(
							ReconnectRequest request) {
						ConnectionElement conn = (ConnectionElement) request
								.getConnectionEditPart().getModel();
						BlockElement newTarget = (BlockElement) getHost().getModel();
						ConnectionReconnectCommand cmd = new ConnectionReconnectCommand(
								conn);
						cmd.setNewTarget(newTarget);
						return cmd;
					}
				});
	}
	
	protected static class BlockFigure extends RectangleFigure {
		private Label label_;

		public BlockFigure() {
			//setCornerDimensions(new Dimension(8,8));
			setBorder(new MarginBorder(4));
			setLayoutManager(new StackLayout());
			label_=new Label();
			add(label_);
		}
		
		public void setEnabled(boolean b) {
			if (b) {
				setBackgroundColor(ColorConstants.button);
				label_.setForegroundColor(ColorConstants.black);
				setForegroundColor(ColorConstants.black);
			}else{
				setBackgroundColor(ColorConstants.lightGray);
				label_.setForegroundColor(ColorConstants.gray);
				setForegroundColor(ColorConstants.gray);
			}
		}
		
		public void setText(String s) {
			label_.setText(s);
		}
	}

	@Override
	protected IFigure createFigure() {
		return new BlockFigure();
	}

	/**
	 * Upon deactivation, detach from the model element as a property change
	 * listener.
	 */
	@Override
	public void deactivate() {
		if (isActive()) {
			super.deactivate();
			((ModelElement) getModel()).removePropertyChangeListener(this);
		}
	}

	public BlockElement getCastedModel() {
		return (BlockElement) getModel();
	}

	protected ConnectionAnchor getConnectionAnchor() {
		if (anchor == null) {
			// default
			anchor = new ChopboxAnchor(getFigure());
		}
		return anchor;
	}

	@Override
	protected List getModelSourceConnections() {
		return getCastedModel().getSourceConnections();
	}

	@Override
	protected List getModelTargetConnections() {
		return getCastedModel().getTargetConnections();
	}

	@Override
	public ConnectionAnchor getSourceConnectionAnchor(
			ConnectionEditPart connection) {
		return getConnectionAnchor();
	}

	@Override
	public ConnectionAnchor getSourceConnectionAnchor(Request request) {
		return getConnectionAnchor();
	}

	@Override
	public ConnectionAnchor getTargetConnectionAnchor(
			ConnectionEditPart connection) {
		return getConnectionAnchor();
	}

	@Override
	public ConnectionAnchor getTargetConnectionAnchor(Request request) {
		return getConnectionAnchor();
	}

	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		String prop = evt.getPropertyName();
		if (BlockElement.LOCATION_PROP.equals(prop) ||
			BlockElement.BLOCK_PROP.equals(prop) ||
			BlockElement.P_NAME.equals(prop) ||
			BlockElement.P_ENABLED.equals(prop))
		{
			refreshVisuals();
		} else if (BlockElement.SOURCE_CONNECTIONS_PROP.equals(prop)) {
			refreshSourceConnections();
		} else if (BlockElement.TARGET_CONNECTIONS_PROP.equals(prop)) {
			refreshTargetConnections();
		}
	}

	@Override
	protected void refreshVisuals() {
		//
		BlockFigure f=(BlockFigure)getFigure();
		BeanBlock bb = getCastedModel().getBeanBlock();
		f.setEnabled(bb.isEnabled());
		f.setText(bb.getName());
		//
		Dimension size = f.getPreferredSize();
		Rectangle bounds = new Rectangle(
				bb.getViewPosition().getX()-size.width/2, bb.getViewPosition().getY()-size.height/2,
				size.width, size.height);
		((GraphicalEditPart) getParent()).setLayoutConstraint(this, f, bounds);
	}
}