package com.psddev.cms.tool.widget;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.servlet.ServletException;
import com.psddev.dari.util.JspUtils;
import org.joda.time.DateTime;
import com.google.common.collect.ImmutableMap;
import com.psddev.cms.db.Draft;
import com.psddev.cms.db.Schedule;
import com.psddev.cms.db.Site;
import com.psddev.cms.tool.Dashboard;
import com.psddev.cms.tool.DefaultDashboardWidget;
import com.psddev.cms.tool.ToolPageContext;
import com.psddev.dari.db.Query;
import com.psddev.dari.util.ObjectUtils;
public class ScheduledEventsWidget extends DefaultDashboardWidget {
@Override
public int getColumnIndex() {
return 1;
}
@Override
public int getWidgetIndex() {
return 2;
}
@Override
public void writeHtml(ToolPageContext page, Dashboard dashboard) throws IOException, ServletException {
Mode mode = page.pageParam(Mode.class, "mode", Mode.WEEK);
DateTime date = new DateTime(page.param(Date.class, "date"), page.getUserDateTimeZone());
DateTime begin = mode.getBegin(date);
DateTime end = mode.getEnd(date);
Map<DateTime, List<Schedule>> schedulesByDate = new TreeMap<DateTime, List<Schedule>>();
boolean hasSchedules = false;
for (DateTime i = begin; i.isBefore(end); i = i.plusDays(1)) {
schedulesByDate.put(i, new ArrayList<Schedule>());
}
Site currentSite = page.getSite();
for (Schedule schedule : Query
.from(Schedule.class)
.where("triggerDate >= ? and triggerDate < ?", begin, end)
.sortAscending("triggerDate")
.iterable(0)) {
if (currentSite != null && !currentSite.equals(schedule.getTriggerSite())) {
continue;
}
DateTime scheduleDate = page.toUserDateTime(schedule.getTriggerDate()).toDateMidnight().toDateTime();
List<Schedule> schedules = schedulesByDate.get(scheduleDate);
if (schedules != null) {
schedules.add(schedule);
hasSchedules = true;
}
}
page.writeStart("div", "class", "widget widget-scheduledEvents" + (hasSchedules ? "" : " widget-scheduledEvents-empty"));
page.writeStart("h1", "class", "icon icon-action-schedule");
page.writeHtml(page.localize(ScheduledEventsWidget.class, "title"));
page.writeEnd();
page.writeStart("ul", "class", "scheduledEvents-controls");
page.writeStart("li");
page.writeStart("a",
"class", "icon icon-action-create",
"href", page.cmsUrl("/scheduleEdit"),
"target", "scheduleEdit");
page.writeHtml(page.localize(ScheduledEventsWidget.class, "action.new"));
page.writeEnd();
page.writeEnd();
page.writeStart("li");
page.writeStart("a",
"class", "icon icon-action-search",
"href", page.cmsUrl("/scheduleList"),
"target", "scheduleList");
page.writeHtml(page.localize(ScheduledEventsWidget.class, "action.viewAll"));
page.writeEnd();
page.writeEnd();
page.writeEnd();
String beginMonth = begin.monthOfYear().getAsText();
int beginDay = begin.dayOfMonth().get();
int beginYear = begin.year().get();
DateTime displayEnd = end.minusDays(1);
String displayEndMonth = displayEnd.monthOfYear().getAsText();
int displayEndDay = displayEnd.dayOfMonth().get();
int displayEndYear = displayEnd.year().get();
//TODO: LOCALIZE
page.writeStart("div", "class", "scheduledEvents-date");
page.writeStart("div", "class", "scheduledEvents-dateDisplay");
page.writeStart("form",
"class", "autoSubmit",
"method", "get",
"action", page.url(null));
page.writeStart("select", "name", "mode");
for (Mode m : Mode.values()) {
page.writeStart("option",
"selected", m.equals(mode) ? "selected" : null,
"value", m.name());
page.writeHtml(page.localize(ScheduledEventsWidget.class, m.resourceKey));
page.writeEnd();
}
page.writeEnd();
page.writeEnd();
page.writeStart("div", "class", "scheduledEvents-dateRange");
page.writeHtml(beginMonth);
page.writeHtml(" ");
page.writeHtml(beginDay);
if (beginYear != displayEndYear) {
page.writeHtml(", ");
page.writeHtml(beginYear);
}
if (beginDay != displayEndDay) {
page.writeHtml(" - ");
if (!displayEndMonth.equals(beginMonth)) {
page.writeHtml(displayEndMonth);
page.writeHtml(" ");
}
page.writeHtml(displayEndDay);
}
page.writeHtml(", ");
page.writeHtml(displayEndYear);
page.writeEnd();
page.writeEnd();
page.writeStart("ul", "class", "pagination scheduledEvents-datePagination");
DateTime previous = mode.getPrevious(date);
DateTime today = new DateTime(null, page.getUserDateTimeZone()).toDateMidnight().toDateTime();
if (!previous.isBefore(today)) {
page.writeStart("li", "class", "previous");
page.writeStart("a",
"href", page.url("", "date", previous.getMillis()));
page.writeHtml(page.localize(
ScheduledEventsWidget.class,
ImmutableMap.of("mode", mode),
"pagination.previous"));
page.writeEnd();
page.writeEnd();
}
page.writeStart("li");
page.writeStart("a",
"href", page.url("", "date", System.currentTimeMillis()));
page.writeHtml(page.localize(ScheduledEventsWidget.class, "option.today"));
page.writeEnd();
page.writeEnd();
page.writeStart("li", "class", "next");
page.writeStart("a",
"href", page.url("", "date", mode.getNext(date).getMillis()));
page.writeHtml(page.localize(
ScheduledEventsWidget.class,
ImmutableMap.of("mode", mode),
"pagination.next"));
page.writeEnd();
page.writeEnd();
page.writeEnd();
page.writeEnd();
mode.display(page, schedulesByDate);
page.writeEnd();
}
private enum Mode {
DAY("option.day") {
@Override
public DateTime getBegin(DateTime date) {
return date.toDateMidnight().toDateTime();
}
@Override
public DateTime getEnd(DateTime date) {
return getBegin(date).plusDays(1);
}
@Override
public DateTime getPrevious(DateTime date) {
return date.plusDays(-1);
}
@Override
public DateTime getNext(DateTime date) {
return date.plusDays(1);
}
@Override
public void display(ToolPageContext page, Map<DateTime, List<Schedule>> schedulesByDate) throws IOException {
displayAgendaView(page, schedulesByDate);
}
},
WEEK("option.week") {
@Override
public DateTime getBegin(DateTime date) {
return date.toDateMidnight().toDateTime();
}
@Override
public DateTime getEnd(DateTime date) {
return getBegin(date).plusWeeks(1);
}
@Override
public DateTime getPrevious(DateTime date) {
return date.plusWeeks(-1);
}
@Override
public DateTime getNext(DateTime date) {
return date.plusWeeks(1);
}
@Override
public void display(ToolPageContext page, Map<DateTime, List<Schedule>> schedulesByDate) throws IOException {
displayAgendaView(page, schedulesByDate);
}
},
MONTH("option.month") {
@Override
public DateTime getBegin(DateTime date) {
return date.toDateMidnight().withDayOfMonth(1).toDateTime();
}
@Override
public DateTime getEnd(DateTime date) {
return getBegin(date).plusMonths(1);
}
@Override
public DateTime getPrevious(DateTime date) {
return date.plusMonths(-1);
}
@Override
public DateTime getNext(DateTime date) {
return date.plusMonths(1);
}
@Override
public void display(ToolPageContext page, Map<DateTime, List<Schedule>> schedulesByDate) throws IOException {
page.writeStart("div", "class", "calendar calendar-month");
for (Map.Entry<DateTime, List<Schedule>> entry : schedulesByDate.entrySet()) {
DateTime date = entry.getKey();
List<Schedule> schedules = entry.getValue();
if (date.getDayOfMonth() == 1 || date.getDayOfWeek() == 1) {
page.writeStart("div", "class", "calendarRow");
if (date.getDayOfMonth() == 1) {
int offset = date.getDayOfWeek() - 1;
for (int i = offset; i > 0; i--) {
writeCalendarDay(page, null, date.minusDays(i), "other-month");
}
}
}
writeCalendarDay(page, schedules, date, "");
if (date.dayOfMonth().withMaximumValue().equals(date)) {
int extraDays = 7 - date.getDayOfWeek();
for (int i = 1; i <= extraDays; i++) {
writeCalendarDay(page, null, date.plusDays(i), "other-month");
}
}
if (date.getDayOfMonth() == 31 || date.getDayOfWeek() == 7) {
page.writeEnd();
}
}
page.writeEnd();
}
private void writeCalendarDay(ToolPageContext page, List<Schedule> schedules, DateTime date, String extraClass) throws IOException {
page.writeStart("div", "class", "calendarDay" + (date.equals(new DateTime(null, page.getUserDateTimeZone()).toDateMidnight()) ? " calendarDay-today" : "") + (" day-of-week-" + date.getDayOfWeek()) + " " + extraClass);
page.writeStart("span", "class", "calendarDayOfWeek").writeHtml(date.dayOfWeek().getAsShortText()).writeEnd();
page.writeStart("span", "class", "calendarDayOfMonth").writeHtml(date.dayOfMonth().get()).writeEnd();
if (!ObjectUtils.isBlank(schedules)) {
long count = schedules.stream()
.mapToLong(schedule -> Query
.fromAll()
.where("com.psddev.cms.db.Draft/schedule = ?", schedule)
.count())
.sum();
if (count > 0) {
page.writeStart("a",
"class", "calendarEvents",
"href", page.cmsUrl("/scheduleEventsList", "date", date.toDate().getTime()),
"target", "scheduleEventsList");
page.writeHtml(count);
page.writeEnd();
}
}
page.writeEnd();
}
};
private final String resourceKey;
Mode(String resourceKey) {
this.resourceKey = resourceKey;
}
public abstract DateTime getBegin(DateTime date);
public abstract DateTime getEnd(DateTime date);
public abstract DateTime getPrevious(DateTime date);
public abstract DateTime getNext(DateTime date);
public abstract void display(ToolPageContext page, Map<DateTime, List<Schedule>> schedulesByDate) throws IOException;
@Override
public String toString() {
return resourceKey;
}
public static void displayAgendaView(ToolPageContext page, Map<DateTime, List<Schedule>> schedulesByDate) throws IOException {
page.writeStart("div", "class", "calendar calendar-week");
for (Map.Entry<DateTime, List<Schedule>> entry : schedulesByDate.entrySet()) {
DateTime date = entry.getKey();
List<Schedule> schedules = entry.getValue();
page.writeStart("div", "class", "calendarRow");
page.writeStart("div", "class", "calendarDay" + (date.equals(new DateTime(null, page.getUserDateTimeZone()).toDateMidnight()) ? " calendarDay-today" : ""));
page.writeStart("span", "class", "calendarDayOfWeek").writeHtml(date.dayOfWeek().getAsShortText()).writeEnd();
page.writeStart("span", "class", "calendarDayOfMonth").writeHtml(date.dayOfMonth().get()).writeEnd();
page.writeEnd();
page.writeStart("div", "class", "calendarCell").writeStart("table", "class", "links table-striped pageThumbnails").writeStart("tbody");
for (Schedule schedule : schedules) {
DateTime triggerDate = page.toUserDateTime(schedule.getTriggerDate());
List<Object> drafts = Query.fromAll().where("com.psddev.cms.db.Draft/schedule = ?", schedule).selectAll();
if (drafts.isEmpty()) {
continue;
}
boolean first = true;
for (Object d : drafts) {
if (!(d instanceof Draft)) {
continue;
}
Draft draft = (Draft) d;
Object draftObject = draft.recreate();
page.writeStart("tr", "data-preview-url", JspUtils.getAbsolutePath(page.getRequest(), "/_preview", "_cms.db.previewId", draft.getId()));
page.writeStart("td", "class", "time");
if (first) {
page.writeHtml(triggerDate.toString("hh:mm a"));
first = false;
}
page.writeEnd();
page.writeStart("td");
page.writeTypeLabel(draftObject);
page.writeEnd();
page.writeStart("td", "data-preview-anchor", "");
page.writeStart("a",
"href", page.objectUrl("/content/edit.jsp", draft),
"target", "_top");
page.writeObjectLabel(draft);
page.writeEnd();
page.writeEnd();
page.writeEnd();
}
}
page.writeEnd().writeEnd().writeEnd();
page.writeEnd();
}
page.writeEnd();
}
}
}