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

import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Rectangle;

/**
 * The base implementation for text flow figures. A flow figure is used to render a
 * document in which elements are laid out horizontally within a "line" until that line is
 * filled. Layout continues on the next line.
 * 
 * <p>WARNING: This class is not intended to be subclassed by clients. Future versions may
 * contain additional abstract methods.
 * 
 * @author hudsonr
 * @since 2.1
 */
public abstract class FlowFigure
	extends Figure
{

/**
 * integer indicating whether selection should be displayed.
 */
protected int selectionStart = -1;

/**
 * Constructs a new FlowFigure.
 */
public FlowFigure() {
	setLayoutManager(createDefaultFlowLayout());
}

/**
 * If the child is a <code>FlowFigure</code>, its FlowContext is passed to it.
 * @see org.eclipse.draw2d.IFigure#add(IFigure, Object, int)
 */
public void add(IFigure child, Object constraint, int index) {
	super.add(child, constraint, index);
	//If this layout manager is a FlowContext, then the child *must* be a FlowFigure
	if (getLayoutManager() instanceof FlowContext)
		((FlowFigure)child).setFlowContext((FlowContext)getLayoutManager());
	revalidateBidi(this);
}

/**
 * Calculates the width of text before the next line-break is encountered.
 * <p>
 * Default implementation treats each FlowFigure as a line-break.  It adds no width and
 * returns <code>true</code>.  Sub-classes should override as needed.
 * 
 * @param width the width before the next line-break (if one's found; all the width,
 * otherwise) will be added on to the first int in the given array
 * @return boolean indicating whether or not a line-break was found
 * @since 3.1
 */
public boolean addLeadingWordRequirements(int[] width) {
	return true;
}

/**
 * FlowFigures can contribute text for their block to the given {@link BidiProcessor}, 
 * which will process the contributions to determine Bidi levels and shaping requirements.
 * <p>
 * This method is invoked as part of validating Bidi.
 * <p>
 * Sub-classes that cache the BidiInfo and/or the bidi level in ContentBoxes should clear
 * the cached values when this method is invoked.
 * 
 * @param proc the BidiProcessor to which contributions should be made
 * @see BidiProcessor#add(FlowFigure, String)
 * @since 3.1
 */
protected void contributeBidi(BidiProcessor proc) {
	for (Iterator iter = getChildren().iterator(); iter.hasNext();)
		((FlowFigure)iter.next()).contributeBidi(proc);
}

/**
 * Creates the default layout manager
 * @return The default layout
 */
protected abstract FlowFigureLayout createDefaultFlowLayout();

/**
 * Called after validate has occurred. This is used to update the bounds of the FlowFigure
 * to encompass its new flow boxed created during validate.
 */
public abstract void postValidate();

/**
 * Overridden to revalidateBidi when fragments are removed.
 * @see org.eclipse.draw2d.IFigure#remove(org.eclipse.draw2d.IFigure)
 */
public void remove(IFigure figure) {
	super.remove(figure);
	revalidateBidi(this);
}

/**
 * This method should be invoked whenever a change that can potentially affect the
 * Bidi evaluation is made (eg., adding or removing children, changing text, etc.).
 * <p>
 * The default implementation delegates the revalidation task to the parent.  Only
 * {@link BlockFlow#revalidateBidi(IFigure) blocks} perform the actual revalidation. 
 * <p>
 * The given IFigure is the one that triggered the revalidation.  This can be used to
 * optimize bidi evaluation.
 * 
 * @param origin the figure that was revalidated
 * @since 3.1
 */
protected void revalidateBidi(IFigure origin) {
	if (getParent() != null)
		((FlowFigure)getParent()).revalidateBidi(origin);
}

/**
 * Sets the bidi information for this figure.  A flow figure contributes bidi text in
 * {@link #contributeBidi(BidiProcessor)}.  If the figure contributes text associated with
 * it, this method is called back to indicate the bidi properties for that text within its
 * block.
 * 
 * @param info the BidiInfo for this figure
 * @since 3.1
 */
public void setBidiInfo(BidiInfo info) { }

/**
 * FlowFigures override setBounds() to prevent translation of children. "bounds" is a
 * derived property for FlowFigures, calculated from the fragments that make up the
 * FlowFigure.
 * @see Figure#setBounds(Rectangle)
 */
public void setBounds(Rectangle r) {
	if (bounds.equals(r))
		return;
	if (!r.contains(bounds))
		erase();
	bounds.x = r.x;
	bounds.y = r.y;
	bounds.width = r.width;
	bounds.height = r.height;
	fireFigureMoved();
	if (isCoordinateSystem())
		fireCoordinateSystemChanged();
	repaint();
}

/**
 * Sets the flow context.
 * @param flowContext the flow context for this flow figure
 */
public void setFlowContext(FlowContext flowContext) {
	((FlowFigureLayout)getLayoutManager()).setFlowContext(flowContext);
}

/**
 * Sets the selection or a range of selection.  A start value of -1 is used to indicate no
 * selection.  A start value >=0 indicates show selection.  A start and end value can be
 * used to represent a range of offsets which should render selection.
 * @param start the start offset
 * @param end the end offset
 * @since 3.1
 */
public void setSelection(int start, int end) {
	if (selectionStart == start)
		return;
	selectionStart = start;
	repaint();
}

}
