/**
 * Copyright (C) 2019 Patrik Dufresne Service Logiciel <info@patrikdufresne.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package com.planimod.ui.views.employees;

import static com.planimod.ui.Localized._;

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 org.eclipse.nebula.paperclips.core.ColumnPrint;
import org.eclipse.nebula.paperclips.core.grid.DefaultGridLook;
import org.eclipse.nebula.paperclips.core.grid.GridPrint;
import org.eclipse.nebula.paperclips.core.border.LineBorder;
import org.eclipse.nebula.paperclips.core.Print;
import org.eclipse.nebula.paperclips.core.text.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.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;
                }

            };
        }
    }

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

    /**
     * Create a new Factory.
     * 
     * @param jobName
     */
    public EmployeeBySectionPrintFactory() {
        super(_("Classification des employés"));
        setTitle(_("Classement des employés"));
    }

    /**
     * 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");

        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");
            grid.addColumn("left:default:grow");
            grid.addColumn("left:preferred");
            grid.addHeader(new TextPrint(PlanimodPrintUtil.getName(s), FontDataUtil.BOLD), 3);
            grid.addHeader(new TextPrint(_("Date anc."), FontDataUtil.BOLD));
            grid.addHeader(new TextPrint(_("Employé"), FontDataUtil.BOLD));
            grid.addHeader(new TextPrint(_(" "), 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(_("Légende"), 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;
    }

}
