1 /*
   2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 import java.util.ArrayList;
  27 import java.util.HashMap;
  28 import java.util.List;
  29 import java.util.Map;
  30 
  31 /**
  32  * RuleDay class represents the value of the "ON" field.  The day of
  33  * week values start from 1 following the {@link java.util.Calendar}
  34  * convention.
  35  *
  36  * @since 1.4
  37  */
  38 class RuleDay {
  39     private static final Map<String,DayOfWeek> abbreviations = new HashMap<String,DayOfWeek>(7);
  40     static {
  41         for (DayOfWeek day : DayOfWeek.values()) {
  42             abbreviations.put(day.getAbbr(), day);
  43         }
  44     }
  45 
  46     private String dayName = null;
  47     private DayOfWeek dow;
  48     private boolean lastOne = false;
  49     private int soonerOrLater = 0;
  50     private int thanDayOfMonth; // day of month (e.g., 8 for "Sun>=8")
  51 
  52     RuleDay() {
  53     }
  54 
  55     RuleDay(int day) {
  56         thanDayOfMonth = day;
  57     }
  58 
  59     int getDay() {
  60         return thanDayOfMonth;
  61     }
  62 
  63     /**
  64      * @return the day of week value (1-based)
  65      */
  66     int getDayOfWeekNum() {
  67         return dow.value();
  68     }
  69 
  70     /**
  71      * @return true if this rule day represents the last day of
  72      * week. (e.g., lastSun).
  73      */
  74     boolean isLast() {
  75         return lastOne;
  76     }
  77 
  78     /**
  79      * @return true if this rule day represents the day of week on or
  80      * later than (after) the {@link #getDay}. (e.g., Sun>=1)
  81      */
  82     boolean isLater() {
  83         return soonerOrLater > 0;
  84     }
  85 
  86     /**
  87      * @return true if this rule day represents the day of week on or
  88      * earlier than (before) the {@link #getDay}. (e.g., Sun<=15)
  89      */
  90     boolean isEarlier() {
  91         return soonerOrLater < 0;
  92     }
  93 
  94     /**
  95      * @return true if this rule day represents an exact day.
  96      */
  97     boolean isExact() {
  98         return soonerOrLater == 0;
  99     }
 100 
 101     /**
 102      * Parses the "ON" field and constructs a RuleDay.
 103      * @param day an "ON" field string (e.g., "Sun>=1")
 104      * @return a RuleDay representing the given "ON" field
 105      */
 106     static RuleDay parse(String day) {
 107         RuleDay d = new RuleDay();
 108         if (day.startsWith("last")) {
 109             d.lastOne = true;
 110             d.dayName = day.substring(4);
 111             d.dow = getDOW(d.dayName);
 112         } else {
 113             int index;
 114             if ((index = day.indexOf(">=")) != -1) {
 115                 d.dayName = day.substring(0, index);
 116                 d.dow = getDOW(d.dayName);
 117                 d.soonerOrLater = 1; // greater or equal
 118                 d.thanDayOfMonth = Integer.parseInt(day.substring(index+2));
 119             } else if ((index = day.indexOf("<=")) != -1) {
 120                 d.dayName = day.substring(0, index);
 121                 d.dow = getDOW(d.dayName);
 122                 d.soonerOrLater = -1; // less or equal
 123                 d.thanDayOfMonth = Integer.parseInt(day.substring(index+2));
 124             } else {
 125                 // it should be an integer value.
 126                 d.thanDayOfMonth = Integer.parseInt(day);
 127             }
 128         }
 129         return d;
 130     }
 131 
 132     /**
 133      * Converts this RuleDay to the SimpleTimeZone day rule.
 134      * @return the converted SimpleTimeZone day rule
 135      */
 136     int getDayForSimpleTimeZone() {
 137         if (isLast()) {
 138             return -1;
 139         }
 140         return isEarlier() ? -getDay() : getDay();
 141     }
 142 
 143     /**
 144      * Converts this RuleDay to the SimpleTimeZone day-of-week rule.
 145      * @return the SimpleTimeZone day-of-week rule value
 146      */
 147     int getDayOfWeekForSimpleTimeZoneInt() {
 148         if (isEarlier() || isLater()) {
 149             return -getDayOfWeekNum();
 150         }
 151         return isLast() ? getDayOfWeekNum() : 0;
 152     }
 153 
 154     /**
 155      * @return the string representation of the {@link
 156      * #getDayOfWeekForSimpleTimeZoneInt} value
 157      */
 158     String getDayOfWeekForSimpleTimeZone() {
 159         int d = getDayOfWeekForSimpleTimeZoneInt();
 160         if (d == 0) {
 161             return "0";
 162         }
 163         String sign = "";
 164         if (d < 0) {
 165             sign = "-";
 166             d = -d;
 167         }
 168         return sign + toString(d);
 169     }
 170 
 171     private static DayOfWeek getDOW(String abbr) {
 172         return abbreviations.get(abbr);
 173     }
 174 
 175     /**
 176      * Converts the specified day of week value to the day-of-week
 177      * name defined in {@link java.util.Calenda}.
 178      * @param dow 1-based day of week value
 179      * @return the Calendar day of week name with "Calendar." prefix.
 180      * @throws IllegalArgumentException if the specified dow value is out of range.
 181      */
 182     static String toString(int dow) {
 183         if (dow >= DayOfWeek.SUNDAY.value() && dow <= DayOfWeek.SATURDAY.value()) {
 184             return "Calendar." + DayOfWeek.values()[dow - 1];
 185         }
 186         throw new IllegalArgumentException("wrong Day_of_Week number: " + dow);
 187     }
 188 }