/*
 * 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.gef.commands;

import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.commands.Command;
import org.maskat.framework.screendef.IComponentDef;
import org.maskat.framework.screendef.IContainerDef;
import org.maskat.framework.screendef.LayoutDef;
import org.maskat.framework.screendef.MaskatDef;
import org.maskat.framework.screendef.PopupDef;
import org.maskat.framework.screendef.customize.IPluginComponentDef;

public class AddComponentCommand extends Command {
	private IContainerDef parent;

	private IComponentDef node;

	private Rectangle constraint;

	private boolean shouldUndoNamespace;

	public AddComponentCommand(IContainerDef parent, IComponentDef node) {
		this.parent = parent;
		this.node = node;
	}

	public void setConstraint(Rectangle rectangle) {
		this.constraint = rectangle;
	}

	public void execute() {
		int targetY = constraint.y;
		if (parent instanceof PopupDef) {
			targetY -= 20;
			targetY = Math.max(0, targetY);
		}
		if (constraint.width == -1 && constraint.height == -1) {
			// XYLayoutEditPolicy#DEFAULT_SIZEとgetConstraintForを参照してください
			// 位置だけ指定されているとき、デフォルトサイズで画面上に生成
			// デフォルトサイズはComponentCreateFactoryを参照
			node.setLeft(constraint.x);
			node.setTop(targetY);
		} else {
			node
					.setConstraint(constraint.x, targetY, constraint.width,
							constraint.height);
		}

		LayoutDef layoutDef = parent.getLayoutDef();
		// @TODO It's not appropriate to downcast the IContainerDef to
		// LayoutDef.
		// solution?

		MaskatDef md = layoutDef.getMaskatDef();
		if (node instanceof IPluginComponentDef) {
			// Must consider the extended component's namespace
			IPluginComponentDef pluginCompDef = (IPluginComponentDef) node;
			String prefix = pluginCompDef.getProxy().getPrefix();
			String namespace = pluginCompDef.getProxy().getNamespace();
			if (namespace == null || "".equals(namespace)) {
				shouldUndoNamespace = false;
			} else {
				if (md.getNamespaces().containsKey(namespace)) {
					// if the md already has the namespace, change the prefix to
					// the one that already existed
					shouldUndoNamespace = false;
					pluginCompDef.getProxy().setPrefix(
							(String) md.getNamespaces().get(namespace));
				} else {
					// add the namespace to the maskatdef
					shouldUndoNamespace = true;
					md.getNamespaces().put(namespace, prefix);
				}
			}
		}

		parent.addChild(node);
	}

	public void undo() {
		parent.removeChild(node);
		if (shouldUndoNamespace) {
			if (node instanceof IPluginComponentDef) {
				LayoutDef layoutDef = (LayoutDef) parent.getLayoutDef();
				// @TODO It's not appropriate to downcast the LayoutDef to
				// LayoutDef. solution?

				MaskatDef md = layoutDef.getMaskatDef();
				IPluginComponentDef pluginCompDef = (IPluginComponentDef) node;
				md.getNamespaces().remove(pluginCompDef.getProxy().getNamespace());
			}
		}
	}

	public boolean canUndo() {
		return true;
	}
}
