<commit_before>/*
 * This file is part of NavalPlan
 *
 * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
 *                    Desenvolvemento Tecnolóxico de Galicia
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.navalplanner.web.planner.chart;

import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.calendars.entities.SameWorkHoursEveryDay;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.resources.entities.Resource;
import org.zkforge.timeplot.Plotinfo;
import org.zkforge.timeplot.Timeplot;
import org.zkforge.timeplot.data.PlotDataSource;
import org.zkforge.timeplot.geometry.DefaultTimeGeometry;
import org.zkforge.timeplot.geometry.DefaultValueGeometry;
import org.zkforge.timeplot.geometry.TimeGeometry;
import org.zkforge.timeplot.geometry.ValueGeometry;
import org.zkoss.ganttz.servlets.CallbackServlet;
import org.zkoss.ganttz.servlets.CallbackServlet.IServletRequestHandler;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.Interval;
import org.zkoss.zk.ui.Executions;

/**
 * Abstract class with the basic functionality to fill the chart.
 * @author <NAME> <<EMAIL>>
 */
public abstract class ChartFiller implements IChartFiller {

    protected abstract class HoursByDayCalculator<T> {
        public SortedMap<LocalDate, BigDecimal> calculate(
                Collection<? extends T> elements) {
            SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
            if (elements.isEmpty()) {
                return result;
            }
            for (T element : elements) {
                if (included(element)) {
                    int hours = getHoursFor(element);
                    LocalDate day = getDayFor(element);
                    if (!result.containsKey(day)) {
                        result.put(day, BigDecimal.ZERO);
                    }
                    result.put(day, result.get(day).add(new BigDecimal(hours)));
                }
            }
            return convertAsNeededByZoom(result);
        }

        protected abstract LocalDate getDayFor(T element);

        protected abstract int getHoursFor(T element);

        protected boolean included(T each) {
            return true;
        }
    }

    protected class DefaultDayAssignmentCalculator extends
            HoursByDayCalculator<DayAssignment> {
        public DefaultDayAssignmentCalculator() {
        }

        @Override
        protected LocalDate getDayFor(DayAssignment element) {
            return element.getDay();
        }

        @Override
        protected int getHoursFor(DayAssignment element) {
            return element.getHours();
        }
    }

    protected final int sumHoursForDay(
            Collection<? extends Resource> resources,
            LocalDate day) {
        int sum = 0;
        for (Resource resource : resources) {
            sum += hoursFor(resource, day);
        }
        return sum;
    }

    private int hoursFor(Resource resource, LocalDate day) {
        int result = 0;
        ResourceCalendar calendar = resource.getCalendar();
        if (calendar != null) {
            result += calendar.getCapacityAt(day);
        } else {
            result += SameWorkHoursEveryDay.getDefaultWorkingDay()
                    .getCapacityAt(day);
        }
        return result;
    }

    protected abstract class GraphicSpecificationCreator implements
            IServletRequestHandler {

        private final LocalDate finish;
        private final SortedMap<LocalDate, BigDecimal> map;
        private final LocalDate start;

        protected GraphicSpecificationCreator(Date finish,
                SortedMap<LocalDate, BigDecimal> map, Date start) {
            this.finish = new LocalDate(finish);
            this.map = map;
            this.start = new LocalDate(start);
        }

        protected Set<LocalDate> getDays() {
            return map.keySet();
        }

        @Override
        public void handle(HttpServletRequest request,
                HttpServletResponse response) throws ServletException,
                IOException {
            PrintWriter writer = response.getWriter();
            fillValues(writer);
            writer.close();
        }

        private void fillValues(PrintWriter writer) {
            fillZeroValueFromStart(writer);
            fillInnerValues(writer, firstDay(), lastDay());
            fillZeroValueToFinish(writer);
        }

        protected abstract void fillInnerValues(PrintWriter writer,
                LocalDate firstDay, LocalDate lastDay);

        protected LocalDate nextDay(LocalDate date) {
            if (isZoomByDay()) {
                return date.plusDays(1);
            } else {
                return date.plusWeeks(1);
            }
        }

        private LocalDate firstDay() {
            LocalDate date = map.firstKey();
            return convertAsNeededByZoom(date);
        }

        private LocalDate lastDay() {
            LocalDate date = map.lastKey();
            return convertAsNeededByZoom(date);
        }

        private LocalDate convertAsNeededByZoom(LocalDate date) {
            if (isZoomByDay()) {
                return date;
            } else {
                return getThursdayOfThisWeek(date);
            }
        }

        protected BigDecimal getHoursForDay(LocalDate day) {
            return map.get(day) != null ? map
                    .get(day) : BigDecimal.ZERO;
        }

        protected void printLine(PrintWriter writer, LocalDate day,
                BigDecimal hours) {
            writer.println(day.toString("yyyyMMdd") + " " + hours);
        }

        private void fillZeroValueFromStart(PrintWriter writer) {
            printLine(writer, start, BigDecimal.ZERO);
            if (startIsPreviousToPreviousDayToFirstAssignment()) {
                printLine(writer, previousDayToFirstAssignment(),
                        BigDecimal.ZERO);
            }
        }

        private boolean startIsPreviousToPreviousDayToFirstAssignment() {
            return !map.isEmpty()
                    && start.compareTo(previousDayToFirstAssignment()) < 0;
        }

        private LocalDate previousDayToFirstAssignment() {
            return map.firstKey().minusDays(1);
        }

        private void fillZeroValueToFinish(PrintWriter writer) {
            if (finishIsPosteriorToNextDayToLastAssignment()) {
                printLine(writer, nextDayToLastAssignment(), BigDecimal.ZERO);
            }
            printLine(writer, finish, BigDecimal.ZERO);
        }

        private boolean finishIsPosteriorToNextDayToLastAssignment() {
            return !map.isEmpty()
                    && finish.compareTo(nextDayToLastAssignment()) > 0;
        }

        private LocalDate nextDayToLastAssignment() {
            return map.lastKey().plusDays(1);
        }
    }

