/**
 * File:    AlignmentHandler.java
 * Created: 16.10.2007
 *
 *
/*******************************************************************************
 * Copyright (c) 2005-2011
 * University of Augsburg, Germany <www.ds-lab.org>
 *
 * 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:
 *    Christian Saad, Programming distributed Systems Lab, University of Augsburg 
 *    	- initial API and implementation
 *******************************************************************************/

package org.eclipse.jwt.we.editors.actions.handlers;

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

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.requests.AlignmentRequest;
import org.eclipse.gef.tools.ToolUtilities;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jwt.we.editors.actions.WEActionHandler;
import org.eclipse.jwt.we.editors.pages.activityEditor.internal.IActivityEditor;
import org.eclipse.jwt.we.misc.util.GeneralHelper;
import org.eclipse.ui.IWorkbenchPart;


/**
 * A handler which aligns the selected edit parts.
 * 
 * This class is based on the AlignmentAction of the Eclipse GEF project.
 * 
 * @version $Id
 * @author Christian Saad (csaad@gmx.net), Programming distributed Systems Lab, University
 *         of Augsburg, Germany, www.ds-lab.org
 */
public final class AlignmentHandler
		extends WEActionHandler
{

	/**
	 * Constructor.
	 */
	public AlignmentHandler()
	{
		super(true);
	}


	/**
	 * Returns the list of editparts which will participate in alignment.
	 * 
	 * @param request
	 *            the alignment request
	 * @return the list of parts which will be aligned
	 */
	protected List getSelectedEditParts(Request request)
	{
		List editparts = new ArrayList(GeneralHelper.getActiveInstance()
				.getCurrentActivitySheet().getGraphicalViewer().getSelectedEditParts());

		if (editparts.isEmpty() || !(editparts.get(0) instanceof GraphicalEditPart))
		{
			return Collections.EMPTY_LIST;
		}

		Object primary = editparts.get(editparts.size() - 1);

		editparts = ToolUtilities.getSelectionWithoutDependants(editparts);
		ToolUtilities.filterEditPartsUnderstanding(editparts, request);

		if (editparts.size() < 2 || !editparts.contains(primary))
		{
			return Collections.EMPTY_LIST;
		}

		EditPart parent = ((EditPart) editparts.get(0)).getParent();

		for (int i = 1; i < editparts.size(); i++)
		{
			EditPart part = (EditPart) editparts.get(i);

			if (part.getParent() != parent)
			{
				return Collections.EMPTY_LIST;
			}
		}

		return editparts;
	}


	/**
	 * Refresh enabled state if selection has changed. Only enabled when an activity
	 * editor is active.
	 */
	@Override
	public void selectionChanged(IWorkbenchPart part, ISelection selection)
	{
		// set to false if no JWT instance is active
		if (GeneralHelper.getActiveInstance() == null)
		{
			setEnabled(false);
			return;
		}

		// set enabled to true only if an IActivityEditor is enabled and
		// if command can be executed
		if (GeneralHelper.getActiveInstance().getActiveEditor() instanceof IActivityEditor)
		{
			Command cmd = createAlignmentCommand(PositionConstants.TOP);
			if (cmd != null && cmd.canExecute())
			{
				setEnabled(true);
			}
			else
			{
				setEnabled(false);
			}
			return;
		}
		else
		{
			setEnabled(false);
		}
	}


	/**
	 * Returns the type of the command as a PositionConstant.
	 * 
	 * @param event
	 * @return Command type.
	 */
	private int getCommandType(ExecutionEvent event)
	{
		// get the name of the command
		String commandId = ""; //$NON-NLS-1$

		try
		{
			commandId = event.getCommand().getId();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

		// check which command was called and return corresponding type
		if (commandId.equals("org.eclipse.jwt.we.alignTopCommand")) //$NON-NLS-1$
		{
			return PositionConstants.TOP;
		}
		if (commandId.equals("org.eclipse.jwt.we.alignBottomCommand")) //$NON-NLS-1$
		{
			return PositionConstants.BOTTOM;
		}
		if (commandId.equals("org.eclipse.jwt.we.alignRightCommand")) //$NON-NLS-1$
		{
			return PositionConstants.RIGHT;
		}
		if (commandId.equals("org.eclipse.jwt.we.alignLeftCommand")) //$NON-NLS-1$
		{
			return PositionConstants.LEFT;
		}
		if (commandId.equals("org.eclipse.jwt.we.alignCenterCommand")) //$NON-NLS-1$
		{
			return PositionConstants.CENTER;
		}
		if (commandId.equals("org.eclipse.jwt.we.alignMiddleCommand")) //$NON-NLS-1$
		{
			return PositionConstants.MIDDLE;
		}

		return 0;
	}


	/**
	 * Returns the alignment rectangle to which all selected parts should be aligned.
	 * 
	 * @param request
	 *            the alignment Request
	 * @return the alignment rectangle
	 */
	protected Rectangle calculateAlignmentRectangle(Request request)
	{
		// the selected edit parts
		List editparts = getSelectedEditParts(request);
		if (editparts == null || editparts.isEmpty())
		{
			return null;
		}

		// calculate the rectangle
		GraphicalEditPart part = (GraphicalEditPart) editparts.get(editparts.size() - 1);
		Rectangle rect = new PrecisionRectangle(part.getFigure().getBounds());
		part.getFigure().translateToAbsolute(rect);

		return rect;
	}


	/**
	 * Returns an alignment command corresponding to the given alignment type.
	 * 
	 * @param alignmentType
	 * @return The alignment command.
	 */
	private Command createAlignmentCommand(int alignmentType)
	{
		// create alignment request
		AlignmentRequest request = new AlignmentRequest(RequestConstants.REQ_ALIGN);
		request.setAlignmentRectangle(calculateAlignmentRectangle(request));
		request.setAlignment(alignmentType);

		// get selected edit parts
		List editparts = getSelectedEditParts(request);
		if (editparts.size() < 2)
		{
			return null;
		}

		// create compound command
		CompoundCommand command = new CompoundCommand();

		for (int i = 0; i < editparts.size(); i++)
		{
			EditPart editpart = (EditPart) editparts.get(i);
			command.add(editpart.getCommand(request));
		}

		return command;
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
	 */
	public Object execute(ExecutionEvent event) throws ExecutionException
	{
		// create command
		Command command = createAlignmentCommand(getCommandType(event));

		// execute on command stack
		if (command != null && command.canExecute())
		{
			GeneralHelper.getActiveInstance().getEditDomain().getCommandStack().execute(
					command);
		}

		return null;
	}

}