package com.planimod.ui.views.employees;

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import net.sf.paperclips.ColumnPrint;
import net.sf.paperclips.DefaultGridLook;
import net.sf.paperclips.GridPrint;
import net.sf.paperclips.LineBorder;
import net.sf.paperclips.Print;
import net.sf.paperclips.TextPrint;

import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.iterators.FilterIterator;

import com.patrikdufresne.jface.databinding.conversion.AcronymConverter;
import com.patrikdufresne.printing.FontDataUtil;
import com.patrikdufresne.util.Localized;
import com.planimod.core.EmployeePreference;
import com.planimod.core.Section;
import com.planimod.core.Team;
import com.planimod.core.comparators.EmployeePreferenceComparators;
import com.planimod.core.comparators.SectionComparators;
import com.planimod.core.comparators.TeamComparators;
import com.planimod.ui.databinding.Converters;
import com.planimod.ui.printing.PlanimodPrintFactory;
import com.planimod.ui.printing.PlanimodPrintUtil;

/**
 * This class create a Employee Print Factory. It create a print listing
 * employees.
 * 
 * @author patapouf
 * 
 */
public class EmployeeBySectionPrintFactory extends PlanimodPrintFactory {

	/**
	 * Private class used to organized the data.
	 * 
	 * @author Patrik Dufresne
	 * 
	 */
	private class DataTable {

		private Collection<EmployeePreference> preferences;

		public DataTable(Collection<EmployeePreference> preferences) {
			if (preferences == null) {
				throw new NullPointerException();
			}
			this.preferences = preferences;
		}

		public Collection<Team> listTeam() {
			Set<Team> teams = new HashSet<Team>();
			for (EmployeePreference p : this.preferences) {
				if (p.getPreferredTeam() != null) {
					teams.addAll(p.getPreferredTeam());
				}
			}
			return teams;
		}

		/**
		 * Return the list of preferred section.
		 * 
		 * @return the sections.
		 */
		public Collection<Section> listSections() {
			Set<Section> set = new HashSet<Section>();
			for (EmployeePreference p : this.preferences) {
				set.add(p.getPreferredSection());
			}
			return set;
		}

		/**
		 * Return a collection of employee with the preferred section specified.
		 * 
		 * @param s
		 *            the preferred section or null
		 * @return the employees.
		 */
		public Collection<EmployeePreference> listEmployeeByPreferredSection(
				final Section s) {
			return new AbstractCollection<EmployeePreference>() {

				@SuppressWarnings("unchecked")
				@Override
				public Iterator<EmployeePreference> iterator() {
					return new FilterIterator(
							DataTable.this.preferences.iterator(),
							new Predicate() {
								@Override
								public boolean evaluate(Object object) {
									return (s == null && ((EmployeePreference) object)
											.getPreferredSection() == null)
											|| (s != null && s
													.equals(((EmployeePreference) object)
															.getPreferredSection()));
								}
							});
				}

				@Override
				public int size() {
					int count = 0;
					Iterator<EmployeePreference> iter = iterator();
					while (iter.hasNext()) {
						iter.next();
						count++;
					}
					return count;
				}

			};
		}
	}

	/**
	 * Used for localization.
	 */
	private Localized localized = Localized
			.load(EmployeeBySectionPrintFactory.class);

	/**
	 * Hold employees list.
	 */
	private Collection<EmployeePreference> prefs = null;

	/**
	 * Create a new Factory.
	 * 
	 * @param jobName
	 */
	public EmployeeBySectionPrintFactory() {
		super(Localized.get(EmployeeBySectionPrintFactory.class,
				"EmployeeBySectionPrintFactory.jobName")); //$NON-NLS-1$
		setTitle(this.localized.get("EmployeeBySectionPrintFactory.title")); //$NON-NLS-1$
	}

