using System;
using System.Diagnostics;

namespace nft.core.schedule
{
    [Serializable]
    public struct Date : IComparable<Date> {
        private readonly Int16 _year;
        private readonly Byte _month;
        private readonly Byte _day;

        public Date(int year, int month, int day) {
            _year = (Int16)year;
            Debug.Assert(month > 0 && day > 0, "month and day must greater than 0.");
            _month = (Byte)month;
            _day = (Byte)day;
        }

        public int Year {
            get {
                return _year;
            }
        }
        public int Month {
            get {
                return _month;
            }
        }
        public int Day {
            get {
                return _day;
            }
        }

        public Int32 SerialValue {
            get {
                return (Year << 9) + (Month << 5) + Day;
            }
        }

        #region IComparable メンバ
        public int CompareTo(Date other) {
            return Math.Sign(this.SerialValue - other.SerialValue);
        }

        public int CompareTo(object obj) {
            Date other =  (Date)obj;
            return Math.Sign(this.SerialValue - other.SerialValue);
        }
        #endregion

        #region Equals and GetHashCode
        public override bool Equals(object obj) {
            if (obj is Date) {
                Date other = (Date)obj;
                return other.SerialValue == this.SerialValue;
            }
            return false;
        }

        public override int GetHashCode() {
            return SerialValue;
        }
        #endregion

        #region 比較演算子<,>など のオーバーロード
        public static bool operator <(Date x, Date y) {
            return x.CompareTo(y) < 0;
        }

        public static bool operator <=(Date x, Date y) {
            return x.CompareTo(y) <= 0;
        }

        public static bool operator >(Date x, Date y) {
            return x.CompareTo(y) > 0;
        }

        public static bool operator >=(Date x, Date y) {
            return x.CompareTo(y) >= 0;
        }
        #endregion
    }

    /// <summary>
	/// Time instant that represent a time of a day.
	/// The Year, Month, Day is always 0 for instances of this class.
	/// </summary>
	[Serializable]
	public struct TimeOfDay : IComparable<TimeOfDay>
	{
        private readonly Byte _hour;
        private readonly Byte _minute;
        private readonly Byte _second;

		public TimeOfDay( int hour, int minute ) : this ( hour, minute, 0 )	{}

		public TimeOfDay( int hour, int minute, int second ) {
            _hour = (Byte)hour;
            _minute = (Byte)minute;
            _second = (Byte)second;
        }

        public int Hour {
            get {
                return _hour;
            }
        }
        public int Minute {
            get {
                return _minute;
            }
        }
        public int Second {
            get {
                return _second;
            }
        }

        public Int32 SerialValue {
            get {
                return (Hour << 12) + (Minute << 6) + Second;
            }
        }
        
        #region IComparable メンバ
        public int CompareTo(TimeOfDay other) {
            return Math.Sign(this.SerialValue - other.SerialValue);
        }

        public int CompareTo(object obj) {
            TimeOfDay other = (TimeOfDay)obj;
            return Math.Sign(this.SerialValue - other.SerialValue);
        }
        #endregion

        #region Equals and GetHashCode
        public override bool Equals(object obj) {
            if (obj is TimeOfDay) {
                TimeOfDay other = (TimeOfDay)obj;
                return other.SerialValue == this.SerialValue;
            }
            return false;
        }

        public override int GetHashCode() {
            return SerialValue;
        }
        #endregion

        #region 比較演算子<,>など のオーバーロード
        public static bool operator <(TimeOfDay x, TimeOfDay y) {
            return x.CompareTo(y) < 0;
        }

        public static bool operator <=(TimeOfDay x, TimeOfDay y) {
            return x.CompareTo(y) <= 0;
        }

        public static bool operator >(TimeOfDay x, TimeOfDay y) {
            return x.CompareTo(y) > 0;
        }

        public static bool operator >=(TimeOfDay x, TimeOfDay y) {
            return x.CompareTo(y) >= 0;
        }
        #endregion
    }
}
