/*
 * Copyright (C) Jerry Huxtable 1998-2001. All rights reserved.
 */
package com.jhlabs.awt;

import java.awt.*;

public class ParagraphLayout extends ConstraintLayout {

	public final static int TYPE_MASK = 0x03;
	public final static int STRETCH_H_MASK = 0x04;
	public final static int STRETCH_V_MASK = 0x08;

	public final static int NEW_PARAGRAPH_VALUE = 1;
	public final static int NEW_PARAGRAPH_TOP_VALUE = 2;
	public final static int NEW_LINE_VALUE = 3;

	public final static Integer NEW_PARAGRAPH = new Integer(0x01);
	public final static Integer NEW_PARAGRAPH_TOP = new Integer(0x02);
	public final static Integer NEW_LINE = new Integer(0x03);
	public final static Integer STRETCH_H = new Integer(0x04);
	public final static Integer STRETCH_V = new Integer(0x08);
	public final static Integer STRETCH_HV = new Integer(0x0c);
	public final static Integer NEW_LINE_STRETCH_H = new Integer(0x07);
	public final static Integer NEW_LINE_STRETCH_V = new Integer(0x0b);
	public final static Integer NEW_LINE_STRETCH_HV = new Integer(0x0f);

	protected int hGapMajor, vGapMajor;
	protected int hGapMinor, vGapMinor;
	protected int rows;
	protected int colWidth1;
	protected int colWidth2;

	public ParagraphLayout() {
		this(10, 10, 12, 11, 4, 4);
	}
	
	public ParagraphLayout(int hMargin, int vMargin, int hGapMajor, int vGapMajor, int hGapMinor, int vGapMinor) {
		this.hMargin = hMargin;
		this.vMargin = vMargin;
		this.hGapMajor = hGapMajor;
		this.vGapMajor = vGapMajor;
		this.hGapMinor = hGapMinor;
		this.vGapMinor = vGapMinor;
	}
	
	public void measureLayout(Container target, Dimension dimension, int type)  {
		int count = target.getComponentCount();
		if (count > 0) {
			Insets insets = target.getInsets();
			Dimension size = target.getSize();
			int x = 0;
			int y = 0;
			int rowHeight = 0;
			int colWidth = 0;
			int numRows = 0;
			boolean lastWasParagraph = false;

			Dimension[] sizes = new Dimension[count];

			// First pass: work out the column widths and row heights
			for (int i = 0; i < count; i++) {
				Component c = target.getComponent(i);
				if (includeComponent(c)) {
					Dimension d = getComponentSize(c, type);
					int w = d.width;
					int h = d.height;
					sizes[i] = d;
					Integer n = (Integer)getConstraint(c);

					if (i == 0 || n == NEW_PARAGRAPH || n == NEW_PARAGRAPH_TOP) {
						if (i != 0)
							y += rowHeight+vGapMajor;
						colWidth1 = Math.max(colWidth1, w);
						colWidth = 0;
						rowHeight = 0;
						lastWasParagraph = true;
					} else if (n == NEW_LINE || lastWasParagraph) {
						x = 0;
						if (!lastWasParagraph && i != 0)
							y += rowHeight+vGapMinor;
						colWidth = w;
						colWidth2 = Math.max(colWidth2, colWidth);
						if (!lastWasParagraph)
							rowHeight = 0;
						lastWasParagraph = false;
					} else {
						colWidth += w+hGapMinor;
						colWidth2 = Math.max(colWidth2, colWidth);
						lastWasParagraph = false;
					}
					rowHeight = Math.max(h, rowHeight);
				}
			}

			// Second pass: actually lay out the components
			if (dimension != null) {
				dimension.width = colWidth1 + hGapMajor + colWidth2;
				dimension.height = y + rowHeight;
			} else {
				int spareHeight = size.height-(y+rowHeight)-insets.top-insets.bottom-2*vMargin;
				x = 0;
				y = 0;
				lastWasParagraph = false;
				int start = 0;
				int rowWidth = 0;
				Integer paragraphType = NEW_PARAGRAPH;
				boolean stretchV = false;
				
				boolean firstLine = true;
				for (int i = 0; i < count; i++) {
					Component c = target.getComponent(i);
					if (includeComponent(c)) {
						Dimension d = sizes[i];
						int w = d.width;
						int h = d.height;
						Integer n = (Integer)getConstraint(c);
						int nv = n != null ? n.intValue() : 0;

						if (i == 0 || n == NEW_PARAGRAPH || n == NEW_PARAGRAPH_TOP) {
							if (i != 0)
								layoutRow(target, sizes, start, i-1, y, rowWidth, rowHeight, firstLine, type, paragraphType);
							stretchV = false;
							paragraphType = n;
							start = i;
							firstLine = true;
							if (i != 0)
								y += rowHeight+vGapMajor;
							rowHeight = 0;
							rowWidth = colWidth1+hGapMajor-hGapMinor;
							lastWasParagraph = true;
						} else if (n == NEW_LINE || lastWasParagraph) {
							if (!lastWasParagraph) {
								layoutRow(target, sizes, start, count-1, y, rowWidth, rowHeight, firstLine, type, paragraphType);
								stretchV = false;
								start = i;
								firstLine = false;
								y += rowHeight+vGapMinor;
								rowHeight = 0;
							}
							rowWidth += sizes[i].width+hGapMinor;
							lastWasParagraph = false;
						} else {
							rowWidth += sizes[i].width+hGapMinor;
							lastWasParagraph = false;
						}
						if ((nv & STRETCH_V_MASK) != 0 && !stretchV) {
							stretchV = true;
							h += spareHeight;
						}
						rowHeight = Math.max(h, rowHeight);
					}
				}
				layoutRow(target, sizes, start, count-1, y, rowWidth, rowHeight, firstLine, type, paragraphType);
			}
		}

	}

	protected void layoutRow(Container target, Dimension[] sizes, int start, int end, int y, int rowWidth, int rowHeight, boolean paragraph, int type, Integer paragraphType) {
		int x = 0;
		Insets insets = target.getInsets();
		Dimension size = target.getSize();
		int spareWidth = size.width-rowWidth-insets.left-insets.right-2*hMargin;

		for (int i = start; i <= end; i++) {
			Component c = target.getComponent(i);
			if (includeComponent(c)) {
				Integer n = (Integer)getConstraint(c);
				int nv = n != null ? n.intValue() : 0;
				Dimension d = sizes[i];
				int w = d.width;
				int h = d.height;

				if ((nv & STRETCH_H_MASK) != 0) {
					w += spareWidth;
					Dimension max = getComponentSize(c, MAXIMUM);
					Dimension min = getComponentSize(c, MINIMUM);
					w = Math.max(min.width, Math.min(max.width, w));
				}
				if ((nv & STRETCH_V_MASK) != 0) {
					h = rowHeight;
					Dimension max = getComponentSize(c, MAXIMUM);
					Dimension min = getComponentSize(c, MINIMUM);
					h = Math.max(min.height, Math.min(max.height, h));
				}

				if (i == start) {
					if (paragraph)
						x = colWidth1-w;
					else
						x = colWidth1 + hGapMajor;
				} else if (paragraph && i == start+1) {
					x = colWidth1 + hGapMajor;
				}
				int yOffset = paragraphType == NEW_PARAGRAPH_TOP ? 0 : (rowHeight-h)/2;
				c.setBounds(insets.left+hMargin+x, insets.top+vMargin+y+yOffset, w, h);
				x += w + hGapMinor;
			}
		}
	}

}