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

import java.util.List;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;

/**
 * The root of a Flow hierarchy. A flow page can be treated as a normal figure, but
 * contains FlowFigures.
 * <P>
 * A FlowPage will not have a defined width unless it is inside a figure whose layout
 * provides width hints when calling 
 * {@link org.eclipse.draw2d.IFigure#getPreferredSize(int, int)}.
 * 
 * <P>WARNING: This class is not intended to be subclassed by clients.
 */
public class FlowPage
	extends BlockFlow
{

private Dimension pageSize = new Dimension();
private int recommendedWidth;
private int pageSizeCacheKeys[] = new int[3];
private Dimension pageSizeCacheValues[] = new Dimension[3];

/**
 * @see org.eclipse.draw2d.Figure#addNotify()
 */
public void addNotify() {
	super.addNotify();
	setValid(false);
}

/**
 * @see org.eclipse.draw2d.text.BlockFlow#createDefaultFlowLayout()
 */
protected FlowFigureLayout createDefaultFlowLayout() {
	return new PageFlowLayout(this);
}

/**
 * @see org.eclipse.draw2d.Figure#getMinimumSize(int, int)
 */
public Dimension getMinimumSize(int w, int h) {
	return getPreferredSize(w, h);
}

/**
 * @see org.eclipse.draw2d.Figure#invalidate()
 */
public void invalidate() {
	pageSizeCacheValues = new Dimension[3];
	super.invalidate();
}

/**
 * @see org.eclipse.draw2d.Figure#getPreferredSize(int, int)
 */
public Dimension getPreferredSize(int width, int h) {
	for (int i = 0; i < 3; i++) {
		if (pageSizeCacheKeys[i] == width && pageSizeCacheValues[i] != null)
			return pageSizeCacheValues[i];
	}

	pageSizeCacheKeys[2] = pageSizeCacheKeys[1];
	pageSizeCacheKeys[1] = pageSizeCacheKeys[0];
	pageSizeCacheKeys[0] = width;
	
	pageSizeCacheValues[2] = pageSizeCacheValues[1];
	pageSizeCacheValues[1] = pageSizeCacheValues[0];	

	//Flowpage must temporarily layout to determine its preferred size
	int oldWidth = getPageWidth();
	setPageWidth(width);
	validate();
	pageSizeCacheValues[0] = pageSize.getCopy();
	
	if (width != oldWidth) {
		setPageWidth(oldWidth);
		getUpdateManager().addInvalidFigure(this);
	}
	return pageSizeCacheValues[0];
}

int getPageWidth() {
	return recommendedWidth;
}

/**
 * @see BlockFlow#postValidate()
 */
public void postValidate() {
	Rectangle r = getBlockBox().toRectangle();
	pageSize.width = r.width;
	pageSize.height = r.height;
	List v = getChildren();
	for (int i = 0; i < v.size(); i++)
		((FlowFigure)v.get(i)).postValidate();
}

/**
 * Overridden to set valid.
 * @see org.eclipse.draw2d.IFigure#removeNotify()
 */
public void removeNotify() {
	super.removeNotify();
	setValid(true);
}

/**
 * @see FlowFigure#setBounds(Rectangle)
 */
public void setBounds(Rectangle r) {
	if (getBounds().equals(r))
		return;
	boolean invalidate = getBounds().width != r.width || getBounds().height != r.height;
	super.setBounds(r);
	int newWidth = r.width;
	if (invalidate || getPageWidth() != newWidth) {
		setPageWidth(newWidth);
		getUpdateManager().addInvalidFigure(this);
	}
}

private void setPageWidth(int width) {
	if (recommendedWidth == width)
		return;
	recommendedWidth = width;
	super.invalidate();
}

/**
 * @see org.eclipse.draw2d.Figure#validate()
 */
public void validate() {
	if (isValid())
		return;
	super.validate();
	postValidate();
}

}
