001    // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 
002    // The Molly framework is freely distributable under the terms of an
003    // MIT-style license. For details, see the molly pages web site at:
004    // http://www.mollypages.org/. Use, modify, have fun !
005    
006    package fc.util;
007    
008    import java.util.*;
009    
010    
011    /** A set of date ranges. **/
012    public class DateRangeSet
013    {
014    DateRange seedRange;  
015    List union;
016    List intersect;
017    
018    /**
019    Constructs a new DateRangeSet with the initial set containing
020    only the specified DateRange
021    
022    @param  cs  the initial DateRange
023    **/
024    public DateRangeSet(DateRange cs) 
025      {
026      Argcheck.notnull(cs);
027      seedRange = cs; 
028      //do _not_ lazy instantiate, otherwise have to put in
029      //null checks in other places
030      union = new ArrayList();
031      intersect = new ArrayList();
032      }
033    
034    /**
035    Adds this specified range as a union to the existing set of 
036    ranges (for purposes of {@link inRange(char)} method). 
037    Overlapping ranges are ok.
038    
039    @param  cs  a DateRange to unite with
040    @throws IllegalArgumentException 
041          if the specified range was null
042    **/
043    public void union(DateRange r) 
044      {
045      Argcheck.notnull(r);
046      union.add(r);
047      }
048    
049    /**
050    Adds the specified range as an intersection to the existing
051    ranges (for purposes of {@link inRange(char)} method). 
052    Overlapping ranges are ok. 
053    
054    @param  r the range to add
055    **/
056    public void intersection(DateRange r) 
057      {
058      Argcheck.notnull(r);  
059      intersect.add(r);
060      }
061    
062    /** 
063    Consider a set of ranges <tt>A</tt>, <tt>B</tt> added as a union
064    (logical <tt>or</tt>) and ranges <tt>C</tt> and <tt>D</tt> added as an
065    intersection (logical <tt>and</tt>). A character <tt>c</tt> is in range if
066    it exists in:
067    
068    <blockquote> <tt>
069    
070    (A.inRange(c) || B.inRange(c) || ...) && C.inRange(c) && D.inRange(c)
071    && ...
072    
073    </tt></blockquote> 
074    
075    This can be generalized to an arbitrary number of sub ranges. If
076    intersection or union ranges don't exist, then they are not
077    considered in the above expression. Note, the interaction may be
078    subtle if any of the ranges (<tt>A, B, C...</tt>etc) are
079    individually negated because in that case the inRange method for
080    that negated range would return true if the specified character
081    was <b>not</b> in that range.
082    
083    @return <tt>true</tt> if the passed in character is allowed by this 
084        set of ranges.
085    
086    **/
087    public boolean inRange(Date val) 
088      {
089      boolean result = seedRange.inRange(val);
090      for (int i = 0, n = union.size(); i < n; i++) {
091        DateRange item = (DateRange) union.get(i);
092        result = result || item.inRange(val);
093        }   
094      for (int i = 0, n = intersect.size(); i < n; i++) {
095        DateRange item = (DateRange) intersect.get(i);
096        result = result && item.inRange(val);
097        } 
098      return result;
099      }
100    
101    public String toString() {
102      StringBuffer buf = new StringBuffer(128); 
103      buf.append("DateRangeSet:["); 
104      
105      if (intersect.size() > 0)
106        buf.append("(");
107    
108      buf.append(seedRange);
109    
110      int len = union.size();
111      if (len > 0) 
112          {
113          buf.append(" || " );
114          for (int i = 0; i < len; i++) {
115            buf.append(union.get(i).toString());
116            if (i < (len-1))
117              buf.append(" || ");
118            }     
119        }
120        
121      len = intersect.size();
122      if (len > 0) 
123        {
124          buf.append(") && " );     
125        for (int i = 0; i < len; i++) {
126          buf.append(intersect.get(i).toString());
127          if (i < (len-1))
128            buf.append(" && ");
129          }     
130        }
131        
132      buf.append("]");
133      return buf.toString();
134      }
135    
136    
137    public static void main(String[] args)
138      {
139      Date now = new Date();
140    
141      Calendar cal = Calendar.getInstance();
142      Date d1 = cal.getTime();
143      //back 1 month
144      cal.add(Calendar.MONTH, -1);
145      Date d2 = cal.getTime();
146         
147      DateRange r = new DateRange(d2, d1);
148    
149      cal.setTime(now);
150      cal.add(Calendar.MONTH, -3);
151      Date d3 = cal.getTime(); 
152      cal.setTime(now);
153      cal.add(Calendar.MONTH, -6);
154      Date d4 = cal.getTime(); 
155    
156      DateRange r2 = new DateRange(d4, d3);
157    
158      DateRangeSet crs = new DateRangeSet(r);
159      crs.union(r2);
160      System.out.println("constructed: " + crs);
161      test(crs);
162      
163      cal.setTime(now);
164      cal.add(Calendar.MONTH, -4);
165      d3 = cal.getTime();
166      cal.setTime(now);
167      cal.add(Calendar.MONTH, -5);
168      d4 = cal.getTime();
169      r2 = new DateRange(d4, d3);
170      crs.intersection(r2);
171      System.out.println("constructed: " + crs);
172      test(crs);
173      } 
174      
175    private static void test(DateRangeSet crs) 
176      { 
177      Calendar cal = Calendar.getInstance();
178      cal.add(Calendar.MONTH, -5);
179      Date d = cal.getTime(); 
180      System.out.println("in range: " + d + "=" + crs.inRange(d));
181      cal.setTime(new Date());
182      cal.add(Calendar.MONTH, 3);
183      d = cal.getTime(); 
184      System.out.println("in range: " + d + "=" + crs.inRange(d));
185      } 
186    }