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

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

import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.gef.requests.GroupRequest;

import org.maskat.core.MaskatElement;
import org.maskat.core.layout.ComponentPart;
import org.maskat.core.layout.Container;
import org.maskat.core.layout.Component;
import org.maskat.core.layout.StructuredComponent;
import org.maskat.ui.editors.layout.commands.AddComponentCommand;
import org.maskat.ui.editors.layout.commands.OrphanChildrenCommand;
import org.maskat.ui.editors.layout.editparts.ComponentEditPart;

public class ComponentXYLayoutEditPolicy extends XYLayoutEditPolicy {

	private int feedBackStyle = FeedBackComponentEditPolicy.NONRESIZE;
	
	public ComponentXYLayoutEditPolicy() {}
	
	public ComponentXYLayoutEditPolicy(int style) {
		setFeedBackStyle(style);
	}
	
	protected Command createAddCommand(EditPart child, Object constraint) {
		Object childModel = child.getModel();

//		EditPart parent = getHost();
		Object parent = getHost().getModel();

		if (!canAddChild(parent, childModel) || !(childModel instanceof Component)) {
			return null;
		}
		
//		if (parent instanceof ComponentEditPart) {
//			if (!(childModel instanceof LayoutElement) ||
//				!((ComponentEditPart) parent).canAddChildren((LayoutElement) childModel)) {
//				return null;
//			}
//		}
		AddComponentCommand command = null;
		if (isCheckConstraint((Rectangle) constraint)) {
//			Object target = getHost().getModel();
			command = new AddComponentCommand((Component) parent, (Component) childModel);
			command.setConstraint((Rectangle) constraint);
			// AddCommandはOrphanChildrenCommandとペアで作用
		}
		return command;
	}

	protected Command createChangeConstraintCommand(EditPart child, Object constraint) {
		Command cmd = null;
		if (child instanceof ComponentEditPart) {
			if (isCheckConstraint((Rectangle) constraint)) {
				ComponentEditPart part = (ComponentEditPart) child;
				cmd = part.createConstrainCommand(child.getModel(), (Rectangle) constraint);
			}
		}
		return cmd;
	}

	private boolean isCheckConstraint(Rectangle rec) {
		return !(rec.x < 0 || rec.y < 0);
	}
	
	protected Command getCreateCommand(CreateRequest request) {
		Object model = getHost().getModel();
		Command cmd = null;
		if (model instanceof Component) {//MaskatElement) {
			MaskatElement host = (MaskatElement) model;
			Object node = request.getNewObject();

			if (!canAddChild(model, node)) {
				return null;
			}
			//EditPart editPart = getHost();
			//if (editPart instanceof ComponentEditPart) {
			//	if (!((ComponentEditPart) editPart).
			//			canAddChildren((LayoutElement) node)) {
			//		return null;
			//	}
			//}
			ComponentEditPart child = (ComponentEditPart)
				getHost().getViewer().getEditPartFactory().createEditPart(null, node);
			cmd = child.getCreateCommand(host, node);
			
			if (cmd != null && cmd instanceof AddComponentCommand) {// && host instanceof Container) {
				((AddComponentCommand) cmd).setConstraint((Rectangle) getConstraintFor(request));
			}
		}
		return cmd;
	}

	private boolean canAddChild(Object parentModel, Object childNode) {
		if (parentModel instanceof Container &&
				!(childNode instanceof ComponentPart) &&
				  childNode instanceof Component) {
			return true;
		}
		if (parentModel instanceof StructuredComponent) {
			if (childNode instanceof ComponentPart) {
				return ((StructuredComponent) parentModel).
					canAddPart((ComponentPart) childNode);
			}
		}
		return false;
	}
	
	protected Command getOrphanChildrenCommand(Request request) {

		Object obj = getHost().getModel();
		if (obj instanceof Container) {
			List editParts = ((GroupRequest) request).getEditParts();
			List models = new ArrayList();
			for (int i = 0; i < editParts.size(); i++) {
				models.add(((EditPart) editParts.get(i)).getModel());
			}
			OrphanChildrenCommand command = new OrphanChildrenCommand(models);
			return command;
		}
		return null;
	}

	protected Command getDeleteDependantCommand(Request request) {
		return null;
	}

	protected Command getCloneCommand(ChangeBoundsRequest request) {
		return super.getCloneCommand(request);
	}
	
	public void setFeedBackStyle(int style) {
		feedBackStyle = style;
	}

	public int getFeedBackStyle() {
		return feedBackStyle;
	}	
	
	protected EditPolicy createChildEditPolicy(EditPart child) {
		int style = 0;
		EditPolicy policy = child.getEditPolicy(EditPolicy.LAYOUT_ROLE);
		if (policy instanceof ComponentXYLayoutEditPolicy) {
			style = ((ComponentXYLayoutEditPolicy) policy).getFeedBackStyle();
		}
		return new FeedBackComponentEditPolicy(style);
	}
}
