    001/* ========================================================================
    002 * JCommon : a free general purpose class library for the Java(tm) platform
    003 * ========================================================================
    004 *
    005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
    006 *
    007 * Project Info:  http://www.jfree.org/jcommon/index.html
    008 *
    009 * This library is free software; you can redistribute it and/or modify it
    010 * under the terms of the GNU Lesser General Public License as published by
    011 * the Free Software Foundation; either version 2.1 of the License, or
    012 * (at your option) any later version.
    013 *
    014 * This library is distributed in the hope that it will be useful, but
    015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017 * License for more details.
    018 *
    019 * You should have received a copy of the GNU Lesser General Public
    020 * License along with this library; if not, write to the Free Software
    021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022 * USA.
    023 *
    024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025 * in the United States and other countries.]
    026 *
    027 * --------------------------
    028 * RelativeDayOfWeekRule.java
    029 * --------------------------
    030 * (C) Copyright 2000-2003, by Object Refinery Limited and Contributors.
    031 *
    032 * Original Author:  David Gilbert (for Object Refinery Limited);
    033 * Contributor(s):   -;
    034 *
    035 * $Id: RelativeDayOfWeekRule.java,v 1.6 2005/11/16 15:58:40 taqua Exp $
    036 *
    037 * Changes (from 26-Oct-2001)
    038 * --------------------------
    039 * 26-Oct-2001 : Changed package to com.jrefinery.date.*;
    040 * 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
    041 *
    042 */
    043
    044package org.jfree.date;
    045
    046/**
    047 * An annual date rule that returns a date for each year based on (a) a
    048 * reference rule; (b) a day of the week; and (c) a selection parameter
    049 * (SerialDate.PRECEDING, SerialDate.NEAREST, SerialDate.FOLLOWING).
    050 * <P>
    051 * For example, Good Friday can be specified as 'the Friday PRECEDING Easter
    052 * Sunday'.
    053 *
    054 * @author David Gilbert
    055 */
    056public class RelativeDayOfWeekRule extends AnnualDateRule {
    057
    058    /** A reference to the annual date rule on which this rule is based. */
    059    private AnnualDateRule subrule;
    060
    061    /**
    062     * The day of the week (SerialDate.MONDAY, SerialDate.TUESDAY, and so on).
    063     */
    064    private int dayOfWeek;
    065
    066    /** Specifies which day of the week (PRECEDING, NEAREST or FOLLOWING). */
    067    private int relative;
    068
    069    /**
    070     * Default constructor - builds a rule for the Monday following 1 January.
    071     */
    072    public RelativeDayOfWeekRule() {
    073        this(new DayAndMonthRule(), SerialDate.MONDAY, SerialDate.FOLLOWING);
    074    }
    075
    076    /**
    077     * Standard constructor - builds rule based on the supplied sub-rule.
    078     *
    079     * @param subrule  the rule that determines the reference date.
    080     * @param dayOfWeek  the day-of-the-week relative to the reference date.
    081     * @param relative  indicates *which* day-of-the-week (preceding, nearest
    082     *                  or following).
    083     */
    084    public RelativeDayOfWeekRule(final AnnualDateRule subrule,
    085            final int dayOfWeek, final int relative) {
    086        this.subrule = subrule;
    087        this.dayOfWeek = dayOfWeek;
    088        this.relative = relative;
    089    }
    090
    091    /**
    092     * Returns the sub-rule (also called the reference rule).
    093     *
    094     * @return The annual date rule that determines the reference date for this
    095     *         rule.
    096     */
    097    public AnnualDateRule getSubrule() {
    098        return this.subrule;
    099    }
    100
    101    /**
    102     * Sets the sub-rule.
    103     *
    104     * @param subrule  the annual date rule that determines the reference date
    105     *                 for this rule.
    106     */
    107    public void setSubrule(final AnnualDateRule subrule) {
    108        this.subrule = subrule;
    109    }
    110
    111    /**
    112     * Returns the day-of-the-week for this rule.
    113     *
    114     * @return the day-of-the-week for this rule.
    115     */
    116    public int getDayOfWeek() {
    117        return this.dayOfWeek;
    118    }
    119
    120    /**
    121     * Sets the day-of-the-week for this rule.
    122     *
    123     * @param dayOfWeek  the day-of-the-week (SerialDate.MONDAY,
    124     *                   SerialDate.TUESDAY, and so on).
    125     */
    126    public void setDayOfWeek(final int dayOfWeek) {
    127        this.dayOfWeek = dayOfWeek;
    128    }
    129
    130    /**
    131     * Returns the 'relative' attribute, that determines *which*
    132     * day-of-the-week we are interested in (SerialDate.PRECEDING,
    133     * SerialDate.NEAREST or SerialDate.FOLLOWING).
    134     *
    135     * @return The 'relative' attribute.
    136     */
    137    public int getRelative() {
    138        return this.relative;
    139    }
    140
    141    /**
    142     * Sets the 'relative' attribute (SerialDate.PRECEDING, SerialDate.NEAREST,
    143     * SerialDate.FOLLOWING).
    144     *
    145     * @param relative  determines *which* day-of-the-week is selected by this
    146     *                  rule.
    147     */
    148    public void setRelative(final int relative) {
    149        this.relative = relative;
    150    }
    151
    152    /**
    153     * Creates a clone of this rule.
    154     *
    155     * @return a clone of this rule.
    156     *
    157     * @throws CloneNotSupportedException this should never happen.
    158     */
    159    public Object clone() throws CloneNotSupportedException {
    160        final RelativeDayOfWeekRule duplicate
    161            = (RelativeDayOfWeekRule) super.clone();
    162        duplicate.subrule = (AnnualDateRule) duplicate.getSubrule().clone();
    163        return duplicate;
    164    }
    165
    166    /**
    167     * Returns the date generated by this rule, for the specified year.
    168     *
    169     * @param year  the year (1900 &lt;= year &lt;= 9999).
    170     *
    171     * @return The date generated by the rule for the given year (possibly
    172     *         <code>null</code>).
    173     */
    174    public SerialDate getDate(final int year) {
    175
    176        // check argument...
    177        if ((year < SerialDate.MINIMUM_YEAR_SUPPORTED)
    178            || (year > SerialDate.MAXIMUM_YEAR_SUPPORTED)) {
    179            throw new IllegalArgumentException(
    180                "RelativeDayOfWeekRule.getDate(): year outside valid range.");
    181        }
    182
    183        // calculate the date...
    184        SerialDate result = null;
    185        final SerialDate base = this.subrule.getDate(year);
    186
    187        if (base != null) {
    188            switch (this.relative) {
    189                case(SerialDate.PRECEDING):
    190                    result = SerialDate.getPreviousDayOfWeek(this.dayOfWeek,
    191                            base);
    192                    break;
    193                case(SerialDate.NEAREST):
    194                    result = SerialDate.getNearestDayOfWeek(this.dayOfWeek,
    195                            base);
    196                    break;
    197                case(SerialDate.FOLLOWING):
    198                    result = SerialDate.getFollowingDayOfWeek(this.dayOfWeek,
    199                            base);
    200                    break;
    201                default:
    202                    break;
    203            }
    204        }
    205        return result;
    206
    207    }
    208
    209}