001/*
002 * Zmanim Java API
003 * Copyright (C) 2004-2020 Eliyahu Hershfeld
004 *
005 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
006 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option)
007 * any later version.
008 *
009 * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied
010 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
011 * details.
012 * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to
013 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA,
014 * or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
015 */
016package com.kosherjava.zmanim.util;
017
018import java.util.Comparator;
019import java.util.Date;
020
021/**
022 * A wrapper class for a astronomical times / <em>zmanim</em> that is mostly intended to allow sorting collections of astronomical times.
023 * It has fields for both date/time and duration based <em>zmanim</em>, name / labels as well as a longer description or explanation of a
024 * <em>zman</em>.
025 * 
026 * Here is an example of various ways of sorting <em>zmanim</em>.
027 * <p>First create the Calendar for the location you would like to calculate:
028 * 
029 * <pre style="background: #FEF0C9; display: inline-block;">
030 * String locationName = &quot;Lakewood, NJ&quot;;
031 * double latitude = 40.0828; // Lakewood, NJ
032 * double longitude = -74.2094; // Lakewood, NJ
033 * double elevation = 20; // optional elevation correction in Meters
034 * // the String parameter in getTimeZone() has to be a valid timezone listed in {@link java.util.TimeZone#getAvailableIDs()}
035 * TimeZone timeZone = TimeZone.getTimeZone(&quot;America/New_York&quot;);
036 * GeoLocation location = new GeoLocation(locationName, latitude, longitude, elevation, timeZone);
037 * ComplexZmanimCalendar czc = new ComplexZmanimCalendar(location);
038  * Zman sunset = new Zman(czc.getSunset(), "Sunset");
039 * Zman shaah16 = new Zman(czc.getShaahZmanis16Point1Degrees(), "Shaah zmanis 16.1");
040 * Zman sunrise = new Zman(czc.getSunrise(), "Sunrise");
041 * Zman shaah = new Zman(czc.getShaahZmanisGra(), "Shaah zmanis GRA");
042 * ArrayList&lt;Zman&gt; zl = new ArrayList&lt;Zman&gt;();
043 * zl.add(sunset);
044 * zl.add(shaah16);
045 * zl.add(sunrise);
046 * zl.add(shaah);
047 * //will sort sunset, shaah 1.6, sunrise, shaah GRA
048 * System.out.println(zl);
049 * Collections.sort(zl, Zman.DATE_ORDER);
050 * // will sort sunrise, sunset, shaah, shaah 1.6 (the last 2 are not in any specific order)
051 * Collections.sort(zl, Zman.DURATION_ORDER);
052 * // will sort sunrise, sunset (the first 2 are not in any specific order), shaah GRA, shaah 1.6
053 * Collections.sort(zl, Zman.NAME_ORDER);
054 * // will sort shaah 1.6, shaah GRA, sunrise, sunset
055 * </pre>
056 * 
057 * @author &copy; Eliyahu Hershfeld 2007-2020
058 * @todo Add secondary sorting. As of now the {@code Comparator}s in this class do not sort by secondary order. This means that when sorting a
059 * {@link java.util.Collection} of <em>zmanim</em> and using the {@link #DATE_ORDER} {@code Comparator} will have the duration based <em>zmanim</em>
060 * at the end, but they will not be sorted by duration. This should be N/A for label based sorting.
061 */
062public class Zman {
063        /**
064         * The name / label of the <em>zman</em>.
065         */
066        private String label;
067        
068        /**
069         * The {@link Date} of the <em>zman</em>
070         */
071        private Date zman;
072        
073        /**
074         * The duration if the <em>zman</em> is  a {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour} (or the various
075         * <em>shaah zmanis</em> base times such as {@link com.kosherjava.zmanim.ZmanimCalendar#getShaahZmanisGra()  <em>shaah Zmanis GRA</em>} or
076         * {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getShaahZmanis16Point1Degrees() <em>shaah Zmanis 16.1&deg;</em>}).
077         */
078        private long duration;
079        
080        /**
081         * A longer description or explanation of a <em>zman</em>.
082         */
083        private String description;
084
085        /**
086         * The constructor setting a {@link Date} based <em>zman</em> and a label.
087         * @param date the Date of the <em>zman</em>.
088         * @param label the label of the  <em>zman</em> such as "<em>Sof Zman Krias Shema GRA</em>".
089         * @see #Zman(long, String)
090         */
091        public Zman(Date date, String label) {
092                this.label = label;
093                this.zman = date;
094        }
095
096        /**
097         * The constructor setting a duration based <em>zman</em> such as
098         * {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour} (or the various <em>shaah zmanis</em> times such as
099         * {@link com.kosherjava.zmanim.ZmanimCalendar#getShaahZmanisGra() <em>shaah zmanis GRA</em>} or
100         * {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getShaahZmanis16Point1Degrees() <em>shaah Zmanis 16.1&deg;</em>}) and label.
101         * @param duration a duration based <em>zman</em> such as ({@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour()}
102         * @param label the label of the  <em>zman</em> such as "<em>Shaah Zmanis GRA</em>".
103         * @see #Zman(Date, String)
104         */
105        public Zman(long duration, String label) {
106                this.label = label;
107                this.duration = duration;
108        }
109
110        /**
111         * Returns the {@code Date} based <em>zman</em>.
112         * @return the <em>zman</em>.
113         * @see #setZman(Date)
114         */
115        public Date getZman() {
116                return this.zman;
117        }
118
119        /**
120         * Sets a {@code Date} based <em>zman</em>.
121         * @param date a {@code Date} based <em>zman</em>
122         * @see #getZman()
123         */
124        public void setZman(Date date) {
125                this.zman = date;
126        }
127
128        /**
129         * Returns a duration based <em>zman</em> such as {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour}
130         * (or the various <em>shaah zmanis</em> times such as {@link com.kosherjava.zmanim.ZmanimCalendar#getShaahZmanisGra() <em>shaah zmanis GRA</em>}
131         * or {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getShaahZmanis16Point1Degrees() <em>shaah zmanis 16.1&deg;</em>}).
132         * @return the duration based <em>zman</em>.
133         * @see #setDuration(long)
134         */
135        public long getDuration() {
136                return this.duration;
137        }
138
139        /**
140         *  Sets a duration based <em>zman</em> such as {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour}
141         * (or the various <em>shaah zmanis</em> times as {@link com.kosherjava.zmanim.ZmanimCalendar#getShaahZmanisGra() <em>shaah zmanis GRA</em>} or
142         * {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getShaahZmanis16Point1Degrees() <em>shaah zmanis 16.1&deg;</em>}).
143         * @param duration duration based <em>zman</em> such as {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour()}.
144         * @see #getDuration()
145         */
146        public void setDuration(long duration) {
147                this.duration = duration;
148        }
149
150        /**
151         * Returns the name / label of the <em>zman</em> such as "<em>Sof Zman Krias Shema GRA</em>". There are no automatically set labels
152         * and you must set them using {@link #setLabel(String)}.
153         * @return the name/label of the <em>zman</em>.
154         * @see #setLabel(String)
155         */
156        public String getLabel() {
157                return this.label;
158        }
159
160        /**
161         * Sets the the name / label of the <em>zman</em> such as "<em>Sof Zman Krias Shema GRA</em>".
162         * @param label the name / label to set for the <em>zman</em>.
163         * @see #getLabel()
164         */
165        public void setLabel(String label) {
166                this.label = label;
167        }
168
169        /**
170         * Returns the longer description or explanation of a <em>zman</em>. There is no default value for this and it must be set using
171         * {@link #setDescription(String)}
172         * @return the description or explanation of a <em>zman</em>.
173         * @see #setDescription(String)
174         */
175        public String getDescription() {
176                return this.description;
177        }
178
179        /**
180         * Sets the longer description or explanation of a <em>zman</em>.
181         * @param description
182         *            the <em>zman</em> description to set.
183         * @see #getDescription()
184         */
185        public void setDescription(String description) {
186                this.description = description;
187        }
188
189        /**
190         * A {@link Comparator} that will compare and sort <em>zmanim</em> by date/time order. Compares its two arguments by the zman's date/time
191         * order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater
192         * than the second.
193         * Please note that this class will handle cases where either the {@code Zman} is a null or {@link #getZman()} returns a null.
194         */
195        public static final Comparator<Zman> DATE_ORDER = new Comparator<Zman>() {
196                public int compare(Zman zman1, Zman zman2) {
197                        long firstTime = (zman1 == null || zman1.getZman() == null) ? Long.MAX_VALUE : zman1.getZman().getTime();
198                        long secondTime = (zman2 == null || zman2.getZman() == null) ? Long.MAX_VALUE : zman2.getZman().getTime();
199                        return Long.valueOf(firstTime).compareTo(Long.valueOf(secondTime));
200                }
201        };
202
203        /**
204         * A {@link Comparator} that will compare and sort zmanim by zmanim label order. Compares its two arguments by the zmanim label
205         * name order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater
206         * than the second.
207         * Please note that this class will will sort cases where either the {@code Zman} is a null or {@link #label} returns a null
208         * as empty {@code String}s.
209         */
210        public static final Comparator<Zman> NAME_ORDER = new Comparator<Zman>() {
211                public int compare(Zman zman1, Zman zman2) {
212                        String firstLabel = (zman1 == null || zman1.getLabel() == null) ? "" : zman1.getLabel();
213                        String secondLabel = (zman2 == null || zman2.getLabel() == null) ? "" : zman2.getLabel();
214                        return firstLabel.compareTo(secondLabel);
215                }
216        };
217
218        /**
219         * A {@link Comparator} that will compare and sort duration based <em>zmanim</em>  such as
220         * {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour} (or the various <em>shaah zmanis</em> times
221         * such as <em>{@link com.kosherjava.zmanim.ZmanimCalendar#getShaahZmanisGra() shaah zmanis GRA}</em> or
222         * {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getShaahZmanis16Point1Degrees() <em>shaah zmanis 16.1&deg;</em>}). Returns a negative
223         * integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
224         * Please note that this class will will sort cases where {@code Zman} is a null.
225         */
226        public static final Comparator<Zman> DURATION_ORDER = new Comparator<Zman>() {
227                public int compare(Zman zman1, Zman zman2) {
228                        long firstDuration  = zman1 == null ? Long.MAX_VALUE : zman1.getDuration();
229                        long secondDuration  = zman2 == null ? Long.MAX_VALUE : zman2.getDuration();
230                        return firstDuration == secondDuration ? 0      : firstDuration > secondDuration ? 1 : -1;
231                }
232        };
233        
234        /**
235         * @see java.lang.Object#toString()
236         */
237        public String toString() {
238                StringBuilder sb = new StringBuilder();
239                sb.append("\nLabel:\t\t\t").append(this.getLabel());
240                sb.append("\nZman:\t\t\t").append(getZman());
241                sb.append("\nDuration:\t\t\t").append(getDuration());
242                sb.append("\nDescription:\t\t\t").append(getDescription());
243                return sb.toString();
244        }
245}