/*******************************************************************************
 * Copyright (c) 2005 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.bpel.ui.util;

import java.util.Iterator;

import org.eclipse.bpel.ui.editparts.util.GraphAnimation;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;


/**
 * Our version of XYLayout that doesn't allow negative x,y children to be clipped.
 * It also has size attribute that overrides what the preferred size should be.
 */
public class NonclippingXYLayout extends XYLayout {

	private Point displacement = new Point(0, 0);
	private Dimension size;
	
	/**
	 * @return the offset of the children in the container
	 */
	public Point getDisplacement() {
		return displacement;
	}

	@Override
	public void layout(IFigure parent) {
		GraphAnimation.recordInitialState(parent);
		if (GraphAnimation.playbackState(parent))
			return;
		
		Point offset = getOrigin(parent);
		IFigure f;

		// calculate a new displacement
		refreshDisplacement(parent);

		Iterator children;
		children = parent.getChildren().iterator();
		while (children.hasNext()) {
			f = (IFigure) children.next();
			Rectangle bounds = (Rectangle) getConstraint(f);
			if (bounds == null)
				continue;
			bounds = bounds.getTranslated(offset);
			if (bounds.width == -1 || bounds.height == -1) {
				Dimension preferredSize = f.getPreferredSize();
				bounds = bounds.getCopy();
				if (bounds.width == -1)
					bounds.width = preferredSize.width;
				if (bounds.height == -1)
					bounds.height = preferredSize.height;
			}
			bounds = bounds.getTranslated(displacement);
			f.setBounds(bounds);
		}
	}

	public void refreshDisplacement(IFigure parent) {
		IFigure f;

		// calculate a new displacement
		Iterator children = parent.getChildren().iterator();
		int minX = 0, minY = 0;
		while (children.hasNext()) {
			f = (IFigure) children.next();
			Rectangle bounds = (Rectangle) getConstraint(f);
			if (bounds == null)
				continue;
			if (bounds.x < 0)
				minX = Math.min(minX, bounds.x);
			if (bounds.y < 0)
				minY = Math.min(minY, bounds.y);
		}
		displacement = new Point(-minX, -minY);
	}

	@Override
	public void setConstraint(IFigure figure, Object newConstraint) {
		Rectangle bounds = null;
		if (newConstraint != null) {
			bounds = ((Rectangle) newConstraint).getCopy();
			bounds.translate(-displacement.x, -displacement.y);
		}
		super.setConstraint(figure, bounds);
//		if (bounds != null)
//			constraints.put(figure, bounds);
	}
	@Override
	protected Dimension calculatePreferredSize(IFigure f, int wHint, int hHint) {
		Dimension result = super.calculatePreferredSize(f, wHint, hHint);
		if (size != null) {
			Dimension largest = new Dimension(size);
			largest.width = Math.max(result.width, size.width);
			largest.height = Math.max(result.height, size.height);
			return largest;
		}
		
		return result;
	}
	public void setSize(Dimension size) {
		this.size = size;
	}
}