/**
 * 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 static com.planimod.ui.Localized._;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

import com.patrikdufresne.util.DateFormatRegistry;
import com.planimod.core.Employee;
import com.planimod.core.NonAvailability;
import com.planimod.core.Position;
import com.planimod.core.Product;
import com.planimod.core.Section;
import com.planimod.core.Shift;
import com.planimod.core.Task;
import com.planimod.core.TimeRange;
import com.planimod.core.TimeRanges;
import com.planimod.core.comparators.TimeRangeComparators;
import com.planimod.ui.printing.PlanimodPrintUtil;
import com.planimod.ui.viewers.EmployeeViewerUtils;

public class PlanifSummaryHelper {

    /**
     * Return a string representation of the production information with the number of required employee.
     * 
     * @param production
     * @param count
     * @return
     */
    public static String getProduction(Product product, Integer count) {
        String family = product.getFamily() == null || product.getFamily().isEmpty() ? null : product.getFamily();
        String name = product.getName() == null || product.getName().isEmpty() ? null : product.getName();
        String refId = product.getRefId() == null || product.getRefId().isEmpty() ? null : product.getRefId();
        String format = "%s %d";
        if (family != null) {
            return String.format(format, family, count);
        } else if (name != null) {
            return String.format(format, name, count);
        } else if (refId != null) {
            return String.format(format, refId, count);
        }
        // TODO Localize this string.
        return String.format(format, "unknown", count);
    }

    /**
     * Format the employee name as follow. <count> <employee's name> [<classified symbol>] [<swappable symbol>]
     * 
     * @param count
     *            the employee count
     * @param e
     *            the employee
     * @param classified
     *            True if assigned to classified position
     * @param swappable
     *            True if the employee is assign to a swappable
     * @return
     */
    public static String getEmployeeName(int count, Employee e, boolean classified, boolean swappable) {
        return getEmployeeName(count, e, classified, swappable, null);
    }

    /**
     * Format the employee name as follow. <count> <employee's name> [<classified symbol>] [<swappable symbol>]
     * 
     * @param count
     *            the employee count
     * @param e
     *            the employee
     * @param classified
     *            True if assigned to classified position
     * @param swappable
     *            True if the employee is assign to a swappable
     * @return
     */
    public static String getEmployeeName(int count, Employee e, boolean classified, boolean swappable, Section preferredSection) {

        StringBuffer buf = new StringBuffer();
        buf.append(count);
        buf.append(PlanimodPrintUtil.SPACE);
        buf.append(EmployeeViewerUtils.getName(e));
        if (classified) {
            buf.append(_("*"));
        }
        if (swappable) {
            buf.append(_(" [R]"));
        }
        if (preferredSection != null) {
            buf.append(String.format(" (%s)", PlanimodPrintUtil.getName(preferredSection)));
        }

        return buf.toString();

    }

    /**
     * Return a string representation of the non availability.
     * 
     * @param range
     *            the current time range displayed.
     * @param na
     *            the non-availability
     * @return the string representation of the non-availability
     */
    public static String getNonAvailabilityDesc(TimeRange range, NonAvailability na) {

        StringBuilder buf = new StringBuilder();
        buf.append(PlanimodPrintUtil.getName(na.getEmployee()));
        buf.append(" - ");
        if (na.getSummary() != null) {
            buf.append(na.getSummary());
        }
        return buf.toString();

    }

    /**
     * Return a string representation of the non-availability: <Employee's name> - <summary> (<day, day, day>)
     * 
     * @param na
     *            the non-availability.
     * @param tasks
     *            all tasks in the team.
     * @return
     */
    public static String getNonAvailabilityDesc(NonAvailability na, Collection<Shift> shifts) {

        List<Shift> orderShifts = new ArrayList<Shift>(shifts);
        Collections.sort(orderShifts, TimeRangeComparators.byDate());

        StringBuilder buf = new StringBuilder();
        buf.append(PlanimodPrintUtil.getName(na.getEmployee()));
        buf.append(" - ");
        if (na.getSummary() != null) {
            buf.append(na.getSummary());
        }
        buf.append(" (");

        int count = 0;
        for (int i = 0; i < orderShifts.size(); i++) {

            Shift s = orderShifts.get(i);
            if (TimeRanges.containsEquals(na, s)) {
                buf.append(count > 0 ? " " : "");
                buf.append(DateFormatRegistry.format(s.getStartDate(), DateFormatRegistry.DAY_OF_WEEK));
                count++;
            } else if (TimeRanges.intersectBefore(na, s)) {
                buf.append(count > 0 ? " " : "");
                buf.append(DateFormatRegistry.format(s.getStartDate(), DateFormatRegistry.DAY_OF_WEEK));
                buf.append(" ");
                buf.append(DateFormatRegistry.format(s.getStartDate(), DateFormatRegistry.TIME | DateFormatRegistry.MEDIUM));
                buf.append(" - ");
                buf.append(DateFormatRegistry.format(na.getEndDate(), DateFormatRegistry.TIME | DateFormatRegistry.MEDIUM));
                count++;
            } else if (TimeRanges.intersectAfter(na, s)) {
                buf.append(count > 0 ? " " : "");
                buf.append(DateFormatRegistry.format(na.getStartDate(), DateFormatRegistry.DAY_OF_WEEK));
                buf.append(" ");
                buf.append(DateFormatRegistry.format(na.getStartDate(), DateFormatRegistry.TIME | DateFormatRegistry.MEDIUM));
                buf.append(" - ");
                buf.append(DateFormatRegistry.format(s.getEndDate(), DateFormatRegistry.TIME | DateFormatRegistry.MEDIUM));
                count++;
            } else if (TimeRanges.containsEquals(s, na)) {
                buf.append(count > 0 ? " " : "");
                buf.append(DateFormatRegistry.formatRange(na.getStartDate(), na.getEndDate(), DateFormatRegistry.TIME | DateFormatRegistry.MEDIUM));
                count++;
            }

        }
        buf.append(")");

        return buf.toString();
    }

    /**
     * Return a string representation of the vacant tasks.
     * <p>
     * The received collection should correspond to the same task with different day for the same team. If the
     * collection doesn't represent the same task, this function return an unexpected value.
     * 
     * @param tasks
     *            collection of tasks representing a position within one team being vacant.
     * 
     * @return the description of the task being vacant. e.g.: <Position name> - <days>
     */
    public static String getVacantDesc(Collection<Task> tasks) {
        if (tasks.size() == 0) {
            throw new IllegalArgumentException();
        }

        Position position = tasks.iterator().next().getPosition();
        if (position == null) {
            return "";
        }

        /*
         * Build list of days
         */
        Collection<Integer> days = new HashSet<Integer>();
        Calendar cal = Calendar.getInstance();
        for (Task task : tasks) {
            cal.setTime(task.getStartDate());
            days.add(Integer.valueOf(cal.get(Calendar.DAY_OF_WEEK)));
        }
        days = new ArrayList<Integer>(days);
        Collections.sort((List<Integer>) days);

        /*
         * Build the string.
         */
        StringBuilder buf = new StringBuilder();
        buf.append(PlanimodPrintUtil.getName(position));
        buf.append(" (");

        int count = 0;
        SimpleDateFormat dateformat = new SimpleDateFormat("EE");
        for (Integer day : days) {
            cal.set(Calendar.DAY_OF_WEEK, day.intValue());
            buf.append(count > 0 ? " " : "");
            buf.append(dateformat.format(cal.getTime()));
            count++;
        }
        buf.append(")");

        return buf.toString();
    }

    /**
     * Return a string to identify a recall from non-availability
     * 
     * @return
     */
    public static String recall() {
        return _(" (Retour)");
    }

}
