FileDocCategorySizeDatePackage
RepeatRule.javaAPI DocphoneME MR2 API (J2ME)27067Wed May 02 18:00:28 BST 2007javax.microedition.pim

RepeatRule.java

/*
 *   
 *
 * Portions Copyright  2000-2007 Sun Microsystems, Inc. All Rights
 * Reserved.  Use is subject to license terms.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */
 
/*
 * Copyright (C) 2002-2003 PalmSource, Inc.  All Rights Reserved.
 */

package javax.microedition.pim;

import com.sun.kvem.midp.pim.PIMHandler;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;

/**
 * This class is defined by the JSR-75 specification
 * <em>PDA Optional Packages for the J2ME™ Platform</em>
 */
// JAVADOC COMMENT ELIDED
public class RepeatRule {
    /** Fields in the rule. */
    private Hashtable fields = new Hashtable();
    /** Exceptions caused by the rule. */
    private Vector exceptions = new Vector();
    // JAVADOC COMMENT ELIDED
    public RepeatRule() { }
    // JAVADOC COMMENT ELIDED
    public static final int FREQUENCY = 0;
    // JAVADOC COMMENT ELIDED
    public static final int DAY_IN_MONTH = 1;
    // JAVADOC COMMENT ELIDED
    public static final int DAY_IN_WEEK = 2;
    // JAVADOC COMMENT ELIDED
    public static final int DAY_IN_YEAR = 4;
    // JAVADOC COMMENT ELIDED
    public static final int MONTH_IN_YEAR = 8;
    // JAVADOC COMMENT ELIDED
    public static final int WEEK_IN_MONTH = 16;
    // JAVADOC COMMENT ELIDED
    public static final int COUNT = 32;
    // JAVADOC COMMENT ELIDED
    public static final int END = 64;
    // JAVADOC COMMENT ELIDED
    public static final int INTERVAL = 128;
    // JAVADOC COMMENT ELIDED
    public static final int DAILY = 0x10;
    // JAVADOC COMMENT ELIDED
    public static final int WEEKLY = 0x11;
    // JAVADOC COMMENT ELIDED
    public static final int MONTHLY = 0x12;
    // JAVADOC COMMENT ELIDED
    public static final int YEARLY = 0x13;
    // JAVADOC COMMENT ELIDED
    public static final int FIRST = 0x1;
    // JAVADOC COMMENT ELIDED
    public static final int SECOND = 0x2;
    // JAVADOC COMMENT ELIDED
    public static final int THIRD = 0x4;
    // JAVADOC COMMENT ELIDED
    public static final int FOURTH = 0x8;
    // JAVADOC COMMENT ELIDED
    public static final int FIFTH = 0x10;
    // JAVADOC COMMENT ELIDED
    public static final int LAST = 0x20;
    // JAVADOC COMMENT ELIDED
    public static final int SECONDLAST = 0x40;
    // JAVADOC COMMENT ELIDED
    public static final int THIRDLAST = 0x80;
    // JAVADOC COMMENT ELIDED
    public static final int FOURTHLAST = 0x100;
    // JAVADOC COMMENT ELIDED
    public static final int FIFTHLAST = 0x200;
    // JAVADOC COMMENT ELIDED
    public static final int SATURDAY = 0x400;
    // JAVADOC COMMENT ELIDED
    public static final int FRIDAY = 0x800;
    // JAVADOC COMMENT ELIDED
    public static final int THURSDAY = 0x1000;
    // JAVADOC COMMENT ELIDED
    public static final int WEDNESDAY = 0x2000;
    // JAVADOC COMMENT ELIDED
    public static final int TUESDAY = 0x4000;
    // JAVADOC COMMENT ELIDED
    public static final int MONDAY = 0x8000;
    // JAVADOC COMMENT ELIDED
    public static final int SUNDAY = 0x10000;
    // JAVADOC COMMENT ELIDED
    public static final int JANUARY = 0x20000;
    // JAVADOC COMMENT ELIDED
    public static final int FEBRUARY = 0x40000;
    // JAVADOC COMMENT ELIDED
    public static final int MARCH = 0x80000;
    // JAVADOC COMMENT ELIDED
    public static final int APRIL = 0x100000;
    // JAVADOC COMMENT ELIDED
    public static final int MAY = 0x200000;
    // JAVADOC COMMENT ELIDED
    public static final int JUNE = 0x400000;
    // JAVADOC COMMENT ELIDED
    public static final int JULY = 0x800000;
    // JAVADOC COMMENT ELIDED
    public static final int AUGUST = 0x1000000;
    // JAVADOC COMMENT ELIDED
    public static final int SEPTEMBER = 0x2000000;
    // JAVADOC COMMENT ELIDED
    public static final int OCTOBER = 0x4000000;
    // JAVADOC COMMENT ELIDED
    public static final int NOVEMBER = 0x8000000;
    // JAVADOC COMMENT ELIDED
    public static final int DECEMBER = 0x10000000;

