package io.github.memfis19.sample.process;
import net.fortuna.ical4j.model.Component;
import net.fortuna.ical4j.model.ComponentFactoryImpl;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Period;
import net.fortuna.ical4j.model.PeriodList;
import org.joda.time.DateTimeZone;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import io.github.memfis19.cadar.data.entity.Event;
import io.github.memfis19.cadar.data.entity.property.EventProperties;
import io.github.memfis19.cadar.data.factory.EventFactory;
import io.github.memfis19.cadar.data.process.EventCalculator;
import io.github.memfis19.cadar.internal.utils.DateUtils;
/**
* Created by memfis on 3/26/15.
* Base event processing implementation of
*
* @see EventCalculator
*/
public class Ical4JEventCalculator implements EventCalculator {
private final static String TAG = "Ical4JEventCalculator";
private List<Event> eventsToProcess;
private EventFactory eventFactory;
private ComponentFactoryImpl componentFactory;
public Ical4JEventCalculator() {
this.componentFactory = ComponentFactoryImpl.getInstance();
}
public Ical4JEventCalculator(List<Event> eventsToProcess) {
this.eventsToProcess = eventsToProcess;
this.componentFactory = ComponentFactoryImpl.getInstance();
}
@Override
public void setEventFactory(EventFactory eventFactory) {
this.eventFactory = eventFactory;
}
@Override
public void setEventsToProcess(List<Event> eventsToProcess) {
this.eventsToProcess = eventsToProcess;
}
@Override
public List<Event> getEventsForDate(Date date) {
return getEventsForPeriod(date, null);
}
@Override
public List<Event> getEventsForPeriod(Date startDate, Date endDate) {
if (eventsToProcess == null || eventsToProcess.isEmpty() || startDate == null)
return new ArrayList<>();
List<Event> eventsToProcess = new ArrayList<>(this.eventsToProcess);
List<Event> resultEventsList = new ArrayList<>();
Date specifiedStartDate = DateUtils.setTimeToMidnight(startDate);
Date specifiedEndDate = endDate == null ? DateUtils.setTimeToEndOfTheDay(startDate) : DateUtils.setTimeToEndOfTheDay(endDate);
DateTime startDateTime = new DateTime(specifiedStartDate);
DateTime endDateTime = new DateTime(specifiedEndDate);
Period period = new Period(startDateTime, endDateTime);
for (Event event : eventsToProcess) {
// Skip event without start date
if (event.getEventStartDate() == null) continue;
Date eventStartDate = DateUtils.setTimeToMidnight(event.getEventStartDate());
// Skip any event, with start date greater then end of specified period date.
if (specifiedEndDate.getTime() < eventStartDate.getTime())
continue;
// Skip any event, with end date less then start of specified period date.
if (event.getEventEndDate() != null
&& (specifiedStartDate.getTime() > event.getEventEndDate().getTime()))
continue;
// Skip not repeatable event, with empty end date and start date less then start of
// specified period date.
if (EventProperties.NONE == event.getEventRepeatPeriod() && event.getEventEndDate() == null
&& (specifiedStartDate.getTime() > eventStartDate.getTime()))
continue;
if (EventProperties.NONE == event.getEventRepeatPeriod() && event.getEventEndDate() == null) {
event.setEventEndDate(DateUtils.setTimeToEndOfTheDay(event.getEventStartDate()));
}
EventComponentCreator eventComponentCreator = new EventComponentCreator(event);
Component component = eventComponentCreator.createEventComponent(componentFactory);
PeriodList periodList = component.calculateRecurrenceSet(period);
resultEventsList.addAll(getEventsForPeriodList(event, periodList));
}
return resultEventsList;
}
@Override
public List<Date> getEventsDates(List<Event> events) {
if (events == null) return null;
Set<Date> dateSet = new HashSet<>();
for (Event event : events) {
dateSet.add(DateUtils.setTimeToMidnight(event.getEventStartDate()));
}
return new ArrayList<>(dateSet);
}
private List<Event> getEventsForPeriodList(Event recurrentEvent, PeriodList periodListForRecurrentEvent) {
if (periodListForRecurrentEvent == null) return null;
List<Event> recurrentEventList = new ArrayList<>(periodListForRecurrentEvent.size());
for (Period period : periodListForRecurrentEvent) {
org.joda.time.DateTime dateTime = new org.joda.time.DateTime(new Date(period.getStart().getTime()), DateTimeZone.UTC);
Event event = eventFactory.createEventCopy(recurrentEvent);
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
long time = event.getEventStartDate().getTime() % MILLIS_PER_DAY;
event.setEventStartDate(new Date(dateTime.toDate().getTime() + time));
recurrentEventList.add(event);
}
return recurrentEventList;
}
}