/*
 * Copyright (c) 2007 Matthew Hall 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:
 *     Matthew Hall - initial API and implementation
 */
package net.sf.paperclips;

import net.sf.paperclips.internal.ResourcePool;
import net.sf.paperclips.internal.Util;

import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;

/**
 * A class for adding line breaks corresponding to a particular font size.
 * Currently this class is used internally by StyledTextPrint to implement the
 * newline() feature.
 * 
 * @author Matthew Hall
 */
public class LineBreakPrint implements Print {
	final FontData font;

	/**
	 * Constructs a new LineBreakPrint on the given font.
	 * 
	 * @param font
	 *            the font which determines the height of the line break.
	 */
	public LineBreakPrint(FontData font) {
		Util.notNull(font);
		this.font = font;
	}

	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((font == null) ? 0 : font.hashCode());
		return result;
	}

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		LineBreakPrint other = (LineBreakPrint) obj;
		if (font == null) {
			if (other.font != null)
				return false;
		} else if (!font.equals(other.font))
			return false;
		return true;
	}

	public PrintIterator iterator(Device device, GC gc) {
		return new LineBreakIterator(this, device, gc);
	}
}

class LineBreakIterator implements PrintIterator {
	private static final int MIN_HEIGHT = 0;
	private static final int MIN_WIDTH = 1;

	private final int lineHeight;
	private boolean hasNext = true;

	LineBreakIterator(LineBreakPrint print, Device device, GC gc) {
		this(calculateLineHeight(print, device, gc));
	}

	private LineBreakIterator(int lineHeight) {
		this.lineHeight = lineHeight;
	}

	private static int calculateLineHeight(LineBreakPrint print, Device device,
			GC gc) {
		Font oldFont = gc.getFont();

		gc.setFont(ResourcePool.forDevice(device).getFont(print.font));
		int result = gc.getFontMetrics().getHeight();

		gc.setFont(oldFont);

		return result;
	}

	public Point minimumSize() {
		return new Point(MIN_WIDTH, MIN_HEIGHT);
	}

	public Point preferredSize() {
		return new Point(MIN_WIDTH, lineHeight);
	}

	public boolean hasNext() {
		return hasNext;
	}

	public PrintPiece next(int width, int height) {
		if (width < MIN_WIDTH || height < MIN_HEIGHT)
			return null;

		hasNext = false;
		return new EmptyPiece(new Point(width, Math.min(height, lineHeight)));
	}

	public PrintIterator copy() {
		return hasNext ? new LineBreakIterator(lineHeight) : this;
	}
}