src/net/fortuna/ical4j/model/PeriodList.java

Tue, 10 Feb 2015 18:12:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 18:12:00 +0100
changeset 0
fb9019fb1bf7
child 3
73bdfa70b04e
permissions
-rw-r--r--

Import initial revisions of existing project AndroidCaldavSyncAdapater,
forked from upstream repository at 27e8a0f8495c92e0780d450bdf0c7cec77a03a55.

michael@0 1 /**
michael@0 2 * Copyright (c) 2012, Ben Fortuna
michael@0 3 * All rights reserved.
michael@0 4 *
michael@0 5 * Redistribution and use in source and binary forms, with or without
michael@0 6 * modification, are permitted provided that the following conditions
michael@0 7 * are met:
michael@0 8 *
michael@0 9 * o Redistributions of source code must retain the above copyright
michael@0 10 * notice, this list of conditions and the following disclaimer.
michael@0 11 *
michael@0 12 * o Redistributions in binary form must reproduce the above copyright
michael@0 13 * notice, this list of conditions and the following disclaimer in the
michael@0 14 * documentation and/or other materials provided with the distribution.
michael@0 15 *
michael@0 16 * o Neither the name of Ben Fortuna nor the names of any other contributors
michael@0 17 * may be used to endorse or promote products derived from this software
michael@0 18 * without specific prior written permission.
michael@0 19 *
michael@0 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
michael@0 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
michael@0 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
michael@0 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
michael@0 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
michael@0 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
michael@0 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
michael@0 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 31 */
michael@0 32 package net.fortuna.ical4j.model;
michael@0 33
michael@0 34 import java.io.Serializable;
michael@0 35 import java.text.ParseException;
michael@0 36 import java.util.Collection;
michael@0 37 import java.util.Collections;
michael@0 38 import java.util.Iterator;
michael@0 39 import java.util.Set;
michael@0 40 import java.util.StringTokenizer;
michael@0 41 import java.util.TreeSet;
michael@0 42
michael@0 43 import org.apache.commons.lang.builder.EqualsBuilder;
michael@0 44 import org.apache.commons.lang.builder.HashCodeBuilder;
michael@0 45
michael@0 46 /**
michael@0 47 * $Id$ [23-Apr-2004]
michael@0 48 *
michael@0 49 * Defines a list of iCalendar periods. NOTE: By implementing the
michael@0 50 * <code>java.util.SortedSet</code> interface period lists will always be
michael@0 51 * sorted according to natural ordering.
michael@0 52 *
michael@0 53 * @author Ben Fortuna
michael@0 54 */
michael@0 55 public class PeriodList implements Set, Serializable {
michael@0 56
michael@0 57 private static final long serialVersionUID = -2317587285790834492L;
michael@0 58
michael@0 59 private final Set periods;
michael@0 60
michael@0 61 private TimeZone timezone;
michael@0 62
michael@0 63 private boolean utc;
michael@0 64
michael@0 65 private final boolean unmodifiable;
michael@0 66
michael@0 67 /**
michael@0 68 * Default constructor.
michael@0 69 */
michael@0 70 public PeriodList() {
michael@0 71 this(true);
michael@0 72 }
michael@0 73
michael@0 74 /**
michael@0 75 * @param utc indicates whether the period list is in UTC time
michael@0 76 */
michael@0 77 public PeriodList(boolean utc) {
michael@0 78 this(utc, false);
michael@0 79 }
michael@0 80
michael@0 81 /**
michael@0 82 * @param utc indicates whether the period list is in UTC time
michael@0 83 */
michael@0 84 public PeriodList(boolean utc, final boolean unmodifiable) {
michael@0 85 this.utc = utc;
michael@0 86 this.unmodifiable = unmodifiable;
michael@0 87 if (unmodifiable) {
michael@0 88 periods = Collections.EMPTY_SET;
michael@0 89 }
michael@0 90 else {
michael@0 91 periods = new TreeSet();
michael@0 92 }
michael@0 93 }
michael@0 94
michael@0 95 /**
michael@0 96 * Parses the specified string representation to create a list of periods.
michael@0 97 *
michael@0 98 * @param aValue
michael@0 99 * a string representation of a list of periods
michael@0 100 * @throws ParseException
michael@0 101 * thrown when an invalid string representation of a period list
michael@0 102 * is specified
michael@0 103 */
michael@0 104 public PeriodList(final String aValue) throws ParseException {
michael@0 105 this();
michael@0 106 final StringTokenizer t = new StringTokenizer(aValue, ",");
michael@0 107 while (t.hasMoreTokens()) {
michael@0 108 add((Object) new Period(t.nextToken()));
michael@0 109 }
michael@0 110 }
michael@0 111
michael@0 112 /**
michael@0 113 * {@inheritDoc}
michael@0 114 */
michael@0 115 public final String toString() {
michael@0 116 final StringBuffer b = new StringBuffer();
michael@0 117 for (final Iterator i = iterator(); i.hasNext();) {
michael@0 118 b.append(i.next().toString());
michael@0 119 if (i.hasNext()) {
michael@0 120 b.append(',');
michael@0 121 }
michael@0 122 }
michael@0 123 return b.toString();
michael@0 124 }
michael@0 125
michael@0 126 /**
michael@0 127 * Add a period to the list.
michael@0 128 *
michael@0 129 * @param period
michael@0 130 * the period to add
michael@0 131 * @return true
michael@0 132 * @see java.util.List#add(java.lang.Object)
michael@0 133 */
michael@0 134 public final boolean add(final Period period) {
michael@0 135 if (isUtc()) {
michael@0 136 period.setUtc(true);
michael@0 137 }
michael@0 138 else {
michael@0 139 period.setTimeZone(timezone);
michael@0 140 }
michael@0 141 return add((Object) period);
michael@0 142 }
michael@0 143
michael@0 144 /**
michael@0 145 * Overrides superclass to throw an <code>IllegalArgumentException</code>
michael@0 146 * where argument is not a <code>net.fortuna.ical4j.model.Period</code>.
michael@0 147 * @param period a period to add to the list
michael@0 148 * @return true if the period was added, otherwise false
michael@0 149 * @see java.util.List#add(E)
michael@0 150 */
michael@0 151 public final boolean add(final Object period) {
michael@0 152 if (!(period instanceof Period)) {
michael@0 153 throw new IllegalArgumentException("Argument not a "
michael@0 154 + Period.class.getName());
michael@0 155 }
michael@0 156 return periods.add(period);
michael@0 157 }
michael@0 158
michael@0 159 /**
michael@0 160 * Remove a period from the list.
michael@0 161 *
michael@0 162 * @param period
michael@0 163 * the period to remove
michael@0 164 * @return true if the list contained the specified period
michael@0 165 * @see java.util.List#remove(java.lang.Object)
michael@0 166 */
michael@0 167 public final boolean remove(final Period period) {
michael@0 168 return remove((Object) period);
michael@0 169 }
michael@0 170
michael@0 171 /**
michael@0 172 * Returns a normalised version of this period list. Normalisation includes
michael@0 173 * combining overlapping periods, removing periods contained by other
michael@0 174 * periods, combining adjacent periods, and removing periods that consume
michael@0 175 * no time. NOTE: If the period list is
michael@0 176 * already normalised then this period list is returned.
michael@0 177 *
michael@0 178 * @return a period list
michael@0 179 */
michael@0 180 public final PeriodList normalise() {
michael@0 181 Period prevPeriod = null;
michael@0 182 Period period = null;
michael@0 183 final PeriodList newList = new PeriodList(isUtc());
michael@0 184 if (timezone != null) {
michael@0 185 newList.setTimeZone(timezone);
michael@0 186 }
michael@0 187 boolean normalised = false;
michael@0 188 for (final Iterator i = iterator(); i.hasNext();) {
michael@0 189 period = (Period) i.next();
michael@0 190 if (period.isEmpty()) {
michael@0 191 period = prevPeriod;
michael@0 192 normalised = true;
michael@0 193 }
michael@0 194 else if (prevPeriod != null) {
michael@0 195 // ignore periods contained by other periods..
michael@0 196 if (prevPeriod.contains(period)) {
michael@0 197 period = prevPeriod;
michael@0 198 normalised = true;
michael@0 199 }
michael@0 200 // combine intersecting periods..
michael@0 201 else if (prevPeriod.intersects(period)) {
michael@0 202 period = prevPeriod.add(period);
michael@0 203 normalised = true;
michael@0 204 }
michael@0 205 // combine adjacent periods..
michael@0 206 else if (prevPeriod.adjacent(period)) {
michael@0 207 period = prevPeriod.add(period);
michael@0 208 normalised = true;
michael@0 209 }
michael@0 210 else {
michael@0 211 // if current period is recognised as distinct
michael@0 212 // from previous period, add the previous period
michael@0 213 // to the list..
michael@0 214 newList.add(prevPeriod);
michael@0 215 }
michael@0 216 }
michael@0 217 prevPeriod = period;
michael@0 218 }
michael@0 219 // remember to add the last period to the list..
michael@0 220 if (prevPeriod != null) {
michael@0 221 newList.add(prevPeriod);
michael@0 222 }
michael@0 223 // only return new list if normalisation
michael@0 224 // has ocurred..
michael@0 225 if (normalised) {
michael@0 226 return newList;
michael@0 227 }
michael@0 228 else {
michael@0 229 return this;
michael@0 230 }
michael@0 231 }
michael@0 232
michael@0 233 /**
michael@0 234 * A convenience method that combines all the periods in the specified list to
michael@0 235 * this list. The result returned is a new PeriodList instance, except where
michael@0 236 * no periods are specified in the arguments. In such cases this instance is returned.
michael@0 237 *
michael@0 238 * Normalisation is also performed automatically after all periods have been added.
michael@0 239 *
michael@0 240 * @param periods a list of periods to add
michael@0 241 * @return a period list instance
michael@0 242 */
michael@0 243 public final PeriodList add(final PeriodList periods) {
michael@0 244 if (periods != null) {
michael@0 245 final PeriodList newList = new PeriodList();
michael@0 246 newList.addAll(this);
michael@0 247 for (final Iterator i = periods.iterator(); i.hasNext();) {
michael@0 248 newList.add((Period) i.next());
michael@0 249 }
michael@0 250 return newList.normalise();
michael@0 251 }
michael@0 252 return this;
michael@0 253 }
michael@0 254
michael@0 255 /**
michael@0 256 * Subtracts the intersection of this list with the specified list of
michael@0 257 * periods from this list and returns the results as a new period list. If
michael@0 258 * no intersection is identified this list is returned.
michael@0 259 *
michael@0 260 * @param subtractions
michael@0 261 * a list of periods to subtract from this list
michael@0 262 * @return a period list
michael@0 263 */
michael@0 264 public final PeriodList subtract(final PeriodList subtractions) {
michael@0 265 if (subtractions == null || subtractions.isEmpty()) {
michael@0 266 return this;
michael@0 267 }
michael@0 268
michael@0 269 PeriodList result = this;
michael@0 270 PeriodList tmpResult = new PeriodList();
michael@0 271
michael@0 272 for (final Iterator i = subtractions.iterator(); i.hasNext();) {
michael@0 273 final Period subtraction = (Period) i.next();
michael@0 274 for (final Iterator j = result.iterator(); j.hasNext();) {
michael@0 275 final Period period = (Period) j.next();
michael@0 276 tmpResult.addAll(period.subtract(subtraction));
michael@0 277 }
michael@0 278 result = tmpResult;
michael@0 279 tmpResult = new PeriodList();
michael@0 280 }
michael@0 281
michael@0 282 return result;
michael@0 283 }
michael@0 284
michael@0 285 public final boolean isUnmodifiable() {
michael@0 286 return unmodifiable;
michael@0 287 }
michael@0 288
michael@0 289 /**
michael@0 290 * Indicates whether this list is in local or UTC format.
michael@0 291 * @return Returns true if in UTC format, otherwise false.
michael@0 292 */
michael@0 293 public final boolean isUtc() {
michael@0 294 return utc;
michael@0 295 }
michael@0 296
michael@0 297 /**
michael@0 298 * Sets whether this list is in UTC or local time format.
michael@0 299 * @param utc The utc to set.
michael@0 300 */
michael@0 301 public final void setUtc(final boolean utc) {
michael@0 302 for (final Iterator i = iterator(); i.hasNext();) {
michael@0 303 final Period period = (Period) i.next();
michael@0 304 period.setUtc(utc);
michael@0 305 }
michael@0 306 this.timezone = null;
michael@0 307 this.utc = utc;
michael@0 308 }
michael@0 309
michael@0 310 /**
michael@0 311 * Applies the specified timezone to all dates in the list.
michael@0 312 * All dates added to this list will also have this timezone
michael@0 313 * applied.
michael@0 314 * @param timeZone the timezone for the period list
michael@0 315 */
michael@0 316 public final void setTimeZone(final TimeZone timeZone) {
michael@0 317 for (final Iterator i = iterator(); i.hasNext();) {
michael@0 318 final Period period = (Period) i.next();
michael@0 319 period.setTimeZone(timeZone);
michael@0 320 }
michael@0 321 this.timezone = timeZone;
michael@0 322 this.utc = false;
michael@0 323 }
michael@0 324
michael@0 325 /**
michael@0 326 * @return Returns the timeZone.
michael@0 327 */
michael@0 328 public final TimeZone getTimeZone() {
michael@0 329 return timezone;
michael@0 330 }
michael@0 331
michael@0 332 /**
michael@0 333 * {@inheritDoc}
michael@0 334 */
michael@0 335 public final boolean addAll(Collection arg0) {
michael@0 336 for (Iterator i = arg0.iterator(); i.hasNext();) {
michael@0 337 add(i.next());
michael@0 338 }
michael@0 339 return true;
michael@0 340 }
michael@0 341
michael@0 342 /**
michael@0 343 * {@inheritDoc}
michael@0 344 */
michael@0 345 public final void clear() {
michael@0 346 periods.clear();
michael@0 347 }
michael@0 348
michael@0 349 /**
michael@0 350 * {@inheritDoc}
michael@0 351 */
michael@0 352 public final boolean contains(Object o) {
michael@0 353 return periods.contains(o);
michael@0 354 }
michael@0 355
michael@0 356 /**
michael@0 357 * {@inheritDoc}
michael@0 358 */
michael@0 359 public final boolean containsAll(Collection arg0) {
michael@0 360 return periods.containsAll(arg0);
michael@0 361 }
michael@0 362
michael@0 363 /**
michael@0 364 * {@inheritDoc}
michael@0 365 */
michael@0 366 public final boolean isEmpty() {
michael@0 367 return periods.isEmpty();
michael@0 368 }
michael@0 369
michael@0 370 /**
michael@0 371 * {@inheritDoc}
michael@0 372 */
michael@0 373 public final Iterator iterator() {
michael@0 374 return periods.iterator();
michael@0 375 }
michael@0 376
michael@0 377 /**
michael@0 378 * {@inheritDoc}
michael@0 379 */
michael@0 380 public final boolean remove(Object o) {
michael@0 381 return periods.remove(o);
michael@0 382 }
michael@0 383
michael@0 384 /**
michael@0 385 * {@inheritDoc}
michael@0 386 */
michael@0 387 public final boolean removeAll(Collection arg0) {
michael@0 388 return periods.removeAll(arg0);
michael@0 389 }
michael@0 390
michael@0 391 /**
michael@0 392 * {@inheritDoc}
michael@0 393 */
michael@0 394 public final boolean retainAll(Collection arg0) {
michael@0 395 return periods.retainAll(arg0);
michael@0 396 }
michael@0 397
michael@0 398 /**
michael@0 399 * {@inheritDoc}
michael@0 400 */
michael@0 401 public final int size() {
michael@0 402 return periods.size();
michael@0 403 }
michael@0 404
michael@0 405 /**
michael@0 406 * {@inheritDoc}
michael@0 407 */
michael@0 408 public final Object[] toArray() {
michael@0 409 return periods.toArray();
michael@0 410 }
michael@0 411
michael@0 412 /**
michael@0 413 * {@inheritDoc}
michael@0 414 */
michael@0 415 public final Object[] toArray(Object[] arg0) {
michael@0 416 return periods.toArray(arg0);
michael@0 417 }
michael@0 418
michael@0 419 public final boolean equals(Object obj) {
michael@0 420 if (!getClass().isAssignableFrom(obj.getClass())) {
michael@0 421 return false;
michael@0 422 }
michael@0 423 final PeriodList rhs = (PeriodList) obj;
michael@0 424 return new EqualsBuilder().append(periods, rhs.periods)
michael@0 425 .append(timezone, rhs.timezone)
michael@0 426 .append(utc, utc)
michael@0 427 .isEquals();
michael@0 428 }
michael@0 429
michael@0 430 public final int hashCode() {
michael@0 431 return new HashCodeBuilder().append(periods)
michael@0 432 .append(timezone)
michael@0 433 .append(utc)
michael@0 434 .toHashCode();
michael@0 435 }
michael@0 436 }

mercurial