    /** Months of the year. */
    private static final int[] MONTHS = {
        JANUARY, FEBRUARY, MARCH, APRIL,
        MAY, JUNE, JULY, AUGUST,
        SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER
    };
    /** DAY_INCREMENT = 86400000l. */
    private static final long DAY_INCREMENT = 86400000l;
    /** DAY_IN_WEEK_MASK = 0x1fc00l. */
    private static final long DAY_IN_WEEK_MASK = 0x1fc00l;
    /** WEEK_IN_MONTH_MASK = 0x3ffl. */
    private static final long WEEK_IN_MONTH_MASK = 0x3ffl;
    /** MONTH_IN_YEAR_MASK = 0x1ffe0000. */
    private static final long MONTH_IN_YEAR_MASK = 0x1ffe0000;
    /** Days of the week. */
    private static final int[] DAYS = {
        SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
    };
    /**  DAY_LENGTH = 86400000L. */
    private static final long DAY_LENGTH = 86400000L;

    // JAVADOC COMMENT ELIDED
    public Enumeration dates(long startDate, long subsetBeginning,
			     long subsetEnding) {
        if (subsetBeginning > subsetEnding) {
            throw new IllegalArgumentException("Bad range: "
                + subsetBeginning + "("
                + PIMHandler.getInstance().composeDateTime(subsetBeginning)
                + ") to " + subsetEnding + "("
                + PIMHandler.getInstance().composeDateTime(subsetEnding));
        }
        Calendar calendar = Calendar.getInstance();
        Date dateObj = new Date(startDate);
        calendar.setTime(dateObj);
        Vector dates = new Vector();
        long date = startDate;
        Integer frequency = (Integer) getField(FREQUENCY, null);
        int interval = ((Integer) getField(INTERVAL,
					   new Integer(1))).intValue();
        int count = ((Integer) 
		     getField(COUNT, 
			      new Integer(Integer.MAX_VALUE))).intValue();
        long end = ((Long) getField(END, new Long(Long.MAX_VALUE))).longValue();
        Integer dayInWeek = (Integer) getField(DAY_IN_WEEK, null);
        Integer dayInMonth = (Integer) getField(DAY_IN_MONTH, null);
        Integer dayInYear = (Integer) getField(DAY_IN_YEAR, null);
        Integer weekInMonth = (Integer) getField(WEEK_IN_MONTH, null);
        Integer monthInYear = (Integer) getField(MONTH_IN_YEAR, null);
        // set defaults, based on starting date
        if (dayInMonth == null && weekInMonth == null) {
            dayInMonth = new Integer(calendar.get(Calendar.DAY_OF_MONTH));
        }
        if (dayInWeek == null) {
            switch (calendar.get(Calendar.DAY_OF_WEEK)) {
                case Calendar.SUNDAY:
		    dayInWeek = new Integer(SUNDAY);
		    break;
                case Calendar.MONDAY:
		    dayInWeek = new Integer(MONDAY);
		    break;
                case Calendar.TUESDAY:
		    dayInWeek = new Integer(TUESDAY);
		    break;
                case Calendar.WEDNESDAY:
		    dayInWeek = new Integer(WEDNESDAY);
		    break;
                case Calendar.THURSDAY:
		    dayInWeek = new Integer(THURSDAY);
		    break;
                case Calendar.FRIDAY: 
		    dayInWeek = new Integer(FRIDAY);
		    break;
                case Calendar.SATURDAY: 
		    dayInWeek = new Integer(SATURDAY);
		    break;
            }
        }
        long rangeStart = Math.max(subsetBeginning, startDate);
        long rangeEnd = Math.min(subsetEnding, end);
        for (int i = 0; date <= subsetEnding && date <= end && i < count; i++) {
            if (frequency == null) {
                // no repetitions
                storeDate(dates, startDate, rangeStart, rangeEnd);
                break;
            }
            switch (frequency.intValue()) {
                case DAILY:
                    storeDate(dates, date, rangeStart, rangeEnd);
                    date += DAY_INCREMENT * interval;
                    dateObj.setTime(date);
                    calendar.setTime(dateObj);
                    break;
                case WEEKLY:
                    if (dayInWeek == null) {
                        storeDate(dates, date, rangeStart, rangeEnd);
                    } else {
                        // shift date to the beginning of the week
                        date -= DAY_INCREMENT * 
                            (calendar.get(Calendar.DAY_OF_WEEK) -
			     Calendar.SUNDAY);
                        dateObj.setTime(date);
                        calendar.setTime(dateObj);
                        storeDays(dates, date, rangeStart, rangeEnd,
				  dayInWeek.intValue());
                    }
                    // increment the week
                    date += DAY_INCREMENT * 7;
                    dateObj.setTime(date);
                    calendar.setTime(dateObj);
                    break;
                case MONTHLY: {
                    storeDaysByMonth(dates, date, rangeStart, rangeEnd,
                        dayInWeek, dayInMonth, weekInMonth);
                    // increment the month
                    int currentMonth = calendar.get(Calendar.MONTH);
                    if (currentMonth == Calendar.DECEMBER) {
                        int currentYear = calendar.get(Calendar.YEAR);
                        calendar.set(Calendar.YEAR, currentYear + 1);
                        calendar.set(Calendar.MONTH, Calendar.JANUARY);
                    } else {
                        calendar.set(Calendar.MONTH, currentMonth + 1);
                    }
                    dateObj = calendar.getTime();
                    date = dateObj.getTime();
                    break;
                }
                case YEARLY: {
                    if (monthInYear == null && dayInYear == null) {
                        storeDate(dates, date, rangeStart, rangeEnd);
                    } else {
                        // shift to January
                        calendar.set(Calendar.MONTH, Calendar.JANUARY);
                        dateObj = calendar.getTime();
                        date = dateObj.getTime();
                        if (monthInYear != null) {
                            int months = monthInYear.intValue();
                            for (int m = 0; m < MONTHS.length; m++) {
                                if ((months & MONTHS[m]) != 0) {
                                    calendar.set(Calendar.MONTH, m);
                                    storeDaysByMonth(dates,
                                        calendar.getTime().getTime(),
                                        rangeStart, rangeEnd,
                                        dayInWeek, dayInMonth, weekInMonth);
                                }
                            }
                        } else {
                            // dayInYear is non-null
                            // shift to the first of January
                            calendar.set(Calendar.DAY_OF_MONTH, 1);
                            dateObj = calendar.getTime();
                            date = dateObj.getTime();
                            storeDate(dates,
                                date + (dayInYear.intValue() - 1)
				      * DAY_INCREMENT,
                                rangeStart,
                                rangeEnd);
                        }
                    }
                    // increment the year
                    calendar.set(Calendar.YEAR, 
				 calendar.get(Calendar.YEAR) + 1);
                    dateObj = calendar.getTime();
                    date = dateObj.getTime();
                    break;
                }
                default:
                    throw new IllegalArgumentException(
                        "Unrecognized value for frequency: " + frequency);
            } // end switch
        } // end for
        return dates.elements();
    }

