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
006package fc.util;
007
008import java.util.*;
009
010
011/** A set of date ranges. **/
012public class DateRangeSet
013{
014DateRange seedRange;  
015List union;
016List intersect;
017
018/**
019Constructs a new DateRangeSet with the initial set containing
020only the specified DateRange
021
022@param  cs  the initial DateRange
023**/
024public 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/**
035Adds this specified range as a union to the existing set of 
036ranges (for purposes of {@link inRange(char)} method). 
037Overlapping ranges are ok.
038
039@param  cs  a DateRange to unite with
040@throws IllegalArgumentException 
041      if the specified range was null
042**/
043public void union(DateRange r) 
044  {
045  Argcheck.notnull(r);
046  union.add(r);
047  }
048
049/**
050Adds the specified range as an intersection to the existing
051ranges (for purposes of {@link inRange(char)} method). 
052Overlapping ranges are ok. 
053
054@param  r the range to add
055**/
056public void intersection(DateRange r) 
057  {
058  Argcheck.notnull(r);  
059  intersect.add(r);
060  }
061
062/** 
063Consider 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
065intersection (logical <tt>and</tt>). A character <tt>c</tt> is in range if
066it 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
075This can be generalized to an arbitrary number of sub ranges. If
076intersection or union ranges don't exist, then they are not
077considered in the above expression. Note, the interaction may be
078subtle if any of the ranges (<tt>A, B, C...</tt>etc) are
079individually negated because in that case the inRange method for
080that negated range would return true if the specified character
081was <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**/
087public 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
101public 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
137public 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  
175private 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}