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.

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

mercurial