    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.5 2005/11/03 09:24:45 mungady 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
    044    package 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     */
    056    public 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 <= year <= 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    }