/**************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved. *
* http://esper.codehaus.org *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
**************************************************************************************/
package com.espertech.esper.type;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;
/**
* Hold parameters for timer:at.
*/
public class CronParameter implements NumberSetParameter {
private CronOperatorEnum operator;
private Calendar calendar;
private Integer day, month;
private static int FIRST_DAY_OF_WEEK = Calendar.SUNDAY;
private static final long serialVersionUID = -4006350378033980878L;
/**
* Ctor.
* @param operator is the operator as text
* @param day is the day text
* @param engineTime is the current engine time
*/
public CronParameter(CronOperatorEnum operator, Integer day, long engineTime) {
this.operator = operator;
this.day = day;
calendar = Calendar.getInstance();
calendar.setTimeInMillis(engineTime);
calendar.setFirstDayOfWeek(FIRST_DAY_OF_WEEK);
}
/**
* Sets the month value.
* @param month to set
*/
public void setMonth(int month) {
this.month = month - 1;
}
public boolean isWildcard(int min, int max) {
return false;
}
public boolean containsPoint(int point) {
throw new UnsupportedOperationException();
}
public String formatted() {
return operator + "(day " + day + " month " + month + ")";
}
public Set<Integer> getValuesInRange(int min, int max) {
Set<Integer> values = new HashSet<Integer>();
if (((min != 0) && (min != 1)) || ((max != 6) && (max != 31))) {
throw new IllegalArgumentException("Invalid usage for timer:at");
}
if (operator == CronOperatorEnum.LASTDAY)
{
// If max=6, determine last day of Week (In US Saturday=7)
if ((min==0) && (max == 6)) {
if (day == null) {
values.add(determineLastDayOfWeek());
} else {
values.add(determineLastDayOfWeekInMonth());
}
} else if ((min==1) && (max == 31)) {
// "Last day of month"
// or "the last xxx day of the month"
if (day == null) {
values.add(determineLastDayOfMonth());
} else {
values.add(determineLastDayOfWeekInMonth());
}
} else {
throw new IllegalArgumentException("Invalid value for last operator");
}
}
else if (operator == CronOperatorEnum.LASTWEEKDAY)
{
values.add(determineLastWeekDayOfMonth());
}
else if (operator == CronOperatorEnum.WEEKDAY)
{
values.add(determineLastWeekDayOfMonth());
}
else
{
throw new IllegalArgumentException("Invalid special operator for observer");
}
return values;
}
private int determineLastDayOfMonth() {
setTime();
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
return calendar.get(Calendar.DAY_OF_MONTH);
}
private int determineLastDayOfWeekInMonth() {
if (day == null) {
return determineLastDayOfMonth();
}
if (day<0 || day>7) {
throw new IllegalArgumentException("Last xx day of the month has to be a day of week (0-7)");
}
int dayOfWeek = getDayOfWeek();
setTime();
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
int dayDiff = calendar.get(Calendar.DAY_OF_WEEK) - dayOfWeek;
if (dayDiff > 0) {
calendar.add(Calendar.DAY_OF_WEEK, -dayDiff);
} else if (dayDiff < 0) {
calendar.add(Calendar.DAY_OF_WEEK, -7 - dayDiff);
}
return calendar.get(Calendar.DAY_OF_MONTH);
}
private int determineLastDayOfWeek() {
setTime();
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
return calendar.get(Calendar.DAY_OF_WEEK) - 1;
}
private int getDayOfWeek() {
setTime();
if (day == null) {
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
} else {
calendar.set(Calendar.DAY_OF_WEEK, day + 1);
}
return calendar.get(Calendar.DAY_OF_WEEK);
}
private int determineLastWeekDayOfMonth() {
int computeDay = (day == null)? determineLastDayOfMonth(): day;
setTime();
if (!checkDayValidInMonth(computeDay, calendar.get(Calendar.MONTH), calendar.get(Calendar.YEAR))) {
throw new IllegalArgumentException("Invalid day for " + calendar.get(Calendar.MONTH));
}
calendar.set(Calendar.DAY_OF_MONTH, computeDay);
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
if ((dayOfWeek >=Calendar.MONDAY) && (dayOfWeek<=Calendar.FRIDAY)) {
return computeDay;
}
if (dayOfWeek == Calendar.SATURDAY) {
if (computeDay == 1) {
calendar.add(Calendar.DAY_OF_MONTH, +2);
} else {
calendar.add(Calendar.DAY_OF_MONTH, -1);
}
}
if (dayOfWeek == Calendar.SUNDAY) {
if ((computeDay == 28) || (computeDay==29) || (computeDay==30) || (computeDay==31)) {
calendar.add(Calendar.DAY_OF_MONTH, -2);
} else {
calendar.add(Calendar.DAY_OF_MONTH, +2);
}
}
return calendar.get(Calendar.DAY_OF_MONTH);
}
private static boolean checkDayValidInMonth(int day, int month, int year)
{
try
{
Calendar calendar = Calendar.getInstance();
calendar.setLenient(false);
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
calendar.getTime();
}
catch (IllegalArgumentException e)
{
return false;
}
return true;
}
private void setTime() {
calendar.set(Calendar.DAY_OF_MONTH, 1);
if (month != null) {
calendar.set(Calendar.MONTH, month);
}
}
}