import org.codehaus.groovy.runtime.TimeCategory
// the above will be deprecated and replaced by: groovy.time.TimeCategory
/// @todo: consider moving this to org.gnumims.DateUtil
/// pros: easy to use in domain classes.
/// cons: have to import so pulls in all referenced imports? Injection probably does that anyway.

/**
* Provides some convenience methods for working with dates.
*/
class DateUtilService {

    boolean transactional = false
    //static scope = "request"

    /**
    * Get the start of today.
     * Can be call as dateUtilService.today or dateUtilService.getToday().
     * @returns A Date object with today's date and all time fields set to 0.
    */
    public static Date getToday() {
        return getMidnight(new Date())
    }

    /**
    * Get the start of tomorrow.
     * Can be call as dateUtilService.tomorrow or dateUtilService.getTomorrow().
     * @returns A Date object with tomorrow's date and all time fields set to 0.
    */
    public static Date getTomorrow() {
        return (getToday() + 1) as Date
    }

    /**
    * Get the start of yesterday.
     * Can be call as dateUtilService.yesterday or dateUtilService.getYesterday().
     * @returns A Date object with yesterday's date and all time fields set to 0.
    */
    public static Date getYesterday() {
        return (getToday() - 1) as Date
    }

    /**
    * Get the start of the day one week ago.
     * Can be call as dateUtilService.oneWeekAgo or dateUtilService.getOneWeekAgo().
     * @returns A Date object with the date one week ago and all time fields set to 0.
    */
    public static Date getOneWeekAgo() {
        return (getToday() - 7) as Date
    }

    /**
    * Get the start of the day one week ago.
     * Can be call as dateUtilService.oneWeekAgo or dateUtilService.getOneWeekAgo().
     * @returns A Date object with the date one week ago and all time fields set to 0.
    */
    public static Date getOneWeekFromNow() {
        return (getToday() + 7) as Date
    }

    /**
    * Get the start of a given date by setting all time fields to 0.
    * The Calendar.getInstance() or Calendar.instance factory returns a new calendar instance, usually
    * a Gregorian calendar but using Calendar we don't have to worry about those details.
    * The time fields are then set to zero and cal.getTime() or cal.time returns a java.util.Date object.
    * @param date The Date object to start with.
    * @returns A Date object having the given date and all time fields set to 0, so the very start of the given day.
    */
    public static Date getMidnight(Date date) {
        Calendar cal = Calendar.instance
        cal.setTime(date)
        cal.set(Calendar.HOUR_OF_DAY, 0)
        cal.set(Calendar.MINUTE, 0)
        cal.set(Calendar.SECOND, 0)
        cal.set(Calendar.MILLISECOND, 0)
        cal.time
    }

    /**
    * Get the date one month in the future.
    * @param date The Date object to start with.
    * @returns A Date object one month in the future.
    */
    public static Date getNextMonth(Date date) {
        use(TimeCategory) {
            date + 1.months
        }
    }

    /**
    * Get the date one month ago.
    * @param date The Date object to start with.
    * @returns A Date object one month ago.
    */
    public static Date getPreviousMonth(Date date) {
        use(TimeCategory) {
            date - 1.months
        }
    }

    /**
    * Get the date one year in the future.
    * @param date The Date object to start with.
    * @returns A Date object one year in the future.
    */
    public static Date getNextYear(Date date) {
        use(TimeCategory) {
            date + 1.years
        }
    }

    /**
    * Get the date one year ago.
    * @param date The Date object to start with.
    * @returns A Date object one year ago.
    */
    public static Date getPreviousYear(Date date) {
        use(TimeCategory) {
            date - 1.years
        }
    }

    /**
    * Make a date object from supplied year, month, day values.
    * The Calendar.getInstance() or Calendar.instance factory returns a new calendar instance, usually
    * a Gregorian calendar but using Calendar we don't have to worry about those details.
    * The time fields are set to zero and cal.getTime() or cal.time returns a java.util.Date object.
    * @param year The year as a string or integer.
    * @param month The month as a string or integer, defaults to 1 (i.e. January).
    * @param day The day as a string or integer, defaults to 1.
    * @returns A Date object having the given date and all time fields set to 0, so the very start of the given day.
    */
    public static Date makeDate(year, month=1, day=1) {
        Calendar cal = Calendar.instance
        cal.clear()
        // Stupid month is 0-based, grumble.
        cal.set(year.toInteger(), month.toInteger()-1, day.toInteger())
        cal.time
    }

    /**
    * Get the day of month from supplied date.
    * @param date The date to extract the day of month from.
    * @returns An integer representing the day of the month.
    */
    public static Integer getDayFromDate(Date date) {
        Calendar cal = Calendar.instance
        cal.setTime(date)
        cal.get(Calendar.DAY_OF_MONTH)
    }

    /**
    * Get the month from supplied date.
    * @param date The date to extract the month from.
    * @returns An integer representing the month.
    */
    public static Integer getMonthFromDate(Date date) {
        Calendar cal = Calendar.instance
        cal.setTime(date)
        cal.get(Calendar.MONTH) + 1 // Stupid month is 0-based, grumble.
    }

    /**
    * Get the year from supplied date.
    * @param date The date to extract the year from.
    * @returns An integer representing the year.
    */
    public static Integer getYearFromDate(Date date) {
        Calendar cal = Calendar.instance
        cal.setTime(date)
        cal.get(Calendar.YEAR)
    }

}