    /**
     * Stores a date.
     * @param dates array to extend
     * @param date to be stored
     * @param rangeStart beginning of range
     * @param rangeEnd end of range
     */
    private void storeDate(Vector dates, long date, long rangeStart, 
			   long rangeEnd) {
        if (date >= rangeStart && date <= rangeEnd) {
            Date dateObj = new Date(date);
            if (!exceptions.contains(dateObj)) {
                dates.addElement(new Date(date));
            }
        }
    }

    /** 
     * Store days.
     * @param dates array to extend
     * @param date to be stored
     * @param rangeStart beginning of range
     * @param rangeEnd end of range
     * @param days filter by specific days
     */    
    private void storeDays(Vector dates, long date,
        long rangeStart, long rangeEnd,
        int days) {
        // shift date back to Sunday, if it is not already Sunday
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date(date));
        int dayShift = cal.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY;
        date -= dayShift * DAY_INCREMENT;
        long dateNextWeek = dayShift + DAY_INCREMENT * 7;
        for (int i = 0; i < DAYS.length; i++) {
            if ((days & DAYS[i]) != 0) {
                long targetDate = (dayShift > i) ? dateNextWeek : date;
                storeDate(dates,
                    targetDate + DAY_INCREMENT * i,
                    rangeStart, rangeEnd);
            }
        }
    }
    
    /** 
     * Store days by month.
     * @param dates array to be extended
     * @param date date to be added.
     * @param rangeStart beginning of range
     * @param rangeEnd end of range
     * @param dayInWeek filter for day in the week
     * @param dayInMonth filter for day in the month
     * @param weekInMonth filter for week in the month
     */
    private void storeDaysByMonth(Vector dates, long date,
        long rangeStart, long rangeEnd,
        Integer dayInWeek, Integer dayInMonth, Integer weekInMonth) {
        // move date to the first of the month
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(date));
        date -= DAY_INCREMENT *
            (calendar.get(Calendar.DAY_OF_MONTH) - 1);
        if (dayInMonth != null) {
            storeDate(dates,
            date + DAY_INCREMENT * (dayInMonth.intValue() - 1),
            rangeStart, rangeEnd);
        } else if (weekInMonth != null) {
            // get a limited range, containing only this month.
            long monthRangeStart = Math.max(rangeStart, date);
            // find the end of the month, assuming no month is longer
            // than 31 days
            long monthEnd = date + DAY_INCREMENT * 31;
            calendar.setTime(new Date(monthEnd));
            while (calendar.get(Calendar.DAY_OF_MONTH) > 1) {
                monthEnd -= DAY_INCREMENT;
                calendar.setTime(new Date(monthEnd));
            }
            monthEnd -= DAY_INCREMENT;
            long monthRangeEnd = Math.min(rangeEnd, monthEnd);
            int weeks = weekInMonth.intValue();
            if ((weeks & FIRST) != 0) {
                storeDays(dates, date,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & SECOND) != 0) {
                storeDays(dates, date + DAY_INCREMENT * 7,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & THIRD) != 0) {
                storeDays(dates, date +  DAY_INCREMENT * 14,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & FOURTH) != 0) {
                storeDays(dates, date +  DAY_INCREMENT * 21,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & FIFTH) != 0) {
                storeDays(dates, date +  DAY_INCREMENT * 28,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & LAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 6,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & LAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 6,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & SECONDLAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 13,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & THIRDLAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 20,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & FOURTHLAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 27,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & FIFTHLAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 34,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
        }
    }

    // JAVADOC COMMENT ELIDED
    public void addExceptDate(long date) {
        exceptions.addElement(new Date(date));
    }

    // JAVADOC COMMENT ELIDED
    public void removeExceptDate(long date) {
        exceptions.removeElement(new Date(date));
    }

    // JAVADOC COMMENT ELIDED
    public Enumeration getExceptDates() {
        Vector results = new Vector();
        for (Enumeration e = exceptions.elements();
	    e.hasMoreElements(); ) {
            Date date = (Date) e.nextElement();
            results.addElement(new Date(date.getTime()));
        }
        return results.elements();
    }

    // JAVADOC COMMENT ELIDED
    public int getInt(int field) {
        validateDataType(field, PIMItem.INT);
        return ((Integer) getField(field, NO_DEFAULT)).intValue();
    }
    /** NO_DEFAULT = "". */
    private static final Object NO_DEFAULT = "";
    
    /**
     * Gets the requested field contents.
     * @param field identifier for the requested field
     * @param defaultValue value to return if field is not found
     * @return requetsed field contents
     */
    private Object getField(int field, Object defaultValue) {
        Integer fieldKey = new Integer(field);
        Object fieldValue = fields.get(fieldKey);
        if (fieldValue == null) {
            if (defaultValue == NO_DEFAULT) {
                throw new FieldEmptyException();
            } else {
                return defaultValue;
            }
        }
        return fieldValue;
    }

    // JAVADOC COMMENT ELIDED
    public void setInt(int field, int value) {
        validateDataType(field, PIMItem.INT);
        boolean isValid;
        switch (field) {
            case COUNT:
                isValid = (value >= 1);
                break;
            case DAY_IN_MONTH:
                isValid = (value >= 1 && value <= 31);
                break;
            case DAY_IN_WEEK:
                isValid = (value & ~DAY_IN_WEEK_MASK) == 0;
                break;
            case FREQUENCY:
                switch (value) {
                    case DAILY:
                    case WEEKLY:
                    case MONTHLY:
                    case YEARLY:
                        isValid = true;
                        break;
                    default:
                        isValid = false;
                }
                break;
            case INTERVAL:
                isValid = (value >= 1);
                break;
            case MONTH_IN_YEAR:
                isValid = (value & ~MONTH_IN_YEAR_MASK) == 0;
                break;
            case WEEK_IN_MONTH:
                isValid = (value & ~WEEK_IN_MONTH_MASK) == 0;
                break;
            case DAY_IN_YEAR:
                isValid = (value >= 1 && value <= 366);
                break;
            default:
                isValid = false;
        }
        if (!isValid) {
            throw new IllegalArgumentException("Field value is invalid");
        }
        Integer fieldKey = new Integer(field);
        fields.put(fieldKey, new Integer(value));
    }

    // JAVADOC COMMENT ELIDED
    public long getDate(int field) {
        validateDataType(field, PIMItem.DATE);
        return ((Long) getField(field, NO_DEFAULT)).longValue();
    }

    // JAVADOC COMMENT ELIDED
    public void setDate(int field, long value) {
        validateDataType(field, PIMItem.DATE);
        Integer fieldKey = new Integer(field);
        fields.put(fieldKey, new Long(value));
    }

    // JAVADOC COMMENT ELIDED
    public int[] getFields() {
        int[] result = new int[fields.size()];
        int i = 0;
        for (Enumeration e = fields.keys(); e.hasMoreElements(); ) {
            Integer fieldKey = (Integer) e.nextElement();
            result[i++] = fieldKey.intValue();
        }
        return result;
    }

    // JAVADOC COMMENT ELIDED
    public boolean equals(Object obj) {
        if (obj == null || !(obj instanceof RepeatRule)) {
            return false;
        }
        RepeatRule rule = (RepeatRule) obj;
        Calendar cal = Calendar.getInstance();
        int[] ruleFields = rule.getFields();
        for (int i = 0; i < ruleFields.length; i++) {
            int field = ruleFields[i];
            Object value = fields.get(new Integer(field));
            if (value == null) {
                // field in other rule is defined, but in this rule is not
                return false;
            }
            switch (getDataType(field)) {
                case PIMItem.INT: {
                    int iValue = ((Integer) value).intValue();
                    if (rule.getInt(field) != iValue) {
                        return false;
                    }
                    break;
                }
                case PIMItem.DATE: {
                    // dates match if they are on the same day
                    long thisDate = ((Long) value).longValue();
                    long ruleDate = rule.getDate(field);
                    if (thisDate == ruleDate) {
                        return true;
                    }
                    if (Math.abs(thisDate - ruleDate) >= DAY_LENGTH) {
                        return false;
                    }
                    cal.setTime(new Date(thisDate));
                    int day = cal.get(Calendar.DATE);
                    cal.setTime(new Date(ruleDate));
                    if (day != cal.get(Calendar.DATE)) {
                        return false;
                    }
                    break;
                }
                default:
                    return false; // unreachable
            }
            
        }
        // see if this rule defines any fields that the other rule does not
        for (Enumeration e = fields.keys(); e.hasMoreElements(); ) {
            Integer fieldKey = (Integer) e.nextElement();
            int field = fieldKey.intValue();
            boolean match = false;
            for (int i = 0; i < ruleFields.length && !match; i++) {
                if (ruleFields[i] == field) {
                    match = true;
                }
            }
            if (!match) {
                return false;
            }
        }
        // check exception dates
        // normalize the list of exception dates to represent only the date
        // and not the time of day
        int[] exceptionDates = new int[exceptions.size()];
        for (int i = 0; i < exceptionDates.length; i++) {
            Date date = (Date) exceptions.elementAt(i);
            cal.setTime(date);
            exceptionDates[i] = cal.get(Calendar.DAY_OF_MONTH)
                + 100 * cal.get(Calendar.MONTH)
                + 10000 * cal.get(Calendar.YEAR);
        }
        boolean[] matchedExceptionDates = new boolean[exceptionDates.length];
        for (Enumeration e = rule.getExceptDates(); e.hasMoreElements(); ) {
            Date date = (Date) e.nextElement();
            cal.setTime(date);
            int day = cal.get(Calendar.DAY_OF_MONTH)
                + 100 * cal.get(Calendar.MONTH)
                + 10000 * cal.get(Calendar.YEAR);
            boolean match = false;
            for (int i = 0; i < exceptionDates.length && !match; i++) {
                if (exceptionDates[i] == day) {
                    match = true;
                    matchedExceptionDates[i] = true;
                }
            }
            if (!match) {
                return false;
            }
        }
        // are there unmatched exception dates?
        for (int i = 0; i < matchedExceptionDates.length; i++) {
            if (!matchedExceptionDates[i]) {
                // make sure this isn't a duplicate of another date
                boolean duplicate = false;
                for (int j = 0; j < i && !duplicate; j++) {
                    duplicate = exceptionDates[j] == exceptionDates[i];
                }
                if (!duplicate) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Checks that data type is valid.
     * @param field identifier of requested field
     * @param dataType type of data to be checked
     * @throws IllegalArgumentException if type is not appropriate
     */
    private void validateDataType(int field, int dataType) {
        int correctDataType = getDataType(field);
        if (dataType != correctDataType) {
            throw new IllegalArgumentException("Invalid field type");
        }
    }
    
    /**
     * Gets the data type for the requested field.
     * @param field identifier of requested field
     * @return data type of requested field
     */
    private int getDataType(int field) {
        switch (field) {
            case COUNT:
            case DAY_IN_MONTH:
            case DAY_IN_WEEK:
            case DAY_IN_YEAR:
            case FREQUENCY:
            case INTERVAL:
            case MONTH_IN_YEAR:
            case WEEK_IN_MONTH:
                return PIMItem.INT;
            case END:
                return PIMItem.DATE;
            default:
                throw new IllegalArgumentException("Unrecognized field: "
						   + field);
        }
    }
}