/**
 * 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.planif.printing;

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

import org.eclipse.nebula.paperclips.core.ColumnPrint;
import org.eclipse.nebula.paperclips.core.grid.GridPrint;
import org.eclipse.nebula.paperclips.core.text.LineBreakPrint;
import org.eclipse.nebula.paperclips.core.NoBreakPrint;
import org.eclipse.nebula.paperclips.core.Print;
import org.eclipse.nebula.paperclips.core.text.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.");
        }
        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");
        }
        // 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");
        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");
                    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));
    }

}
