/*******************************************************************************
 * Copyright (c) 2000, 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.draw2d;

import org.eclipse.draw2d.geometry.Dimension;

/**
 * The foundation for layout managers which are sensitive to width and/or height hints.
 * This class will cache preferred and minimum sizes for a given set of hints. If the
 * hints change in a meaningful way, the cached size is thrown out and redetermined.
 * <P>
 * Subclasses may be sensitive to one or both hints. By default, this class assumes both
 * hints are important. Subclasses may override this behavior in {@link
 * #isSensitiveHorizontally(IFigure)} and {@link #isSensitiveVertically(IFigure)}. At
 * least one of these method should return <code>true</code>.
 * 
 * @author hudsonr
 * @since 2.0
 */
public abstract class AbstractHintLayout
	extends AbstractLayout
{

private Dimension minimumSize = null;
private Dimension cachedPreferredHint = new Dimension(-1, -1);
private Dimension cachedMinimumHint = new Dimension(-1, -1);

/**
 * Calculates the minimum size using the given width and height hints. This method is
 * called from {@link #getMinimumSize(IFigure, int, int)} whenever the cached minimum size
 * has been flushed.
 * <P>
 * By default, this method just calls {@link #getPreferredSize(IFigure, int, int)},
 * meaning minimum and preferres sizes will be the same unless this method is overridden.
 * 
 * @param container the Figure on which this layout is installed
 * @param wHint the width hint
 * @param hHint the height hint
 * 
 * @return the layout's minimum size
 */
protected Dimension calculateMinimumSize(IFigure container, int wHint, int hHint) {
	return getPreferredSize(container, wHint, hHint);
}

/**
 * @see org.eclipse.draw2d.LayoutManager#getMinimumSize(IFigure, int, int)
 */
public Dimension getMinimumSize(IFigure container, int w, int h) {
	boolean flush = cachedMinimumHint.width != w
		&& isSensitiveHorizontally(container);
	flush |= cachedMinimumHint.height != h
		&& isSensitiveVertically(container);
	if (flush) {
		minimumSize = null;
		cachedMinimumHint.width = w;
		cachedMinimumHint.height = h;
	}
	if (minimumSize == null)
		minimumSize = calculateMinimumSize(container, w, h);
	return minimumSize;
}

/**
 * @see org.eclipse.draw2d.LayoutManager#getPreferredSize(IFigure, int, int)
 */
public final Dimension getPreferredSize(IFigure container, int w, int h) {
	boolean flush = cachedPreferredHint.width != w
		&& isSensitiveHorizontally(container);
	flush |= cachedPreferredHint.height != h
		&& isSensitiveVertically(container);
	if (flush) {
		preferredSize = null;
		cachedPreferredHint.width = w;
		cachedPreferredHint.height = h;
	}
	return super.getPreferredSize(container, w, h);
}

/**
 * Extends the superclass implementation to flush the cached minimum size.
 * @see org.eclipse.draw2d.LayoutManager#invalidate()
 */
public void invalidate() {
	minimumSize = null;
	super.invalidate();
}

/**
 * Returns whether this layout manager is sensitive to changes in the horizontal hint. By
 * default, this method returns <code>true</code>.
 * @param container the layout's container
 * @return <code>true</code> if this layout is sensite to horizontal hint changes
 */
protected boolean isSensitiveHorizontally(IFigure container) {
	return true;
}

/**
 * Returns whether this layout manager is sensitive to changes in the vertical hint. By
 * default, this method returns <code>true</code>.
 * @param container the layout's container
 * @return <code>true</code> if this layout is sensite to vertical hint changes
 */
protected boolean isSensitiveVertically(IFigure container) {
	return true;
}

}
