/*******************************************************************************
 * 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
 *     Sven Müller - Added tiling support
 *******************************************************************************/
package org.eclipse.draw2d;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.printing.Printer;
import org.eclipse.swt.widgets.Display;

import org.eclipse.draw2d.geometry.Rectangle;

/**
 * Class responsible for printing Figures.
 * 
 * @author Dan Lee
 * @author Eric Bordeau
 * @author Sven Müller
 */
public class PrintFigureOperation extends PrintOperation {

/**
 * The default print mode. Prints at 100% scale and tiles horizontally and/or vertically, 
 * if necessary.
 */
public static final int TILE = 1;
/**
 * A print mode that scales the printer graphics so that the entire printed image fits on 
 * one page.
 */
public static final int FIT_PAGE = 2;
/**
 * A print mode that scales the printer graphics so that the width of the printed image 
 * fits on one page and tiles vertically, if necessary.
 */
public static final int FIT_WIDTH = 3;
/**
 * A print mode that scales the printer graphics so that the height of the printed image 
 * fits on one page and tiles horizontally, if necessary.
 */
public static final int FIT_HEIGHT = 4;

private IFigure printSource;
private Color oldBGColor;
private int printMode = TILE;

/**
 * Constructor for PrintFigureOperation.
 * <p>
 * Note: Descendants must call setPrintSource(IFigure) to set the IFigure that is to be 
 * printed.
 * @see org.eclipse.draw2d.PrintOperation#PrintOperation(Printer)
 */
protected PrintFigureOperation(Printer p) {
	super(p);
}

/**
 * Constructor for PrintFigureOperation.
 * 
 * @param p Printer to print on
 * @param srcFigure Figure to print
 */
public PrintFigureOperation(Printer p, IFigure srcFigure) {
	super(p);
	setPrintSource(srcFigure);
}

/**
 * @return SWT.RIGHT_TO_LEFT if the print source is mirrored; SWT.LEFT_TO_RIGHT otherwise
 * @see org.eclipse.draw2d.PrintOperation#getGraphicsOrientation()
 */
int getGraphicsOrientation() {
	return getPrintSource().isMirrored() ? SWT.RIGHT_TO_LEFT : SWT.LEFT_TO_RIGHT;
}

/**
 * Returns the current print mode.  The print mode is one of: {@link #FIT_HEIGHT},
 * {@link #FIT_PAGE}, or {@link #FIT_WIDTH}.
 * @return the print mode
 */
protected int getPrintMode() {
	return printMode;
}

/**
 * Returns the printSource.
 * 
 * @return IFigure The source IFigure
 */
protected IFigure getPrintSource() {
	return printSource;
}

/**
 * @see org.eclipse.draw2d.PrintOperation#preparePrintSource()
 */
protected void preparePrintSource() {
	oldBGColor = getPrintSource().getLocalBackgroundColor();
	getPrintSource().setBackgroundColor(ColorConstants.white);
}

/**
 * Prints the pages based on the current print mode.
 * @see org.eclipse.draw2d.PrintOperation#printPages()
 */
protected void printPages() {
	Graphics graphics = getFreshPrinterGraphics();
	IFigure figure = getPrintSource();
	setupPrinterGraphicsFor(graphics, figure);
	Rectangle bounds = figure.getBounds();
	int x = bounds.x, y = bounds.y;
	Rectangle clipRect = new Rectangle();
	while (y < bounds.y + bounds.height) {
		while (x < bounds.x + bounds.width) {
			graphics.pushState();
			getPrinter().startPage();
			graphics.translate(-x, -y);
			graphics.getClip(clipRect);
			clipRect.setLocation(x, y);
			graphics.clipRect(clipRect);
			figure.paint(graphics);
			getPrinter().endPage();
			graphics.popState();
			x += clipRect.width;
		}
		x = bounds.x;
		y += clipRect.height;
	}
}

/**
 * @see org.eclipse.draw2d.PrintOperation#restorePrintSource()
 */
protected void restorePrintSource() {
	getPrintSource().setBackgroundColor(oldBGColor);
	oldBGColor = null;
}

/**
 * Sets the print mode.  Possible values are {@link #TILE}, {@link #FIT_HEIGHT}, 
 * {@link #FIT_WIDTH} and {@link #FIT_PAGE}.
 * @param mode the print mode
 */
public void setPrintMode(int mode) {
	printMode = mode;
}

/**
 * Sets the printSource.
 * @param printSource The printSource to set
 */
protected void setPrintSource(IFigure printSource) {
	this.printSource = printSource;
}

/**
 * Sets up Graphics object for the given IFigure.
 * @param graphics The Graphics to setup
 * @param figure The IFigure used to setup graphics
 */
protected void setupPrinterGraphicsFor(Graphics graphics, IFigure figure) {
	double dpiScale = (double)getPrinter().getDPI().x / Display.getCurrent().getDPI().x;
	
	Rectangle printRegion = getPrintRegion();
	// put the print region in display coordinates
	printRegion.width /= dpiScale;
	printRegion.height /= dpiScale;
	
	Rectangle bounds = figure.getBounds();
	double xScale = (double)printRegion.width / bounds.width;
	double yScale = (double)printRegion.height / bounds.height;
	switch (getPrintMode()) {
		case FIT_PAGE:
			graphics.scale(Math.min(xScale, yScale) * dpiScale);
			break;
		case FIT_WIDTH:
			graphics.scale(xScale * dpiScale);
			break;
		case FIT_HEIGHT:
			graphics.scale(yScale * dpiScale);
			break;
		default:
			graphics.scale(dpiScale);
	}
	graphics.setForegroundColor(figure.getForegroundColor());
	graphics.setBackgroundColor(figure.getBackgroundColor());
	graphics.setFont(figure.getFont());
}

}