/* AWE - Amanzi Wireless Explorer
* http://awe.amanzi.org
* (C) 2008-2009, AmanziTel AB
*
* This library is provided under the terms of the Eclipse Public License
* as described at http://www.eclipse.org/legal/epl-v10.html. Any use,
* reproduction or distribution of the library constitutes recipient's
* acceptance of this agreement.
*
* This library is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.amanzi.neo.core.period;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import org.amanzi.neo.core.internal.Messages;
import org.apache.commons.lang3.ArrayUtils;
/**
* <p>
* Time periods
* </p>
*
* @author Vladislav_Kondratenko
* @since 1.0.0
*/
public enum Period {
// 1 hour
HOURLY(Messages.ctrHourly, null, -1) {
@Override
public Long addPeriod(final Long time) {
return addOnePeriod(time, Calendar.HOUR_OF_DAY);
}
@Override
public Long getStartTime(final Long time) {
final GregorianCalendar cl = new GregorianCalendar();
cl.setTimeInMillis(time);
cl.set(Calendar.MINUTE, 0);
cl.set(Calendar.SECOND, 0);
cl.set(Calendar.MILLISECOND, 0);
return cl.getTimeInMillis();
}
},
// 1 day
DAILY(Messages.ctrDaily, HOURLY, Calendar.HOUR_OF_DAY) {
@Override
public Long addPeriod(final Long time) {
return addOnePeriod(time, Calendar.DAY_OF_MONTH);
}
@Override
public Long getStartTime(final Long time) {
final GregorianCalendar cl = new GregorianCalendar();
cl.setTimeInMillis(time);
cl.set(Calendar.HOUR_OF_DAY, 0);
cl.set(Calendar.MINUTE, 0);
cl.set(Calendar.SECOND, 0);
cl.set(Calendar.MILLISECOND, 0);
return cl.getTimeInMillis();
}
},
// 1 week
WEEKLY(Messages.ctrWeekly, DAILY, Calendar.DAY_OF_YEAR) {
@Override
public Long addPeriod(final Long time) {
return addOnePeriod(time, Calendar.WEEK_OF_YEAR);
}
@Override
public Long getStartTime(final Long time) {
final GregorianCalendar cl = new GregorianCalendar();
cl.setTimeInMillis(time);
cl.set(Calendar.DAY_OF_WEEK, cl.getFirstDayOfWeek());
cl.set(Calendar.HOUR_OF_DAY, 0);
cl.set(Calendar.MINUTE, 0);
cl.set(Calendar.SECOND, 0);
cl.set(Calendar.MILLISECOND, 0);
return cl.getTimeInMillis();
}
},
// 1 month
MONTHLY(Messages.ctrMonthly, WEEKLY, Calendar.WEEK_OF_YEAR) {
@Override
public Long addPeriod(final Long time) {
return addOnePeriod(time, Calendar.MONTH);
}
@Override
public Long getStartTime(final Long time) {
final GregorianCalendar cl = new GregorianCalendar();
cl.setTimeInMillis(time);
final int dayInMonth = cl.get(Calendar.DAY_OF_MONTH);
cl.add(Calendar.DAY_OF_YEAR, 1 - dayInMonth);
cl.set(Calendar.HOUR_OF_DAY, 0);
cl.set(Calendar.MINUTE, 0);
cl.set(Calendar.SECOND, 0);
cl.set(Calendar.MILLISECOND, 0);
return cl.getTimeInMillis();
}
},
YEARLY(Messages.ctrYearly, MONTHLY, Calendar.MONTH) {
@Override
public Long addPeriod(final Long time) {
return addOnePeriod(time, Calendar.YEAR);
}
@Override
public Long getStartTime(final Long time) {
final GregorianCalendar cl = new GregorianCalendar();
cl.setTimeInMillis(time);
cl.set(Calendar.MONTH, Calendar.JANUARY);
cl.set(Calendar.DAY_OF_MONTH, 1);
cl.set(Calendar.HOUR_OF_DAY, 0);
cl.set(Calendar.MINUTE, 0);
cl.set(Calendar.SECOND, 0);
cl.set(Calendar.MILLISECOND, 0);
return cl.getTimeInMillis();
}
},
ALL(Messages.ctrTotal, YEARLY, Calendar.YEAR) {
@Override
public Long addPeriod(final Long time) {
return Long.MAX_VALUE;
}
@Override
public Long getStartTime(final Long time) {
return time;
}
@Override
public Long getEndTime(final Long time) {
return time;
}
};
private final String id;
private static final Period[] SORTED_PERIODS;
static {
SORTED_PERIODS = Period.values();
ArrayUtils.reverse(SORTED_PERIODS);
}
private Period underlyingPeriod;
private int underlyingPeriodCalendarField;
/**
* Constructor.
*
* @param id String
* @param underlyingPeriod Period
*/
Period(final String id, final Period underlyingPeriod, final int underlyingPeriodCalendarField) {
this.id = id;
this.underlyingPeriod = underlyingPeriod;
this.underlyingPeriodCalendarField = underlyingPeriodCalendarField;
}
/**
* @return Returns the id.
*/
public String getId() {
return id;
}
/**
* @return Returns the underlyingPeriod.
*/
public Period getUnderlyingPeriod() {
return underlyingPeriod;
}
/**
* Finds enum by id
*
* @param periodId type id
* @return enum or null
*/
public static Period findById(final String periodId) {
if (periodId == null) {
return null;
}
for (final Period period : Period.values()) {
if (period.getId().equals(periodId)) {
return period;
}
}
return null;
}
/**
* gets first time of period
*
* @param time - timestamp
*/
public abstract Long getStartTime(Long time);
/**
* gets time+period Length
*
* @param time- timestamp
*/
public abstract Long addPeriod(Long time);
/**
* get last ms in current period
*
* @param time - timestamp
* @return last ms
*/
public Long getEndTime(final Long time) {
return addPeriod(getStartTime(time));
}
public static Period getHighestPeriod(final long minTime, final long maxTime) {
final Calendar minDate = Calendar.getInstance();
minDate.setTimeInMillis(minTime);
final Calendar maxDate = Calendar.getInstance();
maxDate.setTimeInMillis(maxTime);
// starting with highest period
Period highestPeriod;
Period result = null;
for (int i = 0; (i < SORTED_PERIODS.length) && (result == null); i++) {
highestPeriod = SORTED_PERIODS[i];
if (highestPeriod == Period.HOURLY) {
result = highestPeriod;
} else {
final int minDatePeriod = minDate.get(highestPeriod.getUnderlyingPeriodCalendarField());
final int maxDatePeriod = maxDate.get(highestPeriod.getUnderlyingPeriodCalendarField());
if (minDatePeriod < maxDatePeriod) {
result = highestPeriod;
}
}
}
return result;
}
/**
* add one period
*
* @param time - timestamp
* @param period - period @see Calendar
* @return timestamp+ 1 period
*/
private static Long addOnePeriod(final Long time, final int period) {
final GregorianCalendar cl = new GregorianCalendar();
cl.setTimeInMillis(time);
cl.add(period, 1);
return cl.getTimeInMillis();
}
/**
* @return Returns the underlyingPeriodCalendarField.
*/
public int getUnderlyingPeriodCalendarField() {
return underlyingPeriodCalendarField;
}
/**
* get available periods for current time range
*
* @param startTime
* @param endTime
* @return
*/
public static List<Period> getAvailablePeriods(final long startTime, final long endTime) {
// TODO: LN: 09.08.2012, remove magic numbers
// TODO: LN: 09.08.2012, algorithm of detecting available periods is in correct since it
// depends on numbers (at least in month we can have more or less than 30 days)
final List<Period> periods = new ArrayList<Period>();
long time = (endTime - startTime) / (1000 * 60);
if ((time = time / 60) >= 0) {
periods.add(HOURLY);
if ((time = time / 24) >= 1) {
periods.add(DAILY);
if ((time / 7) >= 1) {
periods.add(WEEKLY);
}
if ((time = time / 30) >= 1) {
periods.add(MONTHLY);
}
}
}
return periods;
}
/**
* @return Returns the sortedPeriods.
*/
public static Period[] getSortedPeriods() {
return SORTED_PERIODS;
}
}