Package org.fluxtream.core.mvc.models

Source Code of org.fluxtream.core.mvc.models.CalendarModel

package org.fluxtream.core.mvc.models;

import java.util.TimeZone;
import org.fluxtream.core.Configuration;
import org.fluxtream.core.TimeUnit;
import org.fluxtream.core.services.MetadataService;
import org.fluxtream.core.utils.TimeUtils;
import org.fluxtream.core.utils.Utils;
import net.sf.json.JSONObject;
import org.joda.time.DateTimeConstants;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class CalendarModel {

    private static final DateTimeFormatter currentDateFormatter = DateTimeFormat
            .forPattern("EEE, MMM d, yyyy");
    private static final DateTimeFormatter shortDayFormatter = DateTimeFormat
            .forPattern("MMM d");
    private static final DateTimeFormatter currentMonthFormatter = DateTimeFormat
            .forPattern("MMMMMMMMMMMMM yyyy");
    private static final DateTimeFormatter currentYearFormatter = DateTimeFormat
            .forPattern("yyyy");

    private final long guestId;
    private final MetadataService metadataService;

    private TimeUnit timeUnit = TimeUnit.DAY;
    private LocalDate fromDate;

    public CalendarModel(final long guestId, final MetadataService metadataService) {
        this.guestId = guestId;
        this.metadataService = metadataService;
        setToToday();
    }

    public static CalendarModel fromState(final long guestId,
                                          final MetadataService metadataService,
                                          final String state) {
        CalendarModel calendarModel = new CalendarModel(guestId, metadataService);
        calendarModel.replaceState(state);
        return calendarModel;
    }

    public void setYear(final int year) {
        timeUnit = TimeUnit.YEAR;
        fromDate = new LocalDate(year, 1, 1);
    }

    public void setDate(final String formattedDate) {
        this.timeUnit = TimeUnit.DAY;
        // TODO: If we were using JodaTime 2.0 or later, we could simply write
        // fromDate = LocalDate.parse(formattedDate, jsDateFormatter)
        fromDate = TimeUtils.dateFormatter.parseDateTime(formattedDate).toLocalDate();
    }

    public void setWeek(final int year, final int week) {
        this.timeUnit = TimeUnit.WEEK;
        fromDate = TimeUtils.getBeginningOfWeek(year, week);
    }

    public int getWeekYear() {
        if (timeUnit != TimeUnit.WEEK)
            throw new IllegalStateException("Unexpected check for week year when not using week time unit");
        // Off by 1 because getBeginningOfWeek(year, week), and by extension
        // setWeek(year, week) goes back by 1 week
        return fromDate.plusWeeks(1).getWeekyear();
    }

    public int getWeek() {
        if (timeUnit != TimeUnit.WEEK)
            throw new IllegalStateException("Unexpected check for week when not using week time unit");
        // Off by 1 because getBeginningOfWeek(year, week), and by extension
        // setWeek(year, week) goes back by 1 week
        return fromDate.plusWeeks(1).getWeekOfWeekyear();
    }

    public void setMonth(final int year, final int month) {
        timeUnit = timeUnit.MONTH;
        fromDate = new LocalDate(year, 1, 1).withMonthOfYear(month);
    }

    /**
     * Returns one past the end date.
     *
     * This is similar to the behavior of Python's range function or Java's String.substring method,
     * and it has the desirable property that the number of milliseconds between midnight on
     * getToDate() and midnight on fromDate is equal to the number of milliseconds in a day times
     * the number of days in the range described by TimeUnit (assuming there is no time zone change,
     * leap second, or daylight savings time start/end in the middle).
     */
    private LocalDate getToDate() {
        switch (timeUnit) {
            case DAY:
                return fromDate.plusDays(1);
            case WEEK:
                return fromDate.plusWeeks(1);
            case MONTH:
                return fromDate.plusMonths(1);
            case YEAR:
                return fromDate.plusYears(1);
        }

        throw new UnsupportedOperationException("Unexpected TimeUnit value");
    }

    private TimeZone getTimeZone(final LocalDate date) {
        // The format used for dateString is the same format used in
        // MetadataServiceImpl's formatter
        final String dateString = date.toString("yyyy-MM-dd");
        return metadataService.getTimeZone(guestId, dateString);
    }

    private DateTimeZone getBrowserDateTimeZone() {
        // TODO: This doesn't match the implementation, even though it should be right
        final TimeZone tz = metadataService.getCurrentTimeZone(guestId);
        return DateTimeZone.forTimeZone(tz);
    }

    private long getMillis(final LocalDate date) {
        return date.toDateTimeAtStartOfDay(DateTimeZone.forTimeZone(getTimeZone(date)))
                .getMillis();
    }

    private long getMillisAtTrailingMidnight(final LocalDate date){
        return getMillis(date) + DateTimeConstants.MILLIS_PER_DAY;
    }

    public long getStart() {
        return getMillis(fromDate);
    }

    public long getEnd() {
        return getMillisAtTrailingMidnight(getToDate().minusDays(1));
    }

    public String toJSONString(final Configuration env) {
        // TODO: Include information in JSON that tells which calendar cells should
        // be lit up - don't want to use UTC timestamps to determine that info

        final JSONObject json = new JSONObject();
        json.put("timeUnit", timeUnit.toString());
        json.put("currentTimespanLabel", timespanLabel());
        json.put("isToday", isToday());
        json.put("state", getState());
        json.put("start", getStart());
        json.put("end", getEnd());
        return json.toString();
    }

    /**
     * Returns a hash that serves as a client-side caching key; it is
     * release-based
     */
    private String getTimeHash(final Configuration env, final String configKey) {
        final String toHash = env.get("release") + getStart() + getEnd() + configKey;
        return Utils.hash(toHash);
    }

    private String getState() {
        switch (timeUnit) {
            case DAY:
                return "date/" + TimeUtils.dateFormatter.print(fromDate);
            case WEEK:
                return String.format("week/%d/%d", getWeekYear(), getWeek());
            case MONTH:
                return String.format("month/%d/%d", fromDate.getYear(), fromDate.getMonthOfYear());
            case YEAR:
                return String.format("year/%d", fromDate.getYear());
        }

        throw new UnsupportedOperationException("Unexpected TimeUnit value");
    }

    public void setToToday() {
        timeUnit = TimeUnit.DAY;
        fromDate = new LocalDate(getBrowserDateTimeZone());
    }

    private boolean isToday() {
        final LocalDate today = new LocalDate(getBrowserDateTimeZone());
        return (timeUnit == TimeUnit.DAY)
               && (fromDate.getYear() == today.getYear())
               && (fromDate.getMonthOfYear() == today.getMonthOfYear())
               && (fromDate.getDayOfMonth() == today.getDayOfMonth());
    }

    private String timespanLabel() {
        switch (timeUnit) {
            case DAY:
                return currentDateFormatter.print(fromDate);
            case WEEK:
                final String from = shortDayFormatter.print(fromDate);
                final String to = shortDayFormatter.print(getToDate().minusDays(1));
                // TODO: Way to handle from and to in different years?
                final String year = currentYearFormatter.print(fromDate);
                final String toYear = currentYearFormatter.print(getToDate().minusDays(1));
                if (toYear.equals(year))
                    return from + " - " + to + " " + year;
                else
                    return String.format("%s %s - %s %s", from, year, to, toYear);
            case MONTH:
                return currentMonthFormatter.print(fromDate);
            case YEAR:
                return currentYearFormatter.print(fromDate);
        }

        throw new UnsupportedOperationException("Unexpected TimeUnit value");
    }

    public void incrementTimespan() {
        switch (timeUnit) {
            case DAY:
                fromDate = fromDate.plusDays(1);
                break;
            case WEEK:
                fromDate = fromDate.plusWeeks(1);
                break;
            case MONTH:
                fromDate = fromDate.plusMonths(1);
                break;
            case YEAR:
                fromDate = fromDate.plusYears(1);
                break;
        }
    }

    public void decrementTimespan() {
        switch (timeUnit) {
            case DAY:
                fromDate = fromDate.minusDays(1);
                break;
            case WEEK:
                fromDate = fromDate.minusWeeks(1);
                break;
            case MONTH:
                fromDate = fromDate.minusMonths(1);
                break;
            case YEAR:
                fromDate = fromDate.minusYears(1);
                break;
        }
    }

    public void replaceState(final String state) {
        final String[] stateParts = state.split("/");
        final TimeUnit timeUnit = TimeUnit.fromValue(stateParts[0].equals("date") ? "day" : stateParts[0]);

        final int year, month, week;

        switch (timeUnit) {
            case DAY:
                setDate(stateParts[1]);
                break;
            case WEEK:
                year = Integer.valueOf(stateParts[1]);
                week = Integer.valueOf(stateParts[2]);
                setWeek(year, week);
                break;
            case MONTH:
                year = Integer.valueOf(stateParts[1]);
                month = Integer.valueOf(stateParts[2]);
                setMonth(year, month);
                break;
            case YEAR:
                year = Integer.valueOf(stateParts[1]);
                setYear(year);
                break;
        }
    }

    public void setYearTimeUnit() {
        timeUnit = TimeUnit.YEAR;
        fromDate = new LocalDate(fromDate.getYear(), 1, 1);
    }

    public void setMonthTimeUnit() {
        timeUnit = TimeUnit.MONTH;
        fromDate = new LocalDate(fromDate.getYear(), fromDate.getMonthOfYear(), 1);
    }

    public void setDayTimeUnit() {
        timeUnit = TimeUnit.DAY;
        fromDate = new LocalDate(fromDate.getYear(), fromDate.getMonthOfYear(), fromDate.getDayOfMonth());
    }

    public void setWeekTimeUnit() {
        LocalDate origFromDate = fromDate;

        timeUnit = TimeUnit.WEEK;
        fromDate = new LocalDate(fromDate.getYear(), fromDate.getMonthOfYear(), fromDate.getDayOfMonth())
                .withDayOfWeek(TimeUtils.FIRST_DAY_OF_WEEK);
        // Unfortunately, the above code returns the following week instead of the containing week for
        // every day other than Sunday.  Check for this and decrement the week if needed.
        if(fromDate.isAfter(origFromDate)) {
            fromDate = fromDate.minusWeeks(1);
        }
    }
}
TOP

Related Classes of org.fluxtream.core.mvc.models.CalendarModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.