001    /*
002     * Copyleft notice: This is public-domain software and documentation
003     * with no restrictions of any kind.
004     * Please feel free to use any of it in any way you want.
005     * This work is distributed in the hope that it will be useful,
006     * but WITHOUT ANY WARRANTY; without even the implied warranty of
007     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
008     */
009    
010    
011    package time;
012    
013    import java.util.*;
014    
015    /**
016     * A TimeMask is a sorted set of <tt>TimeField</tt> which is used to defined <tt>Time</tt>.
017     * It defines a format which will be used to manipulate <tt>Time</tt>.
018     *
019     *
020     *
021     * @author Arnaud Roques
022     *
023     *
024     * @has - "has" n time.TimeField<V>
025     * @stereotype "SortedSet"
026     *
027     */
028    public final class TimeMask implements SortedSet<TimeField>
029    {
030            private final SortedSet<TimeField> fields;
031            
032            /**
033             * Create a new TimeMask from several TimeField.
034             *
035             * The <tt>TimeFields</tt> will be sorted. It is recommanded that
036             * all <tt>TimeField</tt> belongs to the same chronology, although this
037             * is not mandatory.
038             *
039             * A <tt>TimeMask</tt> that mixes several <tt>TimeField</tt> from different
040             * chronologies is likely to be useless.
041             *
042             * @param       f               all TimeField used by the TimeMask.
043             *
044             * @throws NullPointerException if one or more of the TimeField is <tt>null</tt>.
045             */
046            public TimeMask(TimeField... f)
047            {
048                    this(Arrays.asList(f));
049            }
050            
051            /**
052             * Create a new TimeMask from several TimeField.
053             *
054             * The <tt>TimeFields</tt> will be sorted. It is recommanded that
055             * all <tt>TimeField</tt> belongs to the same chronology, although this
056             * is not mandatory.
057             *
058             * A <tt>TimeMask</tt> that mixes several <tt>TimeField</tt> from different
059             * chronologies is likely to be useless.
060             *
061             * @param       s               all TimeField used by the TimeMask.
062             *
063             * @throws NullPointerException if one or more of the TimeField is <tt>null</tt>.
064             */
065            public TimeMask(Collection<TimeField> s)
066            {
067                    for (TimeField f : s)
068                            if (f==null) throw new NullPointerException();
069                            
070                    fields = Collections.unmodifiableSortedSet(new TreeSet<TimeField>(s));
071            }
072            
073            
074            
075            /**
076             * Create a new TimeMask from several other TimeMask.
077             *
078             * All <tt>TimeField</tt> from every <tt>TimeMask</tt> are collected in
079             * the new <tt>TimeMask</tt>.
080             *
081             * @param       masks   all TimeMask that will be merged in the new TimeMask.
082             *
083             * @throws NullPointerException if one or more of the TimeMask is <tt>null</tt>.
084             */
085            public TimeMask(TimeMask... masks)
086            {
087                    SortedSet<TimeField> s = new TreeSet<TimeField>();
088                    for (TimeMask m : masks)
089                            s.addAll(m.fields);
090                    fields = Collections.unmodifiableSortedSet(s);
091            }
092    
093            /**
094             * Create a new TimeMask by adding TimeField to an existing TimeMask.
095             *
096             * @param mask  the original TimeMask
097             * @param f             all TimeField to add in the new TimeMask
098             *
099             * @throws NullPointerException if <tt>mask</tt> is <tt>null</tt>.
100             * @throws NullPointerException if one or more of the TimeField is <tt>null</tt>.
101             */
102            public TimeMask(TimeMask mask, TimeField... f)
103            {
104                    this(mask, new TimeMask(f));
105            }
106            
107            
108            /**
109             * Return all TimeField contained in this TimeMask.
110             *
111             * @return all TimeField contained in this TimeMask.
112             */
113            public SortedSet<TimeField> getFields()
114            {
115                    return fields;
116            }
117            
118            
119            /**
120             * Return the number of TimeFields in the TimeMask.
121             *
122             * @return number of TimeFields in the TimeMask.
123             */
124            public int size()
125            {
126                    return fields.size();
127            }
128            
129            
130            /**
131             * Compares this TimeMask to the specified object.
132             * The result is <tt>true</tt> if and only if the argument is not <tt>null</tt>
133             * and is a TimeMask that have the same sequence of TimeField as this object.
134             *
135             * @param anObject - the object to compare this TimeMask against.
136             * @hidden
137             */
138            @Override
139            public boolean equals(Object anObject)
140            {
141                    if (!(anObject instanceof TimeMask)) return false;
142                    TimeMask other = (TimeMask) anObject;
143                    return fields.equals(other.fields);
144            }
145            
146            /**
147             * Returns a hash code value for this object.
148             * @hidden
149             */
150            @Override
151            public int hashCode()
152            {
153                    return fields.hashCode();
154            }
155            
156            /**
157             * Convert this TimeMask to a String.
158             *
159             * @return      a String describing this TimeMask
160             * @hidden
161             */
162            @Override
163            public String toString()
164            {
165                    return super.toString()+" "+fields;
166            }
167            
168            
169            
170            /**
171             * Return the <i>less significant</i> TimeField of this TimeMask.
172             *
173             * @return the <i>less significant</i> TimeField of this TimeMask.
174             * @hidden
175             */
176            public TimeField last()
177            {
178                    return fields.last();
179            }
180    
181            /**
182             * Return the <i>most significant</i> TimeField of this TimeMask.
183             *
184             * @return the <i>most significant</i> TimeField of this TimeMask.
185             * @hidden
186             */
187            public TimeField first()
188            {
189                    return fields.first();
190            }
191            
192            /**
193             * Build a new TimeMask with TimeField of this TimeMask which are <i>less
194             * significant</i> (inclusive) than a TimeField.
195             *
196             * @param fromField     TimeField to compare with.
197             *
198             * @return new TimeMask with some of the <i>less significant</i> TimeField of this TimeMask.
199             *
200             * @throws NullPointerException if <tt>fromField</tt> is <tt>null</tt>.
201             * @throws IllegalArgumentException if <tt>fromField</tt> is not in the range of this TimeMask.
202             * @hidden
203             */
204            public TimeMask tailSet(TimeField fromField)
205            {
206                    return new TimeMask(fields.tailSet(fromField));
207            }
208    
209    
210            /**
211             * Build a new TimeMask with TimeField of this TimeMask which are <i>more
212             * significant</i> (exclusive) than a TimeField.
213             *
214             * @param toField       TimeField to compare with.
215             *
216             * @return new TimeMask with some of the <i>more significant</i> TimeField of this TimeMask.
217             *
218             * @throws NullPointerException if <tt>toField</tt> is <tt>null</tt>.
219             * @throws IllegalArgumentException if <tt>toField</tt> is not in the range of this TimeMask.
220             * @hidden
221             */
222            public TimeMask headSet(TimeField toField)
223            {
224                    return new TimeMask(fields.headSet(toField));
225            }
226    
227    
228            /**
229             * Build a new TimeMask with some TimeField of this TimeMask.
230             *
231             * Only TimeField that are:
232             * <ul>
233             * <li><i>less significant</i> than <tt>fromField</tt> (inclusive)
234             * <li><i>more significant</i> than <tt>toField</tt> (exclusive)
235             * </ul>
236             *
237             * will be in the returned TimeMask.
238             *
239             *
240             * @param fromField             lower limit of the TimeField.
241             * @param toField               uppder limit TimeField.
242             *
243             * @return new TimeMask with some of the TimeField of this TimeMask.
244             *
245             * @throws NullPointerException if <tt>fromField</tt> or <tt>toField</tt> is <tt>null</tt>.
246             * @throws IllegalArgumentException if <tt>fromField</tt> or <tt>toField</tt> is not in the range of this TimeMask.
247             * @throws IllegalArgumentException if <tt>fromField</tt> is greater than <tt>toField</tt>.
248             * @hidden
249             */
250            public TimeMask subSet(TimeField fromField, TimeField toField)
251            {
252                    return new TimeMask(fields.subSet(fromField, toField));
253            }
254            
255            
256            /**
257             * Return <tt>null</tt>, as natural order of TimeField are used in TimeMask.
258             *
259             * @return      <tt>null</tt>
260             * @hidden
261             */
262            public Comparator<? super TimeField> comparator()
263            {
264                    return null;
265            }
266            
267            /**
268             * As <tt>TimeMask</tt> are immutable, throws a <tt>UnsupportedOperationException</tt>.
269             * @hidden
270             */
271            public void clear()
272            {
273                    throw new UnsupportedOperationException();
274            }
275            
276            /**
277             * As <tt>TimeMask</tt> are immutable, throws a <tt>UnsupportedOperationException</tt>.
278             * @hidden
279             */
280            public boolean removeAll(Collection<?> c)
281            {
282                    throw new UnsupportedOperationException();
283            }
284            
285            /**
286             * As <tt>TimeMask</tt> are immutable, throws a <tt>UnsupportedOperationException</tt>.
287             * @hidden
288             */
289            public boolean retainAll(Collection<?> c)
290            {
291                    throw new UnsupportedOperationException();
292            }
293            
294            /**
295             * As <tt>TimeMask</tt> are immutable, throws a <tt>UnsupportedOperationException</tt>.
296             * @hidden
297             */
298            public boolean addAll(Collection<? extends TimeField> c)
299            {
300                    throw new UnsupportedOperationException();
301            }
302            
303    
304            /**
305             * As <tt>TimeMask</tt> are immutable, throws a <tt>UnsupportedOperationException</tt>.
306             *
307             * @see #remove(TimeField... f)
308             * @hidden
309             */
310            public boolean remove(Object o)
311            {
312                    throw new UnsupportedOperationException();
313            }
314            
315            /**
316             * Build a new TimeMask by removing some TimeField of this TimeMask.
317             *
318             * @param       f       all TimeField to remove from this TimeField.
319             *
320             * @return      a new TimeMask that contains less TimeField than this TimeMask.
321             *
322             * @throws IllegalArgumentException if one or more of the TimeField are not contained
323             * in the TimeMask.
324             */
325            public TimeMask remove(TimeField... f)
326            {
327                    TreeSet<TimeField> ts = new TreeSet<TimeField>(fields);
328                    Collection<TimeField> toRemove = Arrays.asList(f);
329                    
330                    if (getFields().containsAll(toRemove)==false)
331                            throw new IllegalArgumentException();
332                            
333                    ts.removeAll(toRemove);
334                    return new TimeMask(ts);
335            }
336                    
337            
338            
339            /**
340             * As <tt>TimeMask</tt> are immutable, throws a <tt>UnsupportedOperationException</tt>.
341             *
342             * @see #TimeMask(TimeMask mask, TimeField... f)
343             * @hidden
344             */
345            public boolean add(TimeField o)
346            {
347                    throw new UnsupportedOperationException();
348            }
349            
350            /**
351             * Returns <tt>true</tt> if this TimeMask contains all of the elements
352             * in the specified collection.
353             *
354             * @param c collection to be checked for containment in this TimeMask.
355             *
356             * @return <tt>true</tt> if this TimeMask contains all of the elements
357             * in the specified collection.
358             * @hidden
359             */
360            public boolean containsAll(Collection<?> c)
361            {
362                    return fields.containsAll(c);
363            }
364            
365            /**
366             * Returns <tt>true</tt> if this TimeMask contains the specified element.
367             *
368             * @param obj object to be checked for containment in this TimeMask.
369             * @hidden
370             */
371            public boolean contains(Object obj)     
372            {
373                    return fields.contains(obj);
374            }
375            
376            /**
377             *
378             * @hidden
379             */
380            public <T> T[] toArray(T[] a)
381            {
382                    return fields.toArray(a);
383            }
384            
385            /**
386             *
387             * @hidden
388             */
389            public Object[] toArray()
390            {
391                    return fields.toArray();
392            }
393            
394            
395            /**
396             * Return an iterator over TimeField contained in this TimeMask.
397             * @hidden
398             */
399            public Iterator<TimeField> iterator()
400            {
401                    return fields.iterator();
402            }
403            
404            /**
405             * Return <tt>true</tt> is this TimeMask contains no TimeField.
406             *
407             * @return <tt>true</tt> is this TimeMask contains no TimeField.
408             * @hidden
409             */
410            public boolean isEmpty()
411            {
412                    return fields.isEmpty();
413            }
414            
415            
416            
417            
418    }
419