001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.util.time;
018
019import org.apache.wicket.util.lang.Objects;
020
021/**
022 * Immutable class which represents an interval of time with a beginning and an end. The beginning
023 * value is inclusive and the end value is exclusive. In other words, the time frame of 1pm to 2pm
024 * includes 1pm, but not 2pm. 1:59:59 is the last value in the <code>TimeFrame</code>.
025 * <p>
026 * <code>TimeFrame</code>s can be constructed by calling the <code>valueOf</code> static factory
027 * methods <code>valueOf(Time, Time)</code> (yielding a <code>TimeFrame</code> between two absolute
028 * times) and <code>valueOf(Time, Duration)</code> yielding a <code>TimeFrame</code> starting at an
029 * absolute time and having a given length.
030 * <p>
031 * The start and end of a <code>TimeFrame</code> can be retrieved by calling <code>getStart</code>
032 * and <code>getEnd</code>. Its duration can be retrieved by calling <code>getDuration</code>.
033 * <p>
034 * The <code>contains(Time)</code> method can be called to determine if a <code>TimeFrame</code>
035 * contains a given point in time. The <code>overlaps(TimeFrame)</code> method can be called to
036 * determine if two <code>TimeFrames</code> overlap.
037 * <p>
038 * The <code>eachDay(TimeOfDay, TimeOfDay)</code> will return a <code>TimeFrameSource</code> which
039 * generates a <code>TimeFrame</code> using the two times of day. In other words, if the start is
040 * 3pm and the end is 4pm, the <code>TimeFrameSource</code> returned will yield 3-4pm on the day it
041 * is called (each day).
042 * 
043 * @author Jonathan Locke
044 * @since 1.2.6
045 * 
046 * @deprecated Since Wicket 9 this class is obsolete and no more used. It will be removed in Wicket 10
047 */
048@Deprecated
049public final class TimeFrame implements ITimeFrameSource
050{
051        private static final long serialVersionUID = 1L;
052
053        /** end of this <code>TimeFrame</code> */
054        private final Time end;
055
056        /** beginning of this <code>TimeFrame</code> */
057        private final Time start;
058
059        /**
060         * Creates an <code>ITimeFrameSource</code> source for start and end <code>TimeOfDay</code>s.
061         * For example, called with 3pm and 5pm as parameters, the <code>TimeFrame</code> source
062         * returned would produce <code>TimeFrame</code> objects representing 3pm-5pm on whatever day it
063         * is when the caller calls the <code>TimeFrameSource</code> interface.
064         * 
065         * @param startTimeOfDay
066         *            the start <code>TimeOfDay</code> for this <code>TimeFrame</code> each day
067         * @param endTimeOfDay
068         *            the end <code>TimeOfDay</code> for this <code>TimeFrame</code> each day
069         * @return a <code>TimeFrameSource</code> which will return the specified <code>TimeFrame</code>
070         *         each day
071         */
072        public static ITimeFrameSource eachDay(final TimeOfDay startTimeOfDay,
073                final TimeOfDay endTimeOfDay)
074        {
075                check(startTimeOfDay, endTimeOfDay);
076
077                return new ITimeFrameSource()
078                {
079                        private static final long serialVersionUID = 1L;
080
081                        @Override
082                        public TimeFrame getTimeFrame()
083                        {
084                                return new TimeFrame(Time.valueOf(startTimeOfDay), Time.valueOf(endTimeOfDay));
085                        }
086                };
087        }
088
089        /**
090         * Creates a <code>TimeFrame</code> for a start <code>Time</code> and <code>Duration</code>.
091         * 
092         * @param start
093         *            the start <code>Time</code>
094         * @param duration
095         *            the <code>Duration</code>
096         * @return the <code>TimeFrame</code>
097         * @throws IllegalArgumentException
098         *             thrown if start <code>Time</code> value is before end <code>Time</code> value
099         */
100        public static TimeFrame valueOf(final Time start, final Duration duration)
101        {
102                return new TimeFrame(start, start.add(duration));
103        }
104
105        /**
106         * Creates a <code>TimeFrame</code> for given start and end <code>Time</code>s.
107         * 
108         * @param start
109         *            the start <code>Time</code>
110         * @param end
111         *            the end <code>Time</code>
112         * @return the <code>TimeFrame</code>
113         * @throws IllegalArgumentException
114         *             thrown if start <code>Time</code> value is before end <code>Time</code> value
115         */
116        public static TimeFrame valueOf(final Time start, final Time end)
117        {
118                return new TimeFrame(start, end);
119        }
120
121        /**
122         * Checks consistency of start and end <code>AbstractTimeValue</code> values, ensuring that the
123         * end value is less than the start value.
124         * 
125         * @param start
126         *            start <code>AbstractTimeValue</code> value
127         * @param end
128         *            end <code>AbstractTimeValue</code> value
129         * @throws IllegalArgumentException
130         *             thrown if end is less than start
131         */
132        private static void check(final AbstractTimeValue start, final AbstractTimeValue end)
133        {
134                // Throw illegal argument exception if end is less than start
135                if (end.lessThan(start))
136                {
137                        throw new IllegalArgumentException("Start time of time frame " + start +
138                                " was after end time " + end);
139                }
140        }
141
142        /**
143         * Private constructor to force use of static factory methods.
144         * 
145         * @param start
146         *            the start <code>Time</code>
147         * @param end
148         *            the end <code>Time</code>
149         * @throws IllegalArgumentException
150         *             thrown if start <code>Time</code> value is before end <code>Time</code> value
151         */
152        private TimeFrame(final Time start, final Time end)
153        {
154                check(start, end);
155                this.start = start;
156                this.end = end;
157        }
158
159        /**
160         * Determines if this <code>TimeFrame</code> contains a given point in time.
161         * 
162         * @param time
163         *            the <code>Time</code> to check
164         * @return <code>true</code> if this <code>TimeFrame</code> contains the given time
165         */
166        public boolean contains(final Time time)
167        {
168                return (start.equals(time) || start.before(time)) && end.after(time);
169        }
170
171        /**
172         * Retrieves the <code>Duration</code> of this <code>TimeFrame</code>.
173         * 
174         * @return the <code>Duration</code> of this <code>TimeFrame</code>
175         */
176        public Duration getDuration()
177        {
178                return end.subtract(start);
179        }
180
181        /**
182         * Retrieves the end <code>Time</code> of this <code>TimeFrame</code>.
183         * 
184         * @return the end of this <code>TimeFrame</code>
185         */
186        public Time getEnd()
187        {
188                return end;
189        }
190
191        /**
192         * Retrieves the start <code>Time</code> of this <code>TimeFrame</code>.
193         * 
194         * @return the start of this <code>TimeFrame</code>
195         */
196        public Time getStart()
197        {
198                return start;
199        }
200
201        /**
202         * Implementation of <code>ITimeFrameSource</code> that simply returns this
203         * <code>TimeFrame</code>.
204         * 
205         * @return this <code>TimeFrame</code>
206         */
207        @Override
208        public TimeFrame getTimeFrame()
209        {
210                return this;
211        }
212
213        /**
214         * Determines if two <code>TimeFrame</code>s overlap.
215         * 
216         * @param timeframe
217         *            the <code>TimeFrame</code> to test
218         * @return <code>true</code> if the given <code>TimeFrame</code> overlaps this one
219         */
220        public boolean overlaps(final TimeFrame timeframe)
221        {
222                return contains(timeframe.start) || contains(timeframe.end) || timeframe.contains(start) ||
223                        timeframe.contains(end);
224        }
225
226        @Override
227        public int hashCode()
228        {
229                return Objects.hashCode(start, end);
230        }
231
232        @Override
233        public boolean equals(final Object obj)
234        {
235                if (this == obj)
236                {
237                        return true;
238                }
239                if (obj == null)
240                {
241                        return false;
242                }
243                if (getClass() != obj.getClass())
244                {
245                        return false;
246                }
247                TimeFrame other = (TimeFrame)obj;
248                return Objects.equal(start, other.start) && Objects.equal(end, other.end);
249        }
250
251        /**
252         * Converts this <code>TimeFrame</code> to a <code>String</code> representation.
253         * 
254         * @return a <code>String</code> representation of this object
255         */
256        @Override
257        public String toString()
258        {
259                return "[start=" + start + ", end=" + end + "]";
260        }
261}