import org.codehaus.groovy.runtime.TimeCategory

class TaskRecurringSchedule {

    Task lastGeneratedSubTask
    Period recurPeriod
    Period taskDurationPeriod

    Integer recurEvery = 1
    Integer taskDuration = 0
    Integer generateAhead = 1
    Integer subTasksGenerated = 0
    Date nextGenerationDate = new Date()
    Date nextTargetStartDate = new Date()
    Date nextTargetCompletionDate = new Date()
    boolean enabled = true

//     static hasMany = []

    static belongsTo = [task: Task]

    static constraints = {
        recurEvery(min:1, max:365)
        taskDuration(min:0, max:365)
        generateAhead(min:0, max:62)
        lastGeneratedSubTask(nullable:true)
    }

    String toString() {
        "Recur every ${recurEvery} ${recurPeriod}"
    }

    // As of Grails 1.1.1 this does not fire/pass before validation.
    // But setting some defaults above to pass validation and placing this code here
    // in the hope that this will be fixed in future versions.
    def beforeInsert = {
        setNextGenerationDate()
        setNextTargetCompletionDate()
    }

    public void setNextTargetStartDate() {
        switch (recurPeriod.period) {
            case "Day(s)":
                use(TimeCategory) {
                    nextTargetStartDate = nextTargetStartDate + recurEvery.days
                }
                break
            case "Week(s)":
                use(TimeCategory) {
                    nextTargetStartDate = nextTargetStartDate + recurEvery.weeks
                }
                break
            case "Month(s)":
                use(TimeCategory) {
                    nextTargetStartDate = nextTargetStartDate + recurEvery.months
                }
                break
            case "Year(s)":
                use(TimeCategory) {
                    nextTargetStartDate = nextTargetStartDate + recurEvery.years
                }
                break
        default:
                log.error "No case for recurPeriod.period: ${recurPeriod.period}"
                break
        }
    }

    public void setNextGenerationDate() {
        use(TimeCategory) {
            nextGenerationDate = nextTargetStartDate - generateAhead.days
        }
        def now = new Date()
        if( nextGenerationDate < now) {nextGenerationDate = now}
    }

    public void setNextTargetCompletionDate() {
        switch (taskDurationPeriod.period) {
            case "Day(s)":
                use(TimeCategory) {
                    nextTargetCompletionDate = nextTargetStartDate + taskDuration.days
                }
                break
            case "Week(s)":
                use(TimeCategory) {
                    nextTargetCompletionDate = nextTargetStartDate + taskDuration.weeks
                }
                break
            case "Month(s)":
                use(TimeCategory) {
                    nextTargetCompletionDate = nextTargetStartDate + taskDuration.months
                }
                break
            case "Year(s)":
                use(TimeCategory) {
                    nextTargetCompletionDate = nextTargetStartDate + taskDuration.years
                }
                break
            default:
                log.error "No case for taskDurationPeriod.period: ${taskDurationPeriod.period}"
                break
        }
    }

}

