/*
 * Copyright (c) 2006-2008 Maskat Project.
 *
 * 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:
 *     Maskat Project - initial API and implementation
 */
package org.maskat.ui.editors.layout.actions;

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

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.internal.GEFMessages;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gef.ui.actions.Clipboard;
import org.eclipse.gef.ui.actions.SelectionAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;

import org.maskat.core.MaskatElement;
import org.maskat.core.layout.Component;
import org.maskat.core.layout.Layout;
import org.maskat.core.layout.LayoutElement;
import org.maskat.core.layout.TabFolder;
import org.maskat.core.layout.TabItem;
import org.maskat.core.layout.TreeNode;
import org.maskat.core.layout.TreeView;
import org.maskat.ui.MaskatUIPlugin;
import org.maskat.ui.Messages;
import org.maskat.ui.editors.layout.LayoutGraphicalEditor;
import org.maskat.ui.editors.layout.commands.AddBasicDefCommand;

public class PasteComponentAction extends SelectionAction {

	private LayoutElement targetDef = null;
	private LayoutGraphicalEditor editor = null;

	//public PasteComponentAction(IWorkbenchPart part) {
	public PasteComponentAction(LayoutGraphicalEditor editor) {
		super(editor);
		this.editor = editor;
		
		setId(ActionFactory.PASTE.getId());
		setText(GEFMessages.PasteAction_Label);
		setToolTipText(GEFMessages.PasteAction_Tooltip);
		ISharedImages sharedImages = PlatformUI.getWorkbench()
				.getSharedImages();
		setImageDescriptor(sharedImages.getImageDescriptor(
				ISharedImages.IMG_TOOL_PASTE));
		setDisabledImageDescriptor(sharedImages.getImageDescriptor(
				ISharedImages.IMG_TOOL_PASTE_DISABLED));
		
	}

	protected boolean calculateEnabled() {
		// check the content in the clipboard can be pasted.
		if (!checkClipboard()) {
			return false;
		}
		List objects = this.getSelectedObjects();
		if (objects.isEmpty()) {
			return false;
		}
		if (objects.size() > 1) {
			return false;
		}
		Object selectedObj = objects.get(0);
		if (!(selectedObj instanceof EditPart)) {
			return false;
		}
		Object model = ((EditPart) selectedObj).getModel();
		if (!(model instanceof LayoutElement)) {
			return false;
		}
		targetDef = (LayoutElement) model;
		return canBePasted();
	}

	private boolean checkClipboard() {
		Object clipboardContent = Clipboard.getDefault().getContents();
		if (!(clipboardContent instanceof List)) {
			return false;
		}
		for (int i = 0; i < ((List) clipboardContent).size(); i++) {
			if (!(((List) clipboardContent).get(i) instanceof MaskatElement)) {
				return false;
			}
		}
		return true;
	}

	public void run() {
		if (!checkClipboard()) {
			return;
		}
		Command command = null;

		List basicDefList = (List) Clipboard.getDefault().getContents();
		List source = new ArrayList();
		for (Iterator it = basicDefList.iterator(); it.hasNext();) {
			LayoutElement def = (LayoutElement) it.next();
			try {
				LayoutElement clone = (LayoutElement) def.clone();
				source.add(clone);
			} catch (CloneNotSupportedException e) {
				MessageDialog.openError(this.getWorkbenchPart().getSite().getShell(),
						Messages.getString("layout.cmd.msg.error.title"), //$NON-NLS-1$
						Messages.getString("layout.cmd.paste.msg.error")); //$NON-NLS-1$
				MaskatUIPlugin.log(new Status(IStatus.ERROR, MaskatUIPlugin.PLUGIN_ID,
						IStatus.ERROR, e.getMessage(), e));
				return;
			}
		}
		for (Iterator it = source.iterator(); it.hasNext();) {
			LayoutElement def = (LayoutElement) it.next();
			if (def instanceof Component && targetDef instanceof Component) {
				Component compDef = (Component) def;
				compDef.setLeft(compDef.getLeft() + 10);
				compDef.setTop(compDef.getTop() + 10);
				Component targetComp = (Component) targetDef;
				if (!(targetComp instanceof Layout)) {
					// TODO 20,40よろしいかどうか。
					if (targetComp instanceof TabItem) {
						//TabFolder tabFolder = (TabFolder) ((TabItem) targetComp)
						//		.getContainer();
						TabFolder tabFolder = (TabFolder)((TabItem) targetComp).getParent();
						if (tabFolder.getHeight() - 20 < compDef.getTop()) {
							compDef.setTop(tabFolder.getHeight() - 40);
						}
						if (tabFolder.getWidth() - 20 < compDef.getLeft()) {
							compDef.setLeft(tabFolder.getWidth() - 40);
						}
					} else {
						if (targetComp.getHeight() - 20 < compDef.getTop()) {
							int top = targetComp.getHeight() - 40;
							compDef.setTop(top < 0 ? 0 : top);
						}
						if (targetComp.getWidth() - 20 < compDef.getLeft()) {
							int left = targetComp.getWidth() - 40;
							compDef.setLeft(left < 0 ? 0 : left);
						}
					}
				}
				if (targetDef instanceof TreeView) {
					TreeNode rootNode = (TreeNode) ((TreeView) targetDef)
							.getChildByTypeIdx(TreeNode.class, 0);
					if (rootNode != null) {
						targetDef = rootNode;
					}
				}
			}
			if (command == null) {
				command = genCommand(targetDef, def);
			} else {
				command = command.chain(genCommand(targetDef, def));
			}
		}
		execute(command);

		// もう一度コピー
		List toCopy = new ArrayList();
		for (Iterator it = source.iterator(); it.hasNext();) {
			LayoutElement def = (LayoutElement) it.next();
			try {
				toCopy.add(def.clone());
			} catch (CloneNotSupportedException e) {
			}
		}
		Clipboard.getDefault().setContents(toCopy);
	}

	private Command genCommand(LayoutElement parentDef, LayoutElement childDef) {
		return new AddBasicDefCommand(targetDef, childDef);
	}

	private boolean canBePasted() {
		List basicDefList = (List) Clipboard.getDefault().getContents();
		GraphicalViewer viewer = (GraphicalViewer) this.editor.getAdapter(
					GraphicalViewer.class);
				
		List sourceEPList = new ArrayList();
		for (Iterator it = basicDefList.iterator(); it.hasNext();) {
			LayoutElement def = (LayoutElement) it.next();
			GraphicalEditPart ep = (GraphicalEditPart)
				viewer.getEditPartFactory().createEditPart(null, def);
			
			ep.setModel(def);
			FigureCanvas canvas = (FigureCanvas) viewer.getControl();
			Rectangle rec = canvas.getViewport().getBounds();
			ep.getFigure().setBounds(new Rectangle(rec.width, rec.height, 0, 0));
			sourceEPList.add(ep);
		}
		List objects = this.getSelectedObjects();
		EditPart targetEP = (EditPart) objects.get(0);
		ChangeBoundsRequest request = new ChangeBoundsRequest(RequestConstants.REQ_ADD);
		
		request.setEditParts(sourceEPList);
		Command command = targetEP.getCommand(request);
		return command == null ? false : command.canExecute();
	}
}
