/*
* myLazyClock
*
* Copyright (C) 2014
*
* 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.myLazyClock.calendarApi;
import com.google.appengine.api.memcache.ErrorHandlers;
import com.google.appengine.api.memcache.Expiration;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.model.Component;
import net.fortuna.ical4j.model.ComponentList;
import net.fortuna.ical4j.model.component.VEvent;
import org.myLazyClock.calendarApi.exception.EventNotFoundException;
import org.myLazyClock.calendarApi.exception.ForbiddenCalendarException;
import java.io.*;
import java.net.URL;
import java.util.Map;
import java.util.logging.Level;
/**
* Created on 28/10/14.
*
* @author dralagen
*/
public class CalendarIcsStrategy implements CalendarStrategy {
public static final CalendarId ID = CalendarId.ICS;
//private HashMap<String, String> icsFiles;
@Override
public CalendarId getId() {
return ID;
}
@Override
public String getName() {
return "Calendar ICS";
}
public CalendarIcsStrategy(){
// this.icsFiles = new HashMap<String, String>();
}
/**
* Get ICS file on the given server
* @param edtUrl Path to get ics file in schedule
* @return ICS file as string
* @throws java.io.IOException
*
* @warning Not working with science schedule because of login but
* working well with staps
*/
private String getEdt(URL edtUrl) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(edtUrl.openStream()));
String line;
StringBuilder page = new StringBuilder("");
while ((line = reader.readLine()) != null) {
page.append(line);
page.append("\r\n");
}
reader.close();
return page.toString();
}
/**
* Construct calendar from given ICS file
* and return first event of given day
* @param params Need <strong>url</strong> who contain the url of ics file
*
* @param beginDate Lower bound date in which search event
* @param endDate Upper bound date in which search event
*
* @return First event of the day or null if no events
* @throws org.myLazyClock.calendarApi.exception.EventNotFoundException if no event found
*/
@Override
public CalendarEvent getFirstEvent (Map<String, String> params, java.util.Calendar beginDate, java.util.Calendar endDate) throws EventNotFoundException, ForbiddenCalendarException {
InputStream is;
// use Memcache
MemcacheService cache = MemcacheServiceFactory.getMemcacheService("calendarICS");
cache.setErrorHandler(ErrorHandlers.getConsistentLogAndContinue(Level.WARNING));
byte[] icsValue = (byte[]) cache.get(params.get("url"));
if (icsValue == null) {
String icsFile;
try {
icsFile = getEdt(new URL(params.get("url")));
if (icsFile == null) {
throw new ForbiddenCalendarException("Le fichier ICS n'a pas était trouvé");
}
cache.put(params.get("url"), icsFile.getBytes(), Expiration.byDeltaSeconds(7200));
is = new ByteArrayInputStream(icsFile.getBytes());
} catch (IOException e) {
throw new ForbiddenCalendarException(e);
}
} else {
is = new ByteArrayInputStream(icsValue);
}
// Construct calendar from ICS file
CalendarBuilder builder = new CalendarBuilder();
net.fortuna.ical4j.model.Calendar calendar;
try {
calendar = builder.build(is);
} catch (IOException | ParserException e) {
throw new ForbiddenCalendarException(e);
}
// Looking for first event of the day
ComponentList events = calendar.getComponents(Component.VEVENT);
VEvent nextEvent = null;
for(Object event: events){
VEvent currEvent = (VEvent)event;
java.util.Calendar calCurr = java.util.Calendar.getInstance();
calCurr.setTime(currEvent.getStartDate().getDate());
// Check if beginDate <= calCurr <= endDate
if(beginDate.compareTo(calCurr) <= 0 && endDate.compareTo(calCurr) >= 0) {
// Test if no event found
boolean currentIsBefore;
if(nextEvent == null){
currentIsBefore = calCurr.before(endDate);
}
else {
java.util.Calendar calNext = java.util.Calendar.getInstance();
calNext.setTime(nextEvent.getStartDate().getDate());
currentIsBefore = calCurr.before(calNext);
}
if(currentIsBefore){
nextEvent = currEvent;
}
}
}
if (nextEvent == null) {
throw new EventNotFoundException();
}
CalendarEvent eventReturn = new CalendarEvent();
eventReturn.setBeginDate(nextEvent.getStartDate().getDate());
eventReturn.setEndDate(nextEvent.getEndDate().getDate());
eventReturn.setName(nextEvent.getSummary().getValue());
return eventReturn;
}
}