package org.fluxtream.connectors.moves; import org.fluxtream.core.OutsideTimeBoundariesException; import org.fluxtream.core.TimeInterval; import org.fluxtream.core.TimeUnit; import org.fluxtream.core.connectors.vos.AbstractTimedFacetVO; import org.fluxtream.core.domain.GuestSettings; import org.fluxtream.core.mvc.models.DurationModel; import org.joda.time.DateTimeConstants; import org.joda.time.DateTimeZone; import org.joda.time.LocalDate; import org.joda.time.format.ISODateTimeFormat; import java.util.ArrayList; import java.util.List; import java.util.TimeZone; /** * User: candide * Date: 20/06/13 * Time: 17:37 */ public abstract class AbstractMovesFacetVO<T extends MovesFacet> extends AbstractTimedFacetVO<T> { public List<MovesActivityVO> activities = new ArrayList<MovesActivityVO>(); public boolean hasActivities = false; protected void fromFacetBase(final MovesFacet facet, final TimeInterval timeInterval, final GuestSettings settings) throws OutsideTimeBoundariesException { // Start by computing the timeZone currently in use for the date stored in the facet. // // It's unfortunate that we have two different time zone systems going on // and I don't offhand know how to do what I want only using one or the other, // but oh well... TimeZone timeZone = timeInterval.getTimeZone(facet.date); // Overwrite the default date with the date returned by Moves for this facet this.date = facet.date; // We need the real timezone; The ARBITRARY time intervals used by SimpleTimeInterval don't know it. // We could either create a more general TimerInterval which knows the timezone info, or do a hack like this: //if(timeInterval.getTimeUnit()!= TimeUnit.ARBITRARY) { // metadataService.getTimeZone(guestId, dateString); //} DateTimeZone dateTimeZone = DateTimeZone.forTimeZone(timeZone); // Compute the start and end of that date in milliseconds for comparing // and truncating start/end LocalDate facetLocalDate = LocalDate.parse(facet.date); long dateStart = facetLocalDate.toDateTimeAtStartOfDay(dateTimeZone).getMillis(); long dateEnd = dateStart + DateTimeConstants.MILLIS_PER_DAY; if(timeInterval.getTimeUnit()!= TimeUnit.ARBITRARY) { // This is a date-based query. In case this is an endcap facet, meaning it either // crosses the leading or trailing midnight of a day, // trim the part crossing beyond the leading/trailing midnight so it fits inside the date. // First check to see if this facet is entirely outside the time bounds of this date // If so, throw an exception so this facet isn't returned if(facet.end<dateStart || facet.start>dateEnd) { throw new OutsideTimeBoundariesException(); } // Check if crosses leading midnight if(facet.start<dateStart) { this.start = dateStart; } else { this.start = facet.start; } // Check if crosses trailing midnight if(facet.end>=dateEnd) { this.end = dateEnd-1; } else { this.end = facet.end; } } else { // This is not a date-based query. Don't do any trimming. this.start = facet.start; this.end = facet.end; } // Calculate duration from the potentially truncated times this.duration = new DurationModel((int)(this.end-this.start)/1000); // Also potentially prune the activities int skippedActivities=0; for (MovesActivity activity : facet.getActivities()) { // Only include activities which overlap at least part of this date // This comparison looks funny, but it is true if there is any overlap // between the time range of the activity and this date if (activity.manual) // always add manual activities activities.add(new MovesActivityVO(activity, timeZone, dateStart, dateEnd, settings, false)); else if(timeInterval.getTimeUnit()== TimeUnit.ARBITRARY || activity.start<dateEnd || activity.end>dateStart) { try { activities.add(new MovesActivityVO(activity, timeZone, dateStart, dateEnd, settings, timeInterval.getTimeUnit()!= TimeUnit.ARBITRARY)); } catch (OutsideTimeBoundariesException e) { // Don't negate the entire move facet if a particular activity falls outside // the date boundary, just ignore that individual activity skippedActivities++; } } } hasActivities = facet.getActivities().size()>0; this.eventStart = ISODateTimeFormat.dateTime().withZone(DateTimeZone.forTimeZone(timeInterval.getTimeZone(facet.start))).print(facet.start); this.eventEnd = ISODateTimeFormat.dateTime().withZone(DateTimeZone.forTimeZone(timeInterval.getTimeZone(facet.end))).print(facet.end); } }