Home | History | Annotate | Download | only in pim
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.pim;
     18 
     19 import android.text.TextUtils;
     20 import android.text.format.Time;
     21 
     22 import java.util.Calendar;
     23 
     24 public class EventRecurrence
     25 {
     26     /**
     27      * Thrown when a recurrence string provided can not be parsed according
     28      * to RFC2445.
     29      */
     30     public static class InvalidFormatException extends RuntimeException
     31     {
     32         InvalidFormatException(String s) {
     33             super(s);
     34         }
     35     }
     36 
     37     public EventRecurrence()
     38     {
     39         wkst = MO;
     40     }
     41 
     42     /**
     43      * Parse an iCalendar/RFC2445 recur type according to Section 4.3.10.
     44      */
     45     public native void parse(String recur);
     46 
     47     public void setStartDate(Time date) {
     48         startDate = date;
     49     }
     50 
     51     public static final int SECONDLY = 1;
     52     public static final int MINUTELY = 2;
     53     public static final int HOURLY = 3;
     54     public static final int DAILY = 4;
     55     public static final int WEEKLY = 5;
     56     public static final int MONTHLY = 6;
     57     public static final int YEARLY = 7;
     58 
     59     public static final int SU = 0x00010000;
     60     public static final int MO = 0x00020000;
     61     public static final int TU = 0x00040000;
     62     public static final int WE = 0x00080000;
     63     public static final int TH = 0x00100000;
     64     public static final int FR = 0x00200000;
     65     public static final int SA = 0x00400000;
     66 
     67     public Time      startDate;
     68     public int       freq;
     69     public String    until;
     70     public int       count;
     71     public int       interval;
     72     public int       wkst;
     73 
     74     public int[]     bysecond;
     75     public int       bysecondCount;
     76     public int[]     byminute;
     77     public int       byminuteCount;
     78     public int[]     byhour;
     79     public int       byhourCount;
     80     public int[]     byday;
     81     public int[]     bydayNum;
     82     public int       bydayCount;
     83     public int[]     bymonthday;
     84     public int       bymonthdayCount;
     85     public int[]     byyearday;
     86     public int       byyeardayCount;
     87     public int[]     byweekno;
     88     public int       byweeknoCount;
     89     public int[]     bymonth;
     90     public int       bymonthCount;
     91     public int[]     bysetpos;
     92     public int       bysetposCount;
     93 
     94     /**
     95      * Converts one of the Calendar.SUNDAY constants to the SU, MO, etc.
     96      * constants.  btw, I think we should switch to those here too, to
     97      * get rid of this function, if possible.
     98      */
     99     public static int calendarDay2Day(int day)
    100     {
    101         switch (day)
    102         {
    103             case Calendar.SUNDAY:
    104                 return SU;
    105             case Calendar.MONDAY:
    106                 return MO;
    107             case Calendar.TUESDAY:
    108                 return TU;
    109             case Calendar.WEDNESDAY:
    110                 return WE;
    111             case Calendar.THURSDAY:
    112                 return TH;
    113             case Calendar.FRIDAY:
    114                 return FR;
    115             case Calendar.SATURDAY:
    116                 return SA;
    117             default:
    118                 throw new RuntimeException("bad day of week: " + day);
    119         }
    120     }
    121 
    122     public static int timeDay2Day(int day)
    123     {
    124         switch (day)
    125         {
    126             case Time.SUNDAY:
    127                 return SU;
    128             case Time.MONDAY:
    129                 return MO;
    130             case Time.TUESDAY:
    131                 return TU;
    132             case Time.WEDNESDAY:
    133                 return WE;
    134             case Time.THURSDAY:
    135                 return TH;
    136             case Time.FRIDAY:
    137                 return FR;
    138             case Time.SATURDAY:
    139                 return SA;
    140             default:
    141                 throw new RuntimeException("bad day of week: " + day);
    142         }
    143     }
    144     public static int day2TimeDay(int day)
    145     {
    146         switch (day)
    147         {
    148             case SU:
    149                 return Time.SUNDAY;
    150             case MO:
    151                 return Time.MONDAY;
    152             case TU:
    153                 return Time.TUESDAY;
    154             case WE:
    155                 return Time.WEDNESDAY;
    156             case TH:
    157                 return Time.THURSDAY;
    158             case FR:
    159                 return Time.FRIDAY;
    160             case SA:
    161                 return Time.SATURDAY;
    162             default:
    163                 throw new RuntimeException("bad day of week: " + day);
    164         }
    165     }
    166 
    167     /**
    168      * Converts one of the SU, MO, etc. constants to the Calendar.SUNDAY
    169      * constants.  btw, I think we should switch to those here too, to
    170      * get rid of this function, if possible.
    171      */
    172     public static int day2CalendarDay(int day)
    173     {
    174         switch (day)
    175         {
    176             case SU:
    177                 return Calendar.SUNDAY;
    178             case MO:
    179                 return Calendar.MONDAY;
    180             case TU:
    181                 return Calendar.TUESDAY;
    182             case WE:
    183                 return Calendar.WEDNESDAY;
    184             case TH:
    185                 return Calendar.THURSDAY;
    186             case FR:
    187                 return Calendar.FRIDAY;
    188             case SA:
    189                 return Calendar.SATURDAY;
    190             default:
    191                 throw new RuntimeException("bad day of week: " + day);
    192         }
    193     }
    194 
    195     /**
    196      * Converts one of the internal day constants (SU, MO, etc.) to the
    197      * two-letter string representing that constant.
    198      *
    199      * @throws IllegalArgumentException Thrown if the day argument is not one of
    200      * the defined day constants.
    201      *
    202      * @param day one the internal constants SU, MO, etc.
    203      * @return the two-letter string for the day ("SU", "MO", etc.)
    204      */
    205     private static String day2String(int day) {
    206         switch (day) {
    207         case SU:
    208             return "SU";
    209         case MO:
    210             return "MO";
    211         case TU:
    212             return "TU";
    213         case WE:
    214             return "WE";
    215         case TH:
    216             return "TH";
    217         case FR:
    218             return "FR";
    219         case SA:
    220             return "SA";
    221         default:
    222             throw new IllegalArgumentException("bad day argument: " + day);
    223         }
    224     }
    225 
    226     private static void appendNumbers(StringBuilder s, String label,
    227                                         int count, int[] values)
    228     {
    229         if (count > 0) {
    230             s.append(label);
    231             count--;
    232             for (int i=0; i<count; i++) {
    233                 s.append(values[i]);
    234                 s.append(",");
    235             }
    236             s.append(values[count]);
    237         }
    238     }
    239 
    240     private void appendByDay(StringBuilder s, int i)
    241     {
    242         int n = this.bydayNum[i];
    243         if (n != 0) {
    244             s.append(n);
    245         }
    246 
    247         String str = day2String(this.byday[i]);
    248         s.append(str);
    249     }
    250 
    251     @Override
    252     public String toString()
    253     {
    254         StringBuilder s = new StringBuilder();
    255 
    256         s.append("FREQ=");
    257         switch (this.freq)
    258         {
    259             case SECONDLY:
    260                 s.append("SECONDLY");
    261                 break;
    262             case MINUTELY:
    263                 s.append("MINUTELY");
    264                 break;
    265             case HOURLY:
    266                 s.append("HOURLY");
    267                 break;
    268             case DAILY:
    269                 s.append("DAILY");
    270                 break;
    271             case WEEKLY:
    272                 s.append("WEEKLY");
    273                 break;
    274             case MONTHLY:
    275                 s.append("MONTHLY");
    276                 break;
    277             case YEARLY:
    278                 s.append("YEARLY");
    279                 break;
    280         }
    281 
    282         if (!TextUtils.isEmpty(this.until)) {
    283             s.append(";UNTIL=");
    284             s.append(until);
    285         }
    286 
    287         if (this.count != 0) {
    288             s.append(";COUNT=");
    289             s.append(this.count);
    290         }
    291 
    292         if (this.interval != 0) {
    293             s.append(";INTERVAL=");
    294             s.append(this.interval);
    295         }
    296 
    297         if (this.wkst != 0) {
    298             s.append(";WKST=");
    299             s.append(day2String(this.wkst));
    300         }
    301 
    302         appendNumbers(s, ";BYSECOND=", this.bysecondCount, this.bysecond);
    303         appendNumbers(s, ";BYMINUTE=", this.byminuteCount, this.byminute);
    304         appendNumbers(s, ";BYSECOND=", this.byhourCount, this.byhour);
    305 
    306         // day
    307         int count = this.bydayCount;
    308         if (count > 0) {
    309             s.append(";BYDAY=");
    310             count--;
    311             for (int i=0; i<count; i++) {
    312                 appendByDay(s, i);
    313                 s.append(",");
    314             }
    315             appendByDay(s, count);
    316         }
    317 
    318         appendNumbers(s, ";BYMONTHDAY=", this.bymonthdayCount, this.bymonthday);
    319         appendNumbers(s, ";BYYEARDAY=", this.byyeardayCount, this.byyearday);
    320         appendNumbers(s, ";BYWEEKNO=", this.byweeknoCount, this.byweekno);
    321         appendNumbers(s, ";BYMONTH=", this.bymonthCount, this.bymonth);
    322         appendNumbers(s, ";BYSETPOS=", this.bysetposCount, this.bysetpos);
    323 
    324         return s.toString();
    325     }
    326 
    327     public boolean repeatsOnEveryWeekDay() {
    328         if (this.freq != WEEKLY) {
    329             return false;
    330         }
    331 
    332         int count = this.bydayCount;
    333         if (count != 5) {
    334             return false;
    335         }
    336 
    337         for (int i = 0 ; i < count ; i++) {
    338             int day = byday[i];
    339             if (day == SU || day == SA) {
    340                 return false;
    341             }
    342         }
    343 
    344         return true;
    345     }
    346 
    347     public boolean repeatsMonthlyOnDayCount() {
    348         if (this.freq != MONTHLY) {
    349             return false;
    350         }
    351 
    352         if (bydayCount != 1 || bymonthdayCount != 0) {
    353             return false;
    354         }
    355 
    356         return true;
    357     }
    358 }
    359