/*
 * Copyright (c) 2011, Patrik Dufresne. All rights reserved.
 * Patrik Dufresne PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.planimod.ui.views.planif.printing;

import java.util.ArrayList;
import java.util.List;

import net.sf.paperclips.ColumnPrint;
import net.sf.paperclips.GridPrint;
import net.sf.paperclips.LineBreakPrint;
import net.sf.paperclips.NoBreakPrint;
import net.sf.paperclips.Print;
import net.sf.paperclips.TextPrint;

import com.patrikdufresne.printing.FontDataUtil;

/**
 * This class is used to handle the creation of a grid printed on multiple
 * column but with a minimum number of rows determine by the totla number if
 * item in the grid.
 * <p>
 * This class is intended to be used to print grid for the planif report.
 * 
 * @author Patrik Dufresne
 * 
 */
public class GridHelper {

	int groupId = 0;

	class Entry {
		public Entry(int groupId, Print print, boolean force) {
			super();
			this.groupId = groupId;
			this.print = print;
			this.force = force;
		}

		int groupId;
		Print print;
		/**
		 * True to force the print to be display even if their is only one
		 * group.
		 */
		boolean force;
	}

	List<Entry> prints = new ArrayList<GridHelper.Entry>();

	public GridHelper() {

	}

	private void addGroup(Print print, boolean force) {
		this.groupId++;
		this.prints.add(new Entry(this.groupId, print, force));
	}

	/**
	 * Add a new employee to the current section.
	 * 
	 * @param print
	 *            the print
	 */
	private void addItem(Print print) {
		if (this.groupId == 0) {
			throw new IllegalArgumentException(
					"addSection should be called first."); //$NON-NLS-1$
		}
		this.prints.add(new Entry(this.groupId, print, false));
	}

	/**
	 * 
	 * @param columns
	 *            the number of columns to display
	 * @param spacing
	 *            the spacing between each column.
	 * @return
	 */
	public Print createPrint(int columns, int spacing) {
		if (columns < 2) {
			throw new IllegalArgumentException("columns must be >= 2"); //$NON-NLS-1$
		}
		// Count the total number of rows required for this team.
		int nbRow = Math.max(2, this.prints.size() / columns);

		GridPrint grid = new GridPrint();
		grid.addColumn("l:d:g"); //$NON-NLS-1$
		grid.setCellClippingEnabled(false);

		// Loop on prints.
		int curSectionId = 0;
		GridPrint sectionGrid = null;
		for (int i = 0; i < this.prints.size(); i++) {
			Entry e = this.prints.get(i);

			// Check if we enter in a new section.
			if (curSectionId != e.groupId) {

				// Close the previous section by adding a new line break.
				if (curSectionId != 0) {
					if (sectionGrid != null
							&& sectionGrid.getBodyCells().length < nbRow) {
						sectionGrid.add(new LineBreakPrint(FontDataUtil.SMALL));
					} else {
						grid.add(new LineBreakPrint(FontDataUtil.SMALL));
					}
				}

				// Keep track of the new section.
				curSectionId = e.groupId;

				// If their is more then one section, we must create a grid to
				// hold the first items. This will define the height of the
				// Print. Otherwise it's too compress.
				if (this.groupId > 1 || e.force) {
					sectionGrid = new GridPrint();
					sectionGrid.addColumn("l:d:g"); //$NON-NLS-1$
					if (e.print != null) {
						sectionGrid.add(e.print);
					}
					grid.add(new NoBreakPrint(sectionGrid));
				} else {
					sectionGrid = null;
				}
			} else {

				// Add the employee label to the section grid or to the global
				// grid.
				if (sectionGrid != null
						&& sectionGrid.getBodyCells().length < nbRow) {
					sectionGrid.add(e.print);
				} else {
					grid.add(new NoBreakPrint(e.print));
				}

			}
		}

		return new ColumnPrint(grid, columns, spacing);

	}

	/**
	 * Add a new group. Items added after this call will be added to this group.
	 * 
	 * @param string
	 *            the group name name
	 * @param force
	 *            True to force the group name to be displayed even if their is
	 *            only one group in the print.
	 */
	public void addGroup(String string, boolean force) {
		addGroup(string == null ? null : new TextPrint(string,
				FontDataUtil.BOLD_SMALL), force);
	}

	/**
	 * Add a new group. Items added after this call will be added to this group.
	 * 
	 * @param string
	 *            the group name or null
	 */
	public void addGroup(String string) {
		addGroup(string, false);
	}

	/**
	 * Defaulot method to add an employee to the current section. This function
	 * is same as calling {@link #addItem(Print)} with a TextPrint.
	 * 
	 * @param nonAvailabilityDesc
	 */
	public void addItem(String string) {
		addItem(new TextPrint(string, FontDataUtil.SMALL));
	}

}
