001    package edu.nrao.sss.model.project.scheduling;
002    
003    import java.io.Reader;
004    import java.io.StringReader;
005    import java.math.BigDecimal;
006    
007    import java.util.Date;
008    
009    import javax.xml.bind.annotation.XmlRootElement;
010    
011    import javax.xml.bind.JAXBException;
012    import javax.xml.stream.XMLStreamException;
013    
014    import org.apache.log4j.Logger;
015    
016    import edu.nrao.sss.measure.TimeDuration;
017    import edu.nrao.sss.measure.TimeUnits;
018    import edu.nrao.sss.util.JaxbUtility;
019    
020    //A sidereal day last from when a distant star is on the meridian at a point on Earth until
021    //it is next on the meridian.  A sidereal day lasts 23 hours and 56 minutes.
022    
023    //A Julian Date is used by astronomers, it has an origin of January 0,4173 BC at noon.  This
024    //scale is counted in days and fractions of days rather than hours and minutes.
025    
026    //The modified Julian date places the transition at midnight rather than noon.
027    /**
028     * @deprecated Use {@link edu.nrao.sss.measure.LocalSiderealTime},
029     * {@link edu.nrao.sss.measure.JulianDate}, and the other time classes
030     * in <tt>edu.nrao.sss.measure</tt>.
031     * 
032     * Represents an LST day number and hour for the purposes of scheduling.
033     * @author slovelan
034     */
035    @Deprecated
036    @XmlRootElement
037    public class SchedTime implements Comparable<SchedTime> {
038            
039            public static final float HOURS_PER_LST_DAY = 24;
040            
041            //Number of milliseconds in a day.
042            private static final float MILLISECONDS_PER_DAY = 86400000;
043            private static final int MODIFIED_JULIAN_DAY_FOR_1970= 40587;
044            private static final int SECONDS_PER_HOUR = 3600;
045            private static final Logger log = Logger.getLogger( SchedTime.class );
046            
047        //Starting day number
048            private int day = 0;
049            
050            //Starting hour
051            //Note units are hours although Barry's code uses half hours.
052            private double hour = 0;
053            
054            /**
055             * Returns the number of days corresponding to the number of milliseconds
056             * passed in as an argument.
057             * @param millis the number of milliseconds.
058             * @return the corresponding number of days.
059             */
060            
061            private static double getDaysForMilliseconds( long millis ){
062                    double daysSince1970 = millis /MILLISECONDS_PER_DAY;
063                    return daysSince1970;
064            }
065            
066            
067            /**
068             * Returns the modified julian day corresponding to the given 
069             * number of milliseconds.
070             * @param milliseconds a time quantity.
071             * @return the modified julian day number corresponding to the given
072             *              number of milliseconds.
073             */
074            
075            public static double modifiedJulianDay( long milliseconds ){
076    
077                    double dayNow = getDaysForMilliseconds( milliseconds ) 
078                                                            + MODIFIED_JULIAN_DAY_FOR_1970;
079                    return dayNow;
080            }
081            
082            
083            /**
084             * Returns the current modified julian day.
085             * @return the current modified julian day.
086             */
087            
088            public static double modifiedJulianDayNow(){
089                    long milliseconds = System.currentTimeMillis();
090                    double dayNow = modifiedJulianDay( milliseconds );
091                    return dayNow;
092            }
093            
094            
095            /**
096             * Returns the current LST time.
097             * @return the current LST time.
098             */
099            
100            public static double currentLSTTime(){
101                    double dayNow = modifiedJulianDayNow();
102                    double lstTime = getLSTTime( dayNow );
103                    return lstTime;
104            }
105            
106            
107            /**
108             * Returns the LST time corresponding to the passed in date.
109             * @param theDate a Date for which an LST time is wanted.
110             * @return the LST time corresponding to the date argument.
111             */
112            
113            public static double getLSTTime( Date theDate ){
114                    double theTime = -1;
115                    if ( theDate != null ){
116                            long milliseconds = theDate.getTime();
117                            double jDay = modifiedJulianDay( milliseconds );
118                            theTime = getLSTTime( jDay );
119                    }
120                    return theTime;
121            }
122            
123            
124            /**
125             * Returns the LST time corresponding to the indicated number of
126             * milliseconds.
127             * @param milliseconds a time represented in milliseconds.
128             * @return the LST time corresponding to the indicated number of
129             *         milliseconds.
130             */
131            
132            public static double getLSTTime( long milliseconds ){
133                    double days = modifiedJulianDay( milliseconds );
134                    double lstTime = getLSTTime( days );
135                    return lstTime;
136            }
137            
138            
139            //LST = GST + 1.0027379093( T +  T-to-Greenwich) - L / 15
140            //LST = local sidereal time
141            //GST = Greenwich sidereal time at midnight for the current date.
142            //T = the local 24 hour time
143            //T-to-Greenwich hours to convert local time to greenwich time.
144            //L west longitude of your location converted to hours ( hours=degrees/360*24)
145            /**
146             * Returns the LST time corresponding to the Julian time.
147             * @return the LST time corresponding to the Julian time.
148             */
149            
150            public static double getLSTTime( double julianDays ){
151            
152                    //final double SIDEREAL_DAYS_PER_SOLAR_DAY = 1.0027379093;
153                            
154                    //Convert the time to days and add constants to come up with
155                    //the gst.
156                double lmst = julianDays + 6571;
157                    
158                    lmst =  lmst + 0.0027379094 * julianDays;
159                    //lmst = (days + 6571) + 0.0027379094 * days
160                    //lmst = days( 1.0027379094) +6571
161                    
162                    //Is this something referred to as the equation of equanoxes?
163                    lmst +=  8.0771e-16 * julianDays * julianDays;
164                    
165                    //Is this the longitude part?
166                    lmst += 0.855951;
167             
168                    
169                    return lmst;
170            }
171            
172            
173        public static long convertHoursToSeconds( double hours ){
174            long secs = (long)( hours * SECONDS_PER_HOUR );
175            return secs;
176        }
177        
178        public static double convertSecondsToHours( long seconds ){
179            double hours = ( seconds * 1.0f ) / SECONDS_PER_HOUR;
180            int dayCount = (int)( hours / HOURS_PER_LST_DAY );
181            double leftoverHours = hours - dayCount * HOURS_PER_LST_DAY;
182            return leftoverHours;
183        }
184            
185            //-------------------------------------------------------------------------
186            //                       Construction
187            //-------------------------------------------------------------------------
188            
189            
190            /**
191             * Constructs an instance of this <code>SchedTime</code> initialized to the
192             * current time.
193             */
194            
195            public SchedTime(){
196                    double lstTimeNow = currentLSTTime();
197                    this.day = (int) lstTimeNow;
198                    double hourFraction = lstTimeNow - this.day;
199                    this.hour = hourFraction * HOURS_PER_LST_DAY;
200            }
201            
202            
203            /**
204             * Constructs an instance of this <code>SchedTime</code> initialized to the
205             * indicated LST day and hour.
206             */
207            
208            public SchedTime( double hours, int day ){
209                    if ( hours < 0 || hours > HOURS_PER_LST_DAY ){
210                            throw new IllegalArgumentException( "An hour value of: "+hours +" does not make sense!");
211                    }
212                    if ( day < 0){
213                            throw new IllegalArgumentException( "A day value of: "+day+" does not make sense!");
214                    }
215                    this.hour = hours;
216                    this.day = day;
217            }
218            
219            
220            /**
221             * Constructs an instance of this <code>SchedTime</code> initialized to the
222             * same LST day and hour as the argument.
223             * @param copy a <code>SchedTime</code> representing a scheduling time to copy.
224             */
225            //We provide a copy constructor to avoid Java's horrible clone mechanism
226            public SchedTime( SchedTime copy ){
227                    this.day = copy.getDay();
228                    this.hour = copy.getHour();
229            }
230            
231            
232            //-----------------------------------------------------------------------
233            //                 Hour
234            //-----------------------------------------------------------------------
235                
236            /**
237             * Returns the hour.
238             * @return the hour.
239             */
240            
241        public double getHour(){
242            return hour;
243        }
244        
245        /**
246         * Sets the hour
247         * @param hour the hour for this time.
248         */
249        
250        public void setHour( double hour ){
251            if ( hour >= 0 && hour < HOURS_PER_LST_DAY ){
252                    this.hour = hour;
253            }
254            else {
255                    throw new IllegalArgumentException( "An hour of "+hour+" does not make sense in a schedule.");
256            }
257        }
258            
259        
260        //------------------------------------------------------------
261        //                 LST Day Number
262        //------------------------------------------------------------
263    
264        /**
265         * Sets the LST day number in the schedule.
266         * @param lstDayNumber the LST day number for the schedule.
267         */
268        
269        public void setDay( int lstDayNumber){
270            if ( day >= 0 ){
271                    day = lstDayNumber;
272            }
273            else {
274                    throw new IllegalArgumentException( "Setting an lst day to "+lstDayNumber+" doesn't make sense!");
275            }
276        }
277        
278        
279        /**
280         * Returns the LST day number for the schedule.
281         * @return the lstDayNumber for the schedule.
282         */
283        
284        public int getDay(){
285            return day;
286        }   
287            
288            
289            //------------------------------------------------------------------------------------
290            //                          Math Operations
291            //------------------------------------------------------------------------------------
292        
293        /**
294         * Returns a SchedTime that is the sum of the argument and this <code>SchedTime</code>.
295         * @param td a TimeDuration indicating the length of time this schedule time needs to
296         *           be increased.
297         * @return the sum of this {@code SchedTime} and the argument.
298         */
299        
300            public SchedTime add( TimeDuration td ){
301                    SchedTime sum = null;
302                    if ( td != null ){
303                            double hr = td.convertTo( TimeUnits.HOUR ).getValue().doubleValue();
304                            SchedTime newTime = new SchedTime( hr, 0 );
305                            sum = add( newTime );
306                    }
307                    else {
308                            throw new IllegalArgumentException( "SchedTime needs something to add!");
309                    }
310                    return sum;
311            }
312            /**
313             * Returns a SchedTime that is the sum of the argument and this <code>SchedTime</code>.
314             * @param otherTime the <code>SchedTime</code> that should be added to this one.
315             * @return the sum of this <code>SchedTime</code> and the argument.
316             */
317            
318            public SchedTime add( SchedTime otherTime ){
319                    SchedTime sum = null;
320                    if ( otherTime != null ){
321                            //Add the hours.
322                    
323                            double thisHour = getHour();
324                            double otherHour = otherTime.getHour();
325                            double sumHour = thisHour + otherHour;
326                            int sumDay = day;
327                            if ( sumHour >= HOURS_PER_LST_DAY ){
328                                    sumHour = sumHour - HOURS_PER_LST_DAY;
329                                    sumDay++;
330                            }
331                            //Add the days.
332                            sumDay = sumDay + otherTime.getDay();
333                            sum = new SchedTime( sumHour, sumDay);
334                    }
335                    else {
336                            sum = new SchedTime( this  );
337                    }
338                    return sum;
339            }
340            
341            /**
342             * Returns a <code>TimeDuration</code> that represents the time difference between
343             * this <code>SchedTime</code> and the argument.
344             * @param otherTime the <code>SchedTime</code> that should be subtracted from this one.
345             * @return the difference of this <code>SchedTime</code> and the argument.
346             * @throws IllegalArgumentException if the parameter is larger than this <code>SchedTime</code>.
347             */
348            
349            
350            public TimeDuration subtract( SchedTime otherTime ){
351                    TimeDuration difference = null;
352                    if ( otherTime != null ){
353                            
354                            int diffDay = day;
355            
356                            //Add the hours.
357                            double otherHour = otherTime.getHour();
358                            double thisHour = getHour();
359                            double diffHour = thisHour - otherHour;
360                            if ( diffHour < 0 ){
361                                    diffHour = diffHour + HOURS_PER_LST_DAY;
362                                    diffDay--;
363                            }
364                            
365                            //Subtract the days.
366                            diffDay = diffDay - otherTime.getDay();
367          double hours = diffDay * HOURS_PER_LST_DAY + diffHour;
368                            difference = new TimeDuration(BigDecimal.valueOf(hours), TimeUnits.HOUR );
369                    }
370                    else {
371          double hours = day * HOURS_PER_LST_DAY + getHour();
372                            difference = new TimeDuration(BigDecimal.valueOf(hours), TimeUnits.HOUR );
373                    }
374                    return difference;
375            }
376            
377            
378    
379            
380            //-----------------------------------------------------------------
381            //                   Overriden Object Methods
382            //-----------------------------------------------------------------
383            
384            public boolean equals( SchedTime other ){
385                    
386                    boolean result = false;
387                    if ( other != null ){
388                            if ( other instanceof SchedTime ){
389                                    SchedTime otherSched = (SchedTime) other;
390                                    if ( hour == otherSched.getHour()){
391                                            if ( day == otherSched.getDay() ){
392                                                    result = true;
393                                            }
394                                    }
395                            }
396                    }
397                    return result;
398            }
399            
400            public int compareTo( SchedTime otherTime ){
401                    Integer thisDay = new Integer( day );
402                    Integer otherDay = new Integer( otherTime.getDay());
403                    int result = thisDay.compareTo( otherDay );
404                    if ( result == 0 ){
405                            Double thisHour = new Double( hour );
406                            Double otherHour = new Double( otherTime.getHour());
407                            result = thisHour.compareTo( otherHour );
408                    }
409                    return result;
410            }
411            
412            public int hashCode(){
413                      int result = 7;
414                      result = 11 * result  + new Integer( day ).hashCode();
415                      result = 11 * result + new Double( hour ).hashCode();
416                      return result;
417            }
418            
419            
420            //----------------------------------------------------------------------------
421            //                       XML and String Representations
422            //----------------------------------------------------------------------------
423            
424            /**
425             * Returns a string containing the xml representation of this schedule time.
426             * @return a String containing the xml representation of this schedule time.
427             */
428            
429            public String toXml(){
430                      String xmlStr = "";
431                      
432          try {
433            xmlStr = JaxbUtility.getSharedInstance().objectToXmlString(this);
434          }
435                      catch( JAXBException je ){
436                              je.printStackTrace();
437                              log.error( "Could not convert schedule to xml "+je.getMessage());
438                      }
439                     
440                      return xmlStr;
441            }
442            
443            
444            /**
445             * Returns the <code>SchedTime</code> constructed from a reader or null if
446             * it is not possible to determine the corresponding time.
447             * @param reader a Reader containing schedule time information.
448             * @return the corresponding SchedTime.
449             */
450            
451            public static SchedTime fromXml( Reader reader ){
452                    JaxbUtility util = JaxbUtility.getSharedInstance();
453                    SchedTime newSched = null;
454                    if ( reader != null ){
455                            
456                            String errorStr = "Could not create viewer from string reader";
457                            try {
458                                    newSched = util.readObjectAsXmlFrom( reader, SchedTime.class, null );
459                            }
460            
461                            catch( JAXBException je ){
462                                    log.error( errorStr +"(Jaxb) "+je.getMessage()+je.toString());
463                                    je.printStackTrace();
464                            }
465                            catch( XMLStreamException se ){
466                                    log.error( errorStr + "(XML) "+se.getMessage());
467                            }
468            
469                    }
470                    return newSched;
471            }
472            
473                    /**
474                     * Returns a <code>SchedTime</code> from an xml representation or null if
475                     * it is not possible to parse the xml.
476                     * @param xmlString a String containing the xml representation of a <code>SchedTime</code>
477                     * @return the <code>SchedTime</code> corresponding to the xml representation.
478                     */
479            
480                    public static SchedTime fromXml( String xmlString ){
481                            SchedTime newSched = null;
482                            log.info( "xmlString is "+xmlString );
483                            if ( xmlString != null ){                       
484                                    StringReader reader = new StringReader( xmlString );
485                                    newSched = fromXml( reader );   
486                            }
487                            return newSched;
488                    }
489            
490              /**
491               * Returns a text representation of this schedule entry.
492               * The default form of the text is XML.  However, if anything goes wrong
493               * during the conversion to XML, an alternate, and much abbreviated, form
494               * will be returned.
495               * 
496               * @return a text representation of this schedule entry.
497               * 
498               * @see #toSummaryString()
499               */
500              public String toString(){
501                      try {
502                              return toXml();
503                      }
504                      catch (Exception ex) {
505                              return toSummaryString();
506                      }
507              }
508              
509              
510              /**
511               * Returns a brief word description of this scheduling time.
512               * @return a brief word description of this scheduling time.
513               */
514              
515              public String toSummaryString(){
516                    double hour = getHour();
517                    //Round to one decimal
518                    hour = ((int)(  hour * 10 + 0.5  )) / 10.0;
519                    String result = day + " at "+ hour;
520                    return result;
521              }
522                    
523              
524             /**
525              * Parses a string in the format used by Barry and returns a corresponding
526              * schedule time or null if there is no such time.
527              * @param str a String with the day and hour separated by the word "at".
528              * @return the schedule time corresponding to the string or null if there
529              *         is no such time.
530              */
531              
532            public static SchedTime fromString( String str ){
533                    SchedTime newTime = null;
534                    if ( str != null ){
535                            String[] parts = str.split( " ");
536                            if ( parts.length == 3 ){
537                                    try {
538                                            int day = Integer.parseInt( parts[0]);
539                                            double hour = Double.parseDouble( parts[2]);
540                                            newTime = new SchedTime( hour, day );
541                                    }
542                                    catch( NumberFormatException nfe ){
543                                            //log.error( "Could not make a sched time from string="+str );
544                                    }
545                            }
546                            else {
547                                     //log.error( "Could not make a sched time from string="+str );
548                            }
549                    }
550                    return newTime;
551            }
552            
553    }