View Javadoc

1   /*
2    * Copyright (C) 2007 Alf Mikula
3    * 
4    * This file is part of PromoteGo.
5    *
6    * PromoteGo is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * PromoteGo is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with PromoteGo.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  package org.promotego.logic.storehours;
20  
21  import java.util.Collections;
22  import java.util.Iterator;
23  import java.util.LinkedList;
24  import java.util.List;
25  
26  import org.apache.commons.lang.math.IntRange;
27  
28  class WeeklyHours
29  {
30  	private static IntRangeComparator s_intRangeComparator = new IntRangeComparator();
31  	
32  	private List<IntRange> m_ranges;
33  	
34  	public WeeklyHours()
35  	{
36  		m_ranges = new LinkedList<IntRange>();
37  	}
38  	
39  	public boolean isOpen(IntRange theRange)
40  	{
41  		if (theRange.getMinimumInteger() >= StoreHours.SECONDS_IN_WEEK)
42  		{
43  			throw new IllegalArgumentException("Range must begin with a number less than the number of seconds in a week");
44  		}
45  
46  		if (theRange.getMaximumInteger() > StoreHours.SECONDS_IN_WEEK)
47  		{
48  			// Range needs to be split before checking
49  			IntRange range1 = new IntRange(theRange.getMinimumInteger(), StoreHours.SECONDS_IN_WEEK);
50  			
51  			IntRange range2 = new IntRange(0, theRange.getMaximumInteger()-StoreHours.SECONDS_IN_WEEK);
52  			return isOpen(range1) && isOpen(range2);
53  		}
54  		else
55  		{
56  			int searchResult = Collections.binarySearch(m_ranges, theRange, s_intRangeComparator);
57  			
58  			if (searchResult >= 0)
59  			{
60  				IntRange foundRange = m_ranges.get(searchResult);
61  				
62  				if (foundRange.containsRange(theRange))
63  				{
64  					return true;
65  				}
66  			}
67  			
68  			return false;
69  		}
70  	}
71  	
72  	public void addRange(IntRange theRange)
73  	{
74  		if (theRange.getMinimumInteger() >= StoreHours.SECONDS_IN_WEEK)
75  		{
76  			throw new IllegalArgumentException("Range must begin with a number less than the number of seconds in a week");
77  		}
78  
79  		if (theRange.getMaximumInteger() > StoreHours.SECONDS_IN_WEEK)
80  		{
81  			// Range needs to be split before adding
82  			IntRange range1 = new IntRange(theRange.getMinimumInteger(), StoreHours.SECONDS_IN_WEEK);
83  			addRange(range1);
84  			
85  			IntRange range2 = new IntRange(0, theRange.getMaximumInteger()-StoreHours.SECONDS_IN_WEEK);
86  			addRange(range2);
87  		}
88  		else
89  		{
90  			addRangeInternal(theRange);
91  		}
92  	}
93  
94  	/***
95  	 * @param theRange
96  	 */
97  	private void addRangeInternal(IntRange theRange)
98  	{
99  		int searchResult = Collections.binarySearch(m_ranges, theRange, s_intRangeComparator);
100 		
101 		if (searchResult >= 0)
102 		{
103 			// The given range intersects with the range at the result index.
104 			IntRange currentRange = m_ranges.get(searchResult);
105 			if (currentRange.containsRange(theRange))
106 			{
107 				// Nothing to do: the range provided doesn't add any open time.
108 			}
109 			else if (theRange.containsRange(currentRange))
110 			{
111 				// Replace the range in the list with the new range
112 				m_ranges.remove(searchResult);
113 				m_ranges.add(searchResult, theRange);
114 			}
115 			else
116 			{
117 				// Create a new range with the minimum of the two minimums and the maximum of the two maximums.
118 				int newMinimum = minimum(currentRange.getMinimumInteger(), theRange.getMinimumInteger());
119 				int newMaximum = maximum(currentRange.getMaximumInteger(), theRange.getMaximumInteger());
120 				IntRange newRange = new IntRange(newMinimum, newMaximum);
121 				m_ranges.remove(searchResult);
122 				m_ranges.add(searchResult, newRange);
123 			}
124 		}
125 		else
126 		{
127 			// No intersection, and search has returned -(insertionPoint + 1)
128 			int insertionPoint = -searchResult - 1;
129 			m_ranges.add(insertionPoint, theRange);
130 		}
131 	}
132 	
133 	private int minimum(int a, int b)
134 	{
135 		if (a < b)
136 		{
137 			return a;
138 		}
139 		else
140 		{
141 			return b;
142 		}
143 	}
144 	
145 	private int maximum(int a, int b)
146 	{
147 		if (a > b)
148 		{
149 			return a;
150 		}
151 		else
152 		{
153 			return b;
154 		}
155 	}
156 
157 	public boolean equals(Object anotherObject)
158 	{
159 		if (!(anotherObject instanceof WeeklyHours))
160 		{
161 			return false;
162 		}
163 		
164 		WeeklyHours otherHours = (WeeklyHours)anotherObject;
165 		
166 		if (m_ranges.size() != otherHours.m_ranges.size())
167 		{
168 			return false;
169 		}
170 		
171 		// Because we merge ranges that overlap, and we maintain them in sorted
172 		// order, there will be the same number of ranges in each list, and they
173 		// will have exactly the same values and be listed in the same order.
174 		Iterator<IntRange> myIterator = m_ranges.iterator();
175 		Iterator<IntRange> otherIterator = otherHours.m_ranges.iterator();
176 		while(myIterator.hasNext())
177 		{
178 			if (!myIterator.next().equals(otherIterator.next()))
179 			{
180 				return false;
181 			}
182 		}
183 		
184 		return true;
185 	}
186 	
187 	public int hashCode()
188 	{
189 		int retval = 0;
190 		
191 		for (IntRange thisRange : m_ranges)
192 		{
193 			retval ^= thisRange.hashCode();
194 		}
195 		
196 		return retval;
197 	}
198 }