	/**
	 * This implementation create a employees print.
	 */
	@Override
	protected Print createBodyArea() {

		// Retrieved a list of employees
		List<EmployeePreference> list;
		if (this.prefs == null) {
			list = new ArrayList<EmployeePreference>();
		} else {
			list = new ArrayList<EmployeePreference>(this.prefs);
		}
		Collections.sort(list,
				EmployeePreferenceComparators.byPreferredSectionAndSeniority());

		DataTable data = new DataTable(this.prefs);

		// Create a Grid holding the data as columns
		GridPrint midGrid = new GridPrint();
		midGrid.addColumn("left:default:grow"); //$NON-NLS-1$

		ColumnPrint column = new ColumnPrint(midGrid, 3, 10);
		column.setCompressed(false);

		// Loop on section
		List<Section> sections = new ArrayList<Section>(data.listSections());
		Collections.sort(sections, SectionComparators.byName());
		for (Section s : sections) {

			// Create a grid to hold the employees
			GridPrint grid;
			grid = new GridPrint();
			grid.addColumn("left:preferred"); //$NON-NLS-1$
			grid.addColumn("left:default:grow"); //$NON-NLS-1$
			grid.addColumn("left:preferred"); //$NON-NLS-1$
			grid.addHeader(new TextPrint(PlanimodPrintUtil.getName(s),
					FontDataUtil.BOLD), 3);
			grid.addHeader(new TextPrint(this.localized
					.get("EmployeeBySectionPrintFactory.column.hireDate"), //$NON-NLS-1$
					FontDataUtil.BOLD));
			grid.addHeader(new TextPrint(this.localized
					.get("EmployeeBySectionPrintFactory.column.name"), //$NON-NLS-1$
					FontDataUtil.BOLD));
			grid.addHeader(new TextPrint(this.localized
					.get("EmployeeBySectionPrintFactory.column.team"), //$NON-NLS-1$
					FontDataUtil.BOLD));

			// Set the Grid Look
			DefaultGridLook look = new DefaultGridLook();
			LineBorder border = new LineBorder();
			border.setGapSize(2);
			look.setCellBorder(border);
			grid.setLook(look);
			grid.setCellClippingEnabled(false);
			midGrid.add(grid);

			// Loop on employees
			List<EmployeePreference> employees = new ArrayList<EmployeePreference>(
					data.listEmployeeByPreferredSection(s));
			Collections.sort(employees,
					EmployeePreferenceComparators.bySeniority());
			for (EmployeePreference e : employees) {

				grid.add(new TextPrint(PlanimodPrintUtil.getHireDate(e),
						FontDataUtil.SMALL));

				grid.add(new TextPrint(PlanimodPrintUtil.getName(
						e.getEmployee(),
						EmployeePreferenceComparators.hasPreferredPosition(e)),
						FontDataUtil.SMALL));
				grid.add(new TextPrint(PlanimodPrintUtil
						.getFirstPreferredTeamAcronym(e), FontDataUtil.SMALL));

			}

		}

		// Create legend
		midGrid.add(new TextPrint(this.localized
				.get("EmployeeBySectionPrintFactory.column.legend"), //$NON-NLS-1$
				FontDataUtil.BOLD_SMALL));
		List<Team> teams = new ArrayList<Team>(data.listTeam());
		Collections.sort(teams, TeamComparators.byName());
		for (Team t : teams) {
			String line = (String) AcronymConverter.getInstance().convert(
					t.getName())
					+ " : "
					+ (String) Converters.removeFrontNumber().convert(
							t.getName());
			midGrid.add(new TextPrint(line, FontDataUtil.SMALL));
		}

		return column;
	}

	/**
	 * Returns the employees preference list.
	 * 
	 * @return employees list or null
	 */
	public Collection<EmployeePreference> getEmployeePreferences() {
		return this.prefs;
	}

	/**
	 * Sets the list of employees to print.
	 * 
	 * @param prefs
	 *            a list or null
	 */
	public void setEmployeePreferences(Collection<EmployeePreference> prefs) {
		this.prefs = prefs;
	}

}
