package org.myLazyClock.services;
import org.myLazyClock.calendarApi.*;
import org.myLazyClock.calendarApi.exception.EventNotFoundException;
import org.myLazyClock.calendarApi.exception.ForbiddenCalendarException;
import org.myLazyClock.model.model.AlarmClock;
import org.myLazyClock.model.model.Calendar;
import org.myLazyClock.model.model.MyLazyClockUser;
import org.myLazyClock.model.repository.AlarmClockRepository;
import org.myLazyClock.model.repository.MyLazyClockUserRepository;
import org.myLazyClock.services.bean.AlarmClockEvent;
import org.myLazyClock.services.exception.NotFoundMyLazyClockException;
import org.myLazyClock.travelApi.TravelDuration;
import org.myLazyClock.travelApi.TravelFactory;
import org.myLazyClock.travelApi.TravelId;
import org.myLazyClock.travelApi.TravelStrategy;
import org.myLazyClock.travelApi.exception.TravelNotFoundException;
import java.util.*;
/**
* Created on 30/11/14.
*
* @author dralagen, jeremy
*/
public class ClockEventService {
private static ClockEventService service = null;
private ClockEventService() {}
public static synchronized ClockEventService getInstance() {
if (null == service) {
service = new ClockEventService();
}
return service;
}
/**
* List the first event per day, in next 7 days
* @param alarmClockId Id of the alarmClock
*
* @return List of event found
*/
public Collection<AlarmClockEvent> listEventForWeek(String alarmClockId) throws ForbiddenCalendarException, NotFoundMyLazyClockException {
AlarmClock alarmClock = AlarmClockRepository.getInstance().findOne(Long.decode(alarmClockId));
if (alarmClock == null) {
throw new NotFoundMyLazyClockException("Not found alarm clock " + alarmClockId);
}
MyLazyClockUser user = MyLazyClockUserRepository.getInstance().findOne(alarmClock.getUser());
String userToken = (user != null) ? user.getToken() : "";
Collection<Calendar> calendarList = alarmClock.getCalendars();
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Paris")); // For new Date()
java.util.Calendar currentCal = java.util.Calendar.getInstance();
currentCal.setTime(new Date());
// To search any event before this one
currentCal.set(java.util.Calendar.HOUR_OF_DAY, 0);
currentCal.set(java.util.Calendar.MINUTE, 0);
Collection<AlarmClockEvent> eventsInWeek = new ArrayList<>();
// Search first event for each day of week
for(int i = 0; i < 7; i++){
CalendarEvent eventInDay = null;
Calendar calOfEvent = null;
for(Calendar cal: calendarList){
try {
CalendarEvent eventOfDay = getFirstEventOfDay(cal, currentCal, userToken);
if (cal.isUseAlwaysDefaultLocation() || eventOfDay.getAddress() == null || eventOfDay.getAddress().equals("")) {
eventOfDay.setAddress(cal.getDefaultEventLocation());
}
if (eventInDay != null) {
if (eventOfDay.compareTo(eventInDay) < 0) {
eventInDay = eventOfDay;
calOfEvent = cal;
}
} else {
eventInDay = eventOfDay;
calOfEvent = cal;
}
} catch(EventNotFoundException ignore) { }
}
AlarmClockEvent alarmEvent;
if(eventInDay != null){
alarmEvent = calendarEventToAlarmClockEvent(eventInDay);
alarmEvent.setTravelMode(calOfEvent.getTravelMode());
if (alarmEvent.getBeginDate().compareTo(new Date()) > 0) {
try {
alarmEvent.setTravelDuration(
getDuration(alarmClock, alarmEvent)
);
} catch (TravelNotFoundException e) {
e.printStackTrace();
alarmEvent.setTravelDuration(0l);
}
eventsInWeek.add(alarmEvent);
}
}
// Next day
currentCal.add(java.util.Calendar.DATE, 1);
}
return eventsInWeek;
}
/**
* Return the first event in specified day on online schedule
*
* @param calendar Calendar to use with settings (strategy, url)
* @param date Day where to search event
* @return First event of day if exist, null otherwise
*/
public CalendarEvent getFirstEventOfDay(Calendar calendar, java.util.Calendar date, String token) throws EventNotFoundException, ForbiddenCalendarException {
java.util.Calendar endDate = (java.util.Calendar) date.clone();
endDate.set(java.util.Calendar.HOUR_OF_DAY, 23);
endDate.set(java.util.Calendar.MINUTE, 59);
CalendarId strategyId; // ICS_FILE
String calendarType = calendar.getCalendarType();
Map<String, String> params = new HashMap<>();
switch (calendarType) {
case "EDT":
strategyId = CalendarId.EDT;
params.put("groupId", calendar.getParam());
break;
case "GOOGLE_CALENDAR":
strategyId = CalendarId.GOOGLE_CALENDAR;
params.put("gCalId", calendar.getParam());
params.put("tokenRequest", token);
params.put("apiId", org.myLazyClock.services.ConstantAPI.API_ID);
params.put("apiSecret", org.myLazyClock.services.ConstantAPI.API_SECRET);
break;
default:
strategyId = CalendarId.ICS; // URL of ICS file
params.put("url", calendar.getParam());
break;
}
CalendarStrategy strategy = CalendarFactory.getInstance().get(strategyId);
return strategy.getFirstEvent(params, date, endDate);
}
/**
* Convert an {@link org.myLazyClock.calendarApi.CalendarEvent}
* to new {@link org.myLazyClock.services.bean.AlarmClockEvent}
*
* @param calendarEvent the calendarEvent to convert
* @return new AlarmClockEvent
*/
private AlarmClockEvent calendarEventToAlarmClockEvent(CalendarEvent calendarEvent) {
AlarmClockEvent event = new AlarmClockEvent();
event.setBeginDate(calendarEvent.getBeginDate());
event.setEndDate(calendarEvent.getEndDate());
event.setName(calendarEvent.getName());
event.setAddress(calendarEvent.getAddress());
return event;
}
/**
* Find the best module of {@link org.myLazyClock.travelApi.TravelStrategy} for my event for an alarmClock
*
* @param alarmClock The alarmClock of calendar who contain the start address
* @param event The event who contain the end address and limit end date
*
* @return The duration in second of the travel
* @throws TravelNotFoundException
*/
private Long getDuration (AlarmClock alarmClock, AlarmClockEvent event) throws TravelNotFoundException {
TravelStrategy strategy;
Map<String, String> params = new HashMap<>();
switch (event.getTravelMode()) {
case BICYCLING:
strategy = TravelFactory.getInstance().get(TravelId.GOOGLE_MAP);
params.put("mode", "bicycling");
break;
case TRANSIT:
strategy = TravelFactory.getInstance().get(TravelId.TAN);
params.put("mode", "transit");
break;
case WALKING:
strategy = TravelFactory.getInstance().get(TravelId.GOOGLE_MAP);
params.put("mode", "walking");
break;
case DRIVING:
default:
strategy = TravelFactory.getInstance().get(TravelId.GOOGLE_MAP);
}
TravelDuration travel = strategy.getDuration(alarmClock.getAddress(), event.getAddress(), event.getBeginDate(), params);
return travel.getTime();
}
}