001// Exercise 1.2.19 (Solution published at http://algs4.cs.princeton.edu/)
002package algs12;
003import java.util.Arrays;
004import java.util.Comparator;
005import stdlib.*;
006/* ***********************************************************************
007 *  Compilation:  javac Date.java
008 *  Execution:    java Date
009 *
010 *  An immutable data type for dates.
011 *
012 *************************************************************************/
013
014public class Date implements Comparable<Date> {
015        private static final int[] DAYS = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
016
017        private final int month;   // month (between 1 and 12)
018        private final int day;     // day   (between 1 and DAYS[month]
019        private final int year;    // year
020
021        // do bounds-checking to ensure object represents a valid date
022        public Date(int month, int day, int year) {
023                if (!isValid(month, day, year)) throw new Error("Invalid date");
024                this.month = month;
025                this.day   = day;
026                this.year  = year;
027        }
028
029        // create new data by parsing from string of the form mm/dd/yy
030        public Date(String date) {
031                String[] fields = date.split("/");
032                if (fields.length != 3) {
033                        throw new Error("Date parse error");
034                }
035                month = Integer.parseInt(fields[0]);
036                day   = Integer.parseInt(fields[1]);
037                year  = Integer.parseInt(fields[2]);
038                if (!isValid(month, day, year)) throw new Error("Invalid date");
039        }
040
041        public int month() { return month; }
042        public int day()   { return day;   }
043        public int year()  { return year;  }
044
045
046        // is the given date valid?
047        private static boolean isValid(int m, int d, int y) {
048                if (m < 1 || m > 12)      return false;
049                if (d < 1 || d > DAYS[m]) return false;
050                if (m == 2 && d == 29 && !isLeapYear(y)) return false;
051                return true;
052        }
053
054        // is y a leap year?
055        private static boolean isLeapYear(int y) {
056                if (y % 400 == 0) return true;
057                if (y % 100 == 0) return false;
058                return y % 4 == 0;
059        }
060
061        // return the next Date
062        public Date next() {
063                if (isValid(month, day + 1, year))    return new Date(month, day + 1, year);
064                else if (isValid(month + 1, 1, year)) return new Date(month + 1, 1, year);
065                else                                  return new Date(1, 1, year + 1);
066        }
067
068
069        // is this Date after b?
070        public boolean isAfter(Date b) {
071                return compareTo(b) > 0;
072        }
073
074        // is this Date a before b?
075        public boolean isBefore(Date b) {
076                return compareTo(b) < 0;
077        }
078
079        // compare this Date to that one
080        public int compareTo(Date that) {
081                if (this.year  < that.year)  return -1;
082                if (this.year  > that.year)  return +1;
083                if (this.month < that.month) return -1;
084                if (this.month > that.month) return +1;
085                if (this.day   < that.day)   return -1;
086                if (this.day   > that.day)   return +1;
087                return 0;
088        }
089
090        // return a string representation of this date
091        public String toString() {
092                return month + "/" + day + "/" + year;
093        }
094
095        // is this Date equal to x?
096        public boolean equals(Object x) {
097                if (x == this) return true;
098                if (x == null) return false;
099                if (x.getClass() != this.getClass()) return false;
100                Date that = (Date) x;
101                return (this.month == that.month) && (this.day == that.day) && (this.year == that.year);
102        }
103
104        public int hashCode() {
105                int hash = 17;
106                hash = 31*hash + Integer.hashCode (month);
107                hash = 31*hash + Integer.hashCode (day);
108                hash = 31*hash + Integer.hashCode (year);
109                return hash;
110        }
111
112
113
114        // A stupid class!
115        private static class MyComp implements Comparator<Date>{
116                public int compare (Date o1, Date o2) {
117                        return o2.compareTo (o1);
118                }               
119        }
120        
121        // sample client for testing
122        public static void main(String[] args) {
123                // using the stupid class:
124                Comparator<Date> c1 = new MyComp ();
125
126                // using an inner class:
127                Comparator<Date> c2 = new Comparator<Date>() {
128                        public int compare (Date o1, Date o2) {
129                                return o2.compareTo (o1);
130                        }
131                };
132                
133                // using a lambda expression:
134                Comparator<Date> c3 = (o1, o2) -> o2.compareTo (o1);    
135                
136                Date[] dates = new Date[] { new Date(2, 25, 2004), new Date(2, 25, 2003), } ;
137                StdOut.println (Arrays.binarySearch (dates, new Date(2, 25, 2003), c1));
138                
139//              Date today = new Date(2, 25, 2004);
140//              StdOut.println(today);
141//              for (int i = 0; i < 10; i++) {
142//                      today = today.next();
143//                      StdOut.println(today);
144//              }
145//
146//              StdOut.println(today.isAfter(today.next()));
147//              StdOut.println(today.isAfter(today));
148//              StdOut.println(today.next().isAfter(today));
149//
150//
151//              Date birthday = new Date(10, 16, 1971);
152//              StdOut.println(birthday);
153//              for (int i = 0; i < 10; i++) {
154//                      birthday = birthday.next();
155//                      StdOut.println(birthday);
156//              }
157        }
158
159}