/** * Copyright © 2002 Instituto Superior Técnico * * This file is part of FenixEdu Academic. * * FenixEdu Academic 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. * * FenixEdu Academic 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 FenixEdu Academic. If not, see <http://www.gnu.org/licenses/>. */ package org.fenixedu.academic.util.renderer; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.fenixedu.commons.i18n.I18N; import org.joda.time.DateTime; import org.joda.time.Days; import org.joda.time.Interval; import org.joda.time.YearMonthDay; public class GanttDiagram { private final static Comparator<Interval> INTERVAL_COMPARATOR_BY_BEGIN = new Comparator<Interval>() { @Override public int compare(Interval o1, Interval o2) { return o1.getStart().compareTo(o2.getStart()); } }; private final static Comparator<Interval> INTERVAL_COMPARATOR_BY_END = new Comparator<Interval>() { @Override public int compare(Interval o1, Interval o2) { return o1.getEnd().compareTo(o2.getEnd()); } }; private Locale locale; private List<? extends GanttDiagramEvent> events; private ViewType viewType; private DateTime firstInstant, lastInstant; private Map<Integer, Integer> yearsView; private Map<YearMonthDay, Integer> monthsView; private List<DateTime> months, days; public static GanttDiagram getNewTotalGanttDiagram(List<? extends GanttDiagramEvent> events_, YearMonthDay begin, YearMonthDay end) { return new GanttDiagram(events_, ViewType.TOTAL, begin, end); } public static GanttDiagram getNewWeeklyGanttDiagram(List<? extends GanttDiagramEvent> events_, YearMonthDay begin) { return new GanttDiagram(events_, ViewType.WEEKLY, begin); } public static GanttDiagram getNewDailyGanttDiagram(List<? extends GanttDiagramEvent> events_, YearMonthDay begin) { return new GanttDiagram(events_, ViewType.DAILY, begin); } public static GanttDiagram getNewMonthlyGanttDiagram(List<? extends GanttDiagramEvent> events_, YearMonthDay begin) { return new GanttDiagram(events_, ViewType.MONTHLY, begin); } public static GanttDiagram getNewMonthlyTotalGanttDiagram(List<? extends GanttDiagramEvent> events_, YearMonthDay begin) { return new GanttDiagram(events_, ViewType.MONTHLY_TOTAL, begin); } public static GanttDiagram getNewYearDailyGanttDiagram(List<? extends GanttDiagramEvent> events_, YearMonthDay begin) { return new GanttDiagram(events_, ViewType.YEAR_DAILY, begin); } private GanttDiagram(List<? extends GanttDiagramEvent> events_, ViewType type) { setViewType(type); setEvents(events_); init(type, null, null); } private GanttDiagram(List<? extends GanttDiagramEvent> events_, ViewType type, YearMonthDay begin) { setViewType(type); setEvents(events_); init(type, begin, null); } private GanttDiagram(List<? extends GanttDiagramEvent> events_, ViewType type, YearMonthDay begin, YearMonthDay end) { setViewType(type); setEvents(events_); init(type, begin, end); } private void init(ViewType type, YearMonthDay begin, YearMonthDay end) { switch (type) { case TOTAL: calculateFirstAndLastInstantInTotalMode(begin, end); generateYearsViewAndMonths(); break; case MONTHLY_TOTAL: calculateFirstAndLastInstantInMonthlyMode(begin); generateYearsViewAndMonths(); break; case MONTHLY: calculateFirstAndLastInstantInMonthlyMode(begin); generateYearsViewMonthsViewAndDays(); break; case WEEKLY: calculateFirstAndLastInstantInWeeklyMode(begin); generateYearsViewMonthsViewAndDays(); break; case DAILY: calculateFirstAndLastInstantInDailyMode(begin); generateYearsViewMonthsViewAndDays(); break; case YEAR_DAILY: calculateFirstAndLastInstantInMonthlyMode(begin); generateYearsViewMonthsViewAndDays(); break; default: break; } } private void calculateFirstAndLastInstantInMonthlyMode(YearMonthDay begin) { if (begin == null) { throw new IllegalArgumentException(); } DateTime beginDateTime = begin.toDateTimeAtMidnight(); beginDateTime = (beginDateTime.getDayOfMonth() != 1) ? beginDateTime.withDayOfMonth(1) : beginDateTime; setFirstInstant(beginDateTime); setLastInstant(beginDateTime.plusMonths(1).minusDays(1)); } private void calculateFirstAndLastInstantInDailyMode(YearMonthDay begin) { if (begin == null) { throw new IllegalArgumentException(); } setFirstInstant(begin.toDateTimeAtMidnight()); setLastInstant(begin.toDateTimeAtMidnight()); } private void calculateFirstAndLastInstantInWeeklyMode(YearMonthDay begin) { if (begin == null) { throw new IllegalArgumentException(); } DateTime beginDateTime = begin.toDateTimeAtMidnight(); beginDateTime = (beginDateTime.getDayOfWeek() != 1) ? beginDateTime.withDayOfWeek(1) : beginDateTime; setFirstInstant(beginDateTime); setLastInstant(beginDateTime.plusDays(6)); } private void calculateFirstAndLastInstantInTotalMode(YearMonthDay begin, YearMonthDay end) { if ((begin != null && end == null) || (end != null && begin == null)) { throw new IllegalArgumentException(); } if (begin == null) { SortedSet<Interval> allIntervalsSortedByBeginDate = new TreeSet<Interval>(INTERVAL_COMPARATOR_BY_BEGIN); for (GanttDiagramEvent event : getEvents()) { allIntervalsSortedByBeginDate.addAll(event.getGanttDiagramEventSortedIntervals()); } if (!allIntervalsSortedByBeginDate.isEmpty()) { setFirstInstant(allIntervalsSortedByBeginDate.first().getStart().toDateMidnight().toDateTime()); } SortedSet<Interval> allIntervalsSortedByEndDate = new TreeSet<Interval>(INTERVAL_COMPARATOR_BY_END); for (GanttDiagramEvent event : getEvents()) { allIntervalsSortedByEndDate.addAll(event.getGanttDiagramEventSortedIntervals()); } if (!allIntervalsSortedByEndDate.isEmpty()) { setLastInstant(allIntervalsSortedByEndDate.last().getEnd().toDateMidnight().toDateTime()); } } else { setFirstInstant(begin.toDateTimeAtMidnight()); setLastInstant(end.toDateTimeAtMidnight()); } if ((getFirstInstant() != null && getLastInstant() != null) && (getFirstInstant().isAfter(getLastInstant()) || getLastInstant().isBefore(getFirstInstant()))) { throw new IllegalArgumentException(); } } private void generateYearsViewMonthsViewAndDays() { DateTime firstMonthDateTime = getFirstInstant(); DateTime lastMontDateTime = getLastInstant(); if (firstMonthDateTime != null && lastMontDateTime != null) { while ((firstMonthDateTime.getYear() < lastMontDateTime.getYear()) || (firstMonthDateTime.getYear() == lastMontDateTime.getYear() && firstMonthDateTime.getDayOfYear() <= lastMontDateTime .getDayOfYear())) { getDays().add(firstMonthDateTime); YearMonthDay day = firstMonthDateTime.toYearMonthDay().withDayOfMonth(1); if (getMonthsView().containsKey(day)) { getMonthsView().put(day, getMonthsView().get(day) + 1); } else { getMonthsView().put(day, 1); } if (getYearsView().containsKey(Integer.valueOf(firstMonthDateTime.getYear()))) { getYearsView().put(Integer.valueOf(firstMonthDateTime.getYear()), getYearsView().get(Integer.valueOf(firstMonthDateTime.getYear())) + 1); } else { getYearsView().put(Integer.valueOf(firstMonthDateTime.getYear()), 1); } firstMonthDateTime = firstMonthDateTime.plusDays(1); } } } private void generateYearsViewAndMonths() { DateTime firstMonthDateTime = getFirstInstant(); DateTime lastMontDateTime = getLastInstant(); if (firstMonthDateTime != null && lastMontDateTime != null) { while ((firstMonthDateTime.getYear() < lastMontDateTime.getYear()) || (firstMonthDateTime.getYear() == lastMontDateTime.getYear() && firstMonthDateTime.getMonthOfYear() <= lastMontDateTime .getMonthOfYear())) { getMonths().add(firstMonthDateTime); if (getYearsView().containsKey(Integer.valueOf(firstMonthDateTime.getYear()))) { getYearsView().put(Integer.valueOf(firstMonthDateTime.getYear()), getYearsView().get(Integer.valueOf(firstMonthDateTime.getYear())) + 1); } else { getYearsView().put(Integer.valueOf(firstMonthDateTime.getYear()), 1); } firstMonthDateTime = firstMonthDateTime.plusMonths(1); } } } public List<? extends GanttDiagramEvent> getEvents() { return events; } public void setEvents(List<? extends GanttDiagramEvent> events) { this.events = events; } public DateTime getFirstInstant() { return firstInstant; } public void setFirstInstant(DateTime firstInstant) { this.firstInstant = firstInstant; } public DateTime getLastInstant() { return lastInstant; } public void setLastInstant(DateTime lastInstant) { this.lastInstant = lastInstant; } public List<DateTime> getMonths() { if (months == null) { months = new ArrayList<DateTime>(); } return months; } public void setMonths(List<DateTime> months) { this.months = months; } public int getMonthsDaysSize() { int result = 0; for (DateTime month : getMonths()) { DateTime firstDayOfMonth = (month.getDayOfMonth() != 1) ? month.withDayOfMonth(1) : month; DateTime lastDayOfMonth = firstDayOfMonth.plusMonths(1).minusDays(1); int monthNumberOfDays = Days.daysBetween(firstDayOfMonth, lastDayOfMonth).getDays() + 1; result += monthNumberOfDays; } return result; } public Map<Integer, Integer> getYearsView() { if (yearsView == null) { yearsView = new TreeMap<Integer, Integer>(); } return yearsView; } public void setYearsView(Map<Integer, Integer> years) { this.yearsView = years; } public Map<YearMonthDay, Integer> getMonthsView() { if (monthsView == null) { monthsView = new TreeMap<YearMonthDay, Integer>(); } return monthsView; } public void setMonthsView(Map<YearMonthDay, Integer> monthsView) { this.monthsView = monthsView; } public ViewType getViewType() { return viewType; } public void setViewType(ViewType viewType) { this.viewType = viewType; } public Locale getLocale() { if (locale == null) { locale = I18N.getLocale(); } return locale; } public void setLocale(Locale locale) { this.locale = locale; } public List<DateTime> getDays() { if (days == null) { days = new ArrayList<DateTime>(); } return days; } public void setDays(List<DateTime> days) { this.days = days; } public enum ViewType { TOTAL, MONTHLY, MONTHLY_TOTAL, WEEKLY, DAILY, YEAR_DAILY; } }