    protected class DefaultGraphicSpecificationCreator extends
            GraphicSpecificationCreator {

        private DefaultGraphicSpecificationCreator(Date finish,
                SortedMap<LocalDate, BigDecimal> map, Date start) {
            super(finish, map, start);
        }

        @Override
        protected void fillInnerValues(PrintWriter writer, LocalDate firstDay,
                LocalDate lastDay) {<commit_msg> ItEr58S04ValidacionEProbasFuncionaisItEr57S04: Small fix on chart filler.<commit_after>/*
 * This file is part of NavalPlan
 *
 * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
 *                    Desenvolvemento Tecnolóxico de Galicia
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.navalplanner.web.planner.chart;

import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.calendars.entities.SameWorkHoursEveryDay;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.resources.entities.Resource;
import org.zkforge.timeplot.Plotinfo;
import org.zkforge.timeplot.Timeplot;
import org.zkforge.timeplot.data.PlotDataSource;
import org.zkforge.timeplot.geometry.DefaultTimeGeometry;
import org.zkforge.timeplot.geometry.DefaultValueGeometry;
import org.zkforge.timeplot.geometry.TimeGeometry;
import org.zkforge.timeplot.geometry.ValueGeometry;
import org.zkoss.ganttz.servlets.CallbackServlet;
import org.zkoss.ganttz.servlets.CallbackServlet.IServletRequestHandler;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.Interval;
import org.zkoss.zk.ui.Executions;

/**
 * Abstract class with the basic functionality to fill the chart.
 * @author <NAME> <<EMAIL>>
 */
public abstract class ChartFiller implements IChartFiller {

    protected abstract class HoursByDayCalculator<T> {
        public SortedMap<LocalDate, BigDecimal> calculate(
                Collection<? extends T> elements) {
            SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
            if (elements.isEmpty()) {
                return result;
            }
            for (T element : elements) {
                if (included(element)) {
                    int hours = getHoursFor(element);
                    LocalDate day = getDayFor(element);
                    if (!result.containsKey(day)) {
                        result.put(day, BigDecimal.ZERO);
                    }
                    result.put(day, result.get(day).add(new BigDecimal(hours)));
                }
            }
            return convertAsNeededByZoom(result);
        }

        protected abstract LocalDate getDayFor(T element);

        protected abstract int getHoursFor(T element);

        protected boolean included(T each) {
            return true;
        }
    }

    protected class DefaultDayAssignmentCalculator extends
            HoursByDayCalculator<DayAssignment> {
        public DefaultDayAssignmentCalculator() {
        }

        @Override
        protected LocalDate getDayFor(DayAssignment element) {
            return element.getDay();
        }

        @Override
        protected int getHoursFor(DayAssignment element) {
            return element.getHours();
        }
    }

    protected final int sumHoursForDay(
            Collection<? extends Resource> resources,
            LocalDate day) {
        int sum = 0;
        for (Resource resource : resources) {
            sum += hoursFor(resource, day);
        }
        return sum;
    }

    private int hoursFor(Resource resource, LocalDate day) {
        int result = 0;
        ResourceCalendar calendar = resource.getCalendar();
        if (calendar != null) {
            result += calendar.getCapacityAt(day);
        } else {
            result += SameWorkHoursEveryDay.getDefaultWorkingDay()
                    .getCapacityAt(day);
        }
        return result;
    }

    protected abstract class GraphicSpecificationCreator implements
            IServletRequestHandler {

        private final LocalDate finish;
        private final SortedMap<LocalDate, BigDecimal> map;
        private final LocalDate start;

        protected GraphicSpecificationCreator(Date finish,
                SortedMap<LocalDate, BigDecimal> map, Date start) {
            this.finish = new LocalDate(finish);
            this.map = map;
            this.start = new LocalDate(start);
        }

        protected Set<LocalDate> getDays() {
            return map.keySet();
        }

        @Override
        public void handle(HttpServletRequest request,
                HttpServletResponse response) throws ServletException,
                IOException {
            PrintWriter writer = response.getWriter();
            fillValues(writer);
            writer.close();
        }

        private void fillValues(PrintWriter writer) {
            fillZeroValueFromStart(writer);
            fillInnerValues(writer, firstDay(), lastDay());
            fillZeroValueToFinish(writer);
        }

        protected abstract void fillInnerValues(PrintWriter writer,
                LocalDate firstDay, LocalDate lastDay);

        protected LocalDate nextDay(LocalDate date) {
            if (isZoomByDay()) {
                return date.plusDays(1);
            } else {
                return date.plusWeeks(1);
            }
        }

        private LocalDate firstDay() {
            LocalDate date = map.firstKey();
            return convertAsNeededByZoom(date);
        }

        private LocalDate lastDay() {
            LocalDate date = map.lastKey();
            return convertAsNeededByZoom(date);
        }

        private LocalDate convertAsNeededByZoom(LocalDate date) {
            if (isZoomByDay()) {
                return date;
            } else {
                return getThursdayOfThisWeek(date);
            }
        }

        protected BigDecimal getHoursForDay(LocalDate day) {
            return map.get(day) != null ? map
                    .get(day) : BigDecimal.ZERO;
        }

        protected void printLine(PrintWriter writer, LocalDate day,
                BigDecimal hours) {
            writer.println(day.toString("yyyyMMdd") + " " + hours);
        }

        private void fillZeroValueFromStart(PrintWriter writer) {
            if (!startIsDayOfFirstAssignment()) {
                printLine(writer, start, BigDecimal.ZERO);
                if (startIsPreviousToPreviousDayToFirstAssignment()) {
                    printLine(writer, previousDayToFirstAssignment(),
                            BigDecimal.ZERO);
                }
            }
        }

        private boolean startIsDayOfFirstAssignment() {
            return !map.isEmpty() && start.compareTo(map.firstKey()) == 0;
        }

        private boolean startIsPreviousToPreviousDayToFirstAssignment() {
            return !map.isEmpty()
                    && start.compareTo(previousDayToFirstAssignment()) < 0;
        }

        private LocalDate previousDayToFirstAssignment() {
            return map.firstKey().minusDays(1);
        }

        private void fillZeroValueToFinish(PrintWriter writer) {
            if (!finishIsDayOfLastAssignment()) {
                if (finishIsPosteriorToNextDayToLastAssignment()) {
                    printLine(writer, nextDayToLastAssignment(),
                            BigDecimal.ZERO);
                }
                printLine(writer, finish, BigDecimal.ZERO);
            }
        }

        private boolean finishIsDayOfLastAssignment() {
            return !map.isEmpty() && start.compareTo(map.lastKey()) == 0;
        }

        private boolean finishIsPosteriorToNextDayToLastAssignment() {
            return !map.isEmpty()
                    && finish.compareTo(nextDayToLastAssignment()) > 0;
        }

        private LocalDate nextDayToLastAssignment() {
            return map.lastKey().plusDays(1);
        }
    }

    protected class DefaultGraphicSpecificationCreator extends
            GraphicSpecificationCreator {

        private DefaultGraphicSpecificationCreator(Date finish,
                SortedMap<LocalDate, BigDecimal> map, Date start) {
            super(finish, map, start);
        }

        @Override
        protected void fillInnerValues(PrintWriter writer, LocalDate firstDay,
                LocalDate lastDay) {
{'fraction_non_alphanumeric': 0.08129715122170926, 'fraction_numerical': 0.0020267987839207298, 'mean_word_length': 2.291882876204596, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6003922', 'n_tokens_mistral': 4630, 'n_tokens_neox': 4487, 'n_words': 1112}