/*
 * Copyright 2006 Maskat Project.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.maskat.ide.action;

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.gef.EditPart;
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.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.maskat.framework.BasicDef;
import org.maskat.framework.screendef.GridDef;
import org.maskat.framework.screendef.GridHeaderDef;
import org.maskat.framework.screendef.IComponentDef;
import org.maskat.framework.screendef.LayoutDef;
import org.maskat.framework.screendef.TabFolderDef;
import org.maskat.framework.screendef.TabItemDef;
import org.maskat.framework.screendef.TreeNodeDef;
import org.maskat.framework.screendef.TreeViewDef;
import org.maskat.ide.MaskatIDEPlugin;
import org.maskat.ide.gef.commands.AddBasicDefCommand;
import org.maskat.ide.gef.editparts.ComponentEditPart;

public class PasteComponentAction extends SelectionAction {

	// private static Request request = new CreateRequest();

	public PasteComponentAction(IWorkbenchPart part) {
		super(part);
		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));
	}

	private BasicDef targetDef = null;

	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 BasicDef)) {
			return false;
		}
		targetDef = (BasicDef) 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 BasicDef))
				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();) {
			BasicDef def = (BasicDef) it.next();
			try {
				BasicDef clone = (BasicDef) def.clone();
				source.add(clone);
			} catch (CloneNotSupportedException e) {
				// should not happen
				MessageDialog.openError(this.getWorkbenchPart().getSite().getShell(),
						"貼り付け操作失敗", "貼り付け操作に失敗しました。詳しくはエラーログを参照してください。");
				MaskatIDEPlugin.getDefault().getLog().log(
						new Status(IStatus.ERROR, MaskatIDEPlugin.PLUGIN_ID,
								IStatus.ERROR, e.getMessage(), e));
				return;
			}
		}
		for (Iterator it = source.iterator(); it.hasNext();) {
			BasicDef def = (BasicDef) it.next();
			if (def instanceof IComponentDef && targetDef instanceof IComponentDef) {
				IComponentDef compDef = (IComponentDef) def;
				compDef.setLeft(compDef.getLeft() + 10);
				compDef.setTop(compDef.getTop() + 10);
				IComponentDef targetComp = (IComponentDef) targetDef;
				if (!(targetComp instanceof LayoutDef)) {
					// TODO 20,40よろしいかどうか。
					if (targetComp instanceof TabItemDef) {
						TabFolderDef tabFolder = (TabFolderDef) ((TabItemDef) 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())
							compDef.setTop(targetComp.getHeight() - 40);
						if (targetComp.getWidth() - 20 < compDef.getLeft())
							compDef.setLeft(targetComp.getWidth() - 40);
					}
				}

				targetComp.getLayoutDef().setAppropriateNameForComponent(compDef);
				if (targetDef instanceof TreeViewDef) {
					TreeNodeDef rootNode = (TreeNodeDef) ((TreeViewDef) targetDef)
							.getChildByTypeIdx(TreeNodeDef.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();) {
			BasicDef def = (BasicDef) it.next();
			try {
				toCopy.add(def.clone());
			} catch (CloneNotSupportedException e) {
			}
		}
		Clipboard.getDefault().setContents(toCopy);
	}

	private Command genCommand(BasicDef parentDef, BasicDef childDef) {
		// if (parentDef instanceof IContainerDef && childDef instanceof
		// IComponentDef) {
		// return new AddComponentCommand((IContainerDef) parentDef,
		// (IComponentDef) childDef);
		// }
		return new AddBasicDefCommand(targetDef, childDef);
	}

	private boolean canBePasted() {
		List basicDefList = (List) Clipboard.getDefault().getContents();

		List sourceEPList = new ArrayList();
		for (Iterator it = basicDefList.iterator(); it.hasNext();) {
			BasicDef def = (BasicDef) it.next();
			// TODO
			if (def instanceof GridHeaderDef) {
				if (targetDef instanceof GridDef)
					return true;
				else
					return false;
			}
			// TODO
			ComponentEditPart ep = new ComponentEditPart();
			ep.setModel(def);
			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();
	}
}
