me.vertretungsplan.additionalinfo.BaseIcalParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parser Show documentation
Show all versions of parser Show documentation
Java library for parsing schools' substitution schedules. Supports multiple different systems mainly used in the German-speaking countries.
/*
* substitution-schedule-parser - Java library for parsing schools' substitution schedules
* Copyright (c) 2017 Johan v. Forstner
*
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package me.vertretungsplan.additionalinfo;
import biweekly.Biweekly;
import biweekly.ICalendar;
import biweekly.component.VEvent;
import biweekly.io.TimezoneAssignment;
import biweekly.io.TimezoneInfo;
import biweekly.util.com.google.ical.compat.javautil.DateIterator;
import me.vertretungsplan.objects.AdditionalInfo;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;
public abstract class BaseIcalParser extends BaseAdditionalInfoParser {
protected abstract String getIcalUrl();
protected String getTitle() {
return "Termine";
}
protected int getMaxItemsCount() {
return 4;
}
@Override
public AdditionalInfo getAdditionalInfo() throws IOException {
AdditionalInfo info = new AdditionalInfo();
info.setTitle(getTitle());
String rawdata = httpGet(getIcalUrl(), "UTF-8");
if (shouldStripTimezoneInfo()) {
Pattern pattern = Pattern.compile("BEGIN:VTIMEZONE.*END:VTIMEZONE", Pattern.DOTALL);
rawdata = pattern.matcher(rawdata).replaceAll("");
}
DateTime now = DateTime.now().withTimeAtStartOfDay();
List icals = Biweekly.parse(rawdata).all();
List events = new ArrayList<>();
for (ICalendar ical : icals) {
for (VEvent event : ical.getEvents()) {
Event item = new Event();
TimeZone timezoneStart = getTimeZoneStart(ical, event);
if (event.getDescription() != null) {
item.description = event.getDescription().getValue();
}
if (event.getSummary() != null) {
item.summary = event.getSummary().getValue();
}
if (event.getDateStart() != null) {
item.startDate = new DateTime(event.getDateStart().getValue());
item.startHasTime = event.getDateStart().getValue().hasTime();
} else {
continue;
}
if (event.getDateEnd() != null) {
item.endDate = new DateTime(event.getDateEnd().getValue());
item.endHasTime = event.getDateEnd().getValue().hasTime();
}
if (event.getLocation() != null) {
item.location = event.getLocation().getValue();
}
if (event.getUrl() != null) {
item.url = event.getUrl().getValue();
}
if (event.getRecurrenceRule() == null
&& item.endDate != null
&& (item.endDate.compareTo(now) < 0)) {
continue;
} else if (event.getRecurrenceRule() == null
&& (item.startDate.compareTo(now) < 0)) {
continue;
}
if (event.getRecurrenceRule() != null
&& event.getRecurrenceRule().getValue().getUntil() != null
&& event.getRecurrenceRule().getValue().getUntil()
.compareTo(now.toDate()) < 0) {
continue;
}
if (event.getRecurrenceRule() != null) {
Duration duration = null;
if (event.getDateEnd() != null) {
duration = new Duration(new DateTime(event.getDateStart().getValue()), new DateTime(event
.getDateEnd().getValue()));
}
DateIterator iterator = event.getDateIterator(timezoneStart);
while (iterator.hasNext()) {
Date date = iterator.next();
Event reccitem = item.clone();
reccitem.startDate = new DateTime(date);
reccitem.endDate = reccitem.startDate.plus(duration);
if (item.startDate.equals(reccitem.startDate)) continue;
if (item.endDate != null
&& (item.endDate.compareTo(now) < 0)) {
continue;
} else if (item.endDate == null
&& (item.startDate.compareTo(now) < 0)) {
continue;
}
events.add(reccitem);
}
}
if (item.endDate != null
&& (item.endDate.compareTo(now) < 0)) {
continue;
} else if (item.endDate == null
&& (item.startDate.compareTo(now) < 0)) {
continue;
}
events.add(item);
}
}
Collections.sort(events, new Comparator() {
@Override public int compare(Event o1, Event o2) {
return o1.startDate.compareTo(o2.startDate);
}
});
StringBuilder content = new StringBuilder();
int count = 0;
DateTimeFormatter fmtDt = DateTimeFormat.shortDateTime().withLocale(Locale.GERMANY);
DateTimeFormatter fmtD = DateTimeFormat.shortDate().withLocale(Locale.GERMANY);
DateTimeFormatter fmtT = DateTimeFormat.shortTime().withLocale(Locale.GERMANY);
for (Event item : events) {
if (count >= getMaxItemsCount()) {
break;
} else if (count != 0) {
content.append("
\n\n");
}
DateTime start = item.startDate;
if (item.endDate != null) {
DateTime end = item.endDate;
if (!item.endHasTime) {
end = end.minusDays(1);
}
content.append((item.startHasTime ? fmtDt : fmtD).print(start));
if (!end.equals(start)) {
content.append(" - ");
if (item.startHasTime && item.endHasTime && end.toLocalDate().equals(start.toLocalDate())) {
content.append(fmtT.print(end));
} else {
content.append((item.endHasTime ? fmtDt : fmtD).print(end));
}
}
} else {
content.append(fmtDt.print(start));
}
content.append("
\n");
content.append("");
content.append(item.summary);
content.append("");
count++;
}
info.setText(content.toString());
return info;
}
protected boolean shouldStripTimezoneInfo() {
return false;
}
private TimeZone getTimeZoneStart(ICalendar ical, VEvent event) {
if (event.getDateStart() == null) {
return null;
}
TimezoneInfo tzinfo = ical.getTimezoneInfo();
TimeZone timezone;
if (tzinfo.isFloating(event.getDateStart())) {
timezone = TimeZone.getDefault();
} else {
TimezoneAssignment dtstartTimezone = tzinfo.getTimezone(event.getDateStart());
timezone = (dtstartTimezone == null) ? TimeZone.getTimeZone("UTC") : dtstartTimezone.getTimeZone();
}
return timezone;
}
private class Event implements Cloneable {
public String summary;
public String description;
public String location;
public DateTime startDate;
public DateTime endDate;
public String url;
public boolean startHasTime;
public boolean endHasTime;
@Override
protected Event clone() {
Event clone = new Event();
clone.summary = this.summary;
clone.description = this.description;
clone.location = this.location;
clone.startDate = this.startDate;
clone.endDate = this.endDate;
clone.url = this.url;
return clone;
}
}
}