import org.codehaus.groovy.grails.plugins.springsecurity.Secured
import org.codehaus.groovy.grails.commons.ConfigurationHolder
import com.zeddware.grails.plugins.filterpane.FilterUtils
import org.springframework.web.servlet.support.RequestContextUtils as RCU

@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
class TaskDetailedController extends BaseController {

    def authService
    def taskService
    def taskSearchService
    def filterService
    def exportService
    def dateUtilService

    // these actions only accept POST requests
    static allowedMethods = [save:'POST',update:'POST',restore:'POST', trash:'POST',
                                                approve:'POST', renegeApproval:'POST', complete:'POST',
                                                reopen:'POST', setAttentionFlag:'POST', clearAttentionFlag:'POST']

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def index = { redirect(action: 'search', params: params) }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def setSearchParamsMax = {
        def max = 1000
        if(params.newMax.isInteger()) {
            def i = params.newMax.toInteger()
            if(i > 0 && i <= max)
                session.taskSearchParamsMax = params.newMax
            if(i > max)
                session.taskSearchParamsMax = max
        }
        forward(action: 'search', params: params)
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def setSearchCalendarParamsMax = {
        def max = 1000
        if(params.newMax.isInteger()) {
            def i = params.newMax.toInteger()
            if(i > 0 && i <= max)
                session.taskSearchCalendarParamsMax = params.newMax
            if(i > max)
                session.taskSearchCalendarParamsMax = max
        }
        forward(action: 'searchCalendar', params: params)
    }

    /**
    * Search for tasks.
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def search = {

        if(session.taskSearchParamsMax)
            params.max = session.taskSearchParamsMax

        // Protect filterPane.
        params.max = Math.min( params.max ? params.max.toInteger() : 100,  1000 )

        def taskInstanceList = []
        def taskInstanceTotal
        def filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
        def isFilterApplied = FilterUtils.isFilterApplied(params)

        // Restore search unless a new search is being requested.
        if(!params.quickSearch && !filterParams) {
            if(session.taskSearchQuickSearch)
                params.quickSearch = session.taskSearchQuickSearch
            else if(session.taskSearchFilterParams) {
                session.taskSearchFilterParams.each() { params[it.key] = it.value }
                params.filter = session.taskSearchFilter
                isFilterApplied = FilterUtils.isFilterApplied(params)
            }
        }

        // Remember sort if supplied, otherwise try to restore.
        if(params.sort && params.order) {
             session.taskSearchSort = params.sort
             session.taskSearchOrder = params.order
        }
        else if(session.taskSearchSort && session.taskSearchOrder) {
            params.sort = session.taskSearchSort
            params.order = session.taskSearchOrder
        }

        if(isFilterApplied) {
            // filterPane:
            if(params.sort == "attentionFlag") // See ticket #64 in Trac.
                params.sort = "id"
            // Prevent tasks in the trash being returned unless explicitly requested.
            if(!params.filter.op.trash) {
                params.filter.op.trash = "Equal"
                params.filter.trash = "false"
            }
            // Call filterService.
            taskInstanceList = filterService.filter( params, Task )
            taskInstanceTotal = filterService.count( params, Task )
            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
            // Remember search.
            session.taskSearchFilterParams = new LinkedHashMap(filterParams)
            session.taskSearchFilter = new LinkedHashMap(params.filter)
            session.removeAttribute("taskSearchQuickSearch")
        }
        else {
            // Quick Search:
            if(!params.quickSearch) params.quickSearch = "myTodays"
            def result = taskSearchService.getQuickSearch(params, RCU.getLocale(request))
            taskInstanceList = result.taskInstanceList
            taskInstanceTotal = result.taskInstanceList.totalCount
            params.message = result.message
            filterParams.quickSearch = result.quickSearch
            // Remember search.
            session.removeAttribute("taskSearchFilterParams")
            session.removeAttribute("taskSearchFilter")
            session.taskSearchQuickSearch = result.quickSearch
        }

        // export plugin:
        if(params?.format && params.format != "html") {

            def dateFmt = { date ->
                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
            }

            String title
            if(params.quickSearch)
                title = params.message
            else
                title = "Filtered tasks."

            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
            response.setHeader("Content-disposition", "attachment; filename=Tasks.${params.extension}")
            List fields = ["id", "targetStartDate", "description", "leadPerson", "taskPriority", "taskType", "taskStatus"]
            Map labels = ["id": "ID", "targetStartDate": "Target Start Date", "description": "Description",
                                    "leadPerson": "Lead Person", "taskPriority": "Task Priority",
                                    "taskType": "Task Type", "taskStatus": "Task Status"]
            Map formatters = [ targetStartDate: dateFmt]
            Map parameters = [title: title, separator: ","]

            exportService.export(params.format, response.outputStream, taskInstanceList, fields, labels, formatters, parameters)
        }

        // Add some basic params to filterParams.
        filterParams.max = params.max
        filterParams.offset = params.offset?.toInteger() ?: 0
        filterParams.sort = params.sort ?: "attentionFlag"
        filterParams.order = params.order ?: "desc"

        // Get some associatedProperty values for filterpane.
        def associatedPropertyValues = [:]
        def associatedPropertyMax = 10000
        associatedPropertyValues.taskPriorityList = TaskPriority.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
        def lastNameQuery = 'select distinct p.lastName from Person p where p.isActive = ? order by p.lastName'
        associatedPropertyValues.lastNameList = Person.executeQuery(lastNameQuery, [true], [max:associatedPropertyMax])
        def firstNameQuery = 'select distinct p.firstName from Person p where p.isActive = ? order by p.firstName'
        associatedPropertyValues.firstNameList = Person.executeQuery(firstNameQuery, [true], [max:associatedPropertyMax])
        associatedPropertyValues.taskGroupList = TaskGroup.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
        associatedPropertyValues.assetList = Asset.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
        associatedPropertyValues.taskStatusList = TaskStatus.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
        associatedPropertyValues.taskTypeList = TaskType.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
        def startOfYearRange = dateUtilService.getYearFromDate(dateUtilService.plusYear(new Date(), -10))
        def endOfYearRange = dateUtilService.getYearFromDate(dateUtilService.plusYear(new Date(), 10))
        associatedPropertyValues.yearRange = startOfYearRange..endOfYearRange

        return[ taskInstanceList: taskInstanceList,
                        taskInstanceTotal: taskInstanceTotal,
                        filterParams: filterParams,
                        params: params,
                        associatedPropertyValues: associatedPropertyValues ]

    } // search

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def searchCalendar = {

        // No pagination for calendar.
        params.offset = 0

        // Restore params.max
        if(session.taskSearchCalendarParamsMax)
            params.max = session.taskSearchCalendarParamsMax

        // Protect filterPane.
        params.max = Math.min( params.max ? params.max.toInteger() : 100,  1000 )

        def taskInstanceList = []
        def taskInstanceTotal
        def filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
        def isFilterApplied = FilterUtils.isFilterApplied(params)

        // Restore search unless a new search is being requested.
        if(!params.quickSearch && !filterParams) {
            if(session.taskSearchCalendarQuickSearch)
                params.quickSearch = session.taskSearchCalendarQuickSearch
            else if(session.taskSearchCalendarFilterParams) {
                session.taskSearchCalendarFilterParams.each() { params[it.key] = it.value }
                params.filter = session.taskSearchCalendarFilter
                isFilterApplied = FilterUtils.isFilterApplied(params)
            }
        }

        // The date the calendar will use to determine the month to show.
        // Use session, if not specified in params, otherwise use today.
        def showDate = new Date()
        if(params.showMonth) {
            if(params.showYear)
                showDate = dateUtilService.makeDate(params.showYear, params.showMonth)
            else
                showDate = dateUtilService.makeDate(dateUtilService.getYearFromDate(showDate), params.showMonth)
            // Remember the showDate.
            session.taskSearchCalendarShowDate = showDate
        }
        else if(session.taskSearchCalendarShowDate)
            showDate = session.taskSearchCalendarShowDate

        // Get the dates for the calendar month controls.
        def calendarMonthControls = getCalendarMonthControls(showDate)

        if(isFilterApplied) {
            // filterPane:
            if(params.sort == "attentionFlag") // See ticket #64 in Trac.
                params.sort = "id"
            // Prevent tasks in the trash being returned unless explicitly requested.
            if(!params.filter.op.trash) {
                params.filter.op.trash = "Equal"
                params.filter.trash = "false"
            }
            // Call filterService.
            taskInstanceList = filterService.filter( params, Task )
            taskInstanceTotal = filterService.count( params, Task )
            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
            // Remember search.
            session.taskSearchCalendarFilterParams = new LinkedHashMap(filterParams)
            session.taskSearchCalendarFilter = new LinkedHashMap(params.filter)
            session.removeAttribute("taskSearchCalendarQuickSearch")
        }
        else {
            // Quick Search:
            def result = taskSearchService.getQuickSearch(params, RCU.getLocale(request))
            taskInstanceList = result.taskInstanceList
            taskInstanceTotal = result.taskInstanceList.totalCount
            params.message = result.message
            filterParams.quickSearch = result.quickSearch
            // Remember search.
            session.removeAttribute("taskSearchCalendarFilterParams")
            session.removeAttribute("taskSearchCalendarFilter")
            session.taskSearchCalendarQuickSearch = result.quickSearch
        }

        // export plugin:
        if(params?.format && params.format != "html") {

            def dateFmt = { date ->
                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
            }

            String title
            if(params.quickSearch)
                title = params.message
            else
                title = "Filtered tasks."

            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
            response.setHeader("Content-disposition", "attachment; filename=Tasks.${params.extension}")
            List fields = ["id", "targetStartDate", "description", "leadPerson", "taskPriority", "taskType", "taskStatus"]
            Map labels = ["id": "ID", "targetStartDate": "Target Start Date", "description": "Description",
                                    "leadPerson": "Lead Person", "taskPriority": "Task Priority",
                                    "taskType": "Task Type", "taskStatus": "Task Status"]
            Map formatters = [ targetStartDate: dateFmt]
            Map parameters = [title: title, separator: ","]

            exportService.export(params.format, response.outputStream, taskInstanceList, fields, labels, formatters, parameters)
        }

        if(taskInstanceTotal > params.max)
            params.errorMessage = g.message(code:"task.search.calendar.text.too.many.results", args:[params.max])

        // Add some basic params to filterParams.
        filterParams.max = params.max
        filterParams.offset = params.offset?.toInteger() ?: 0

        return[taskInstanceList: taskInstanceList,
                        taskInstanceTotal: taskInstanceTotal,
                        filterParams: filterParams,
                        params: params,
                        showDate: showDate,
                        today: calendarMonthControls.today,
                        previousMonth: calendarMonthControls.previousMonth,
                        nextMonth: calendarMonthControls.nextMonth,
                        previousYear: calendarMonthControls.previousYear,
                        nextYear: calendarMonthControls.nextYear]

    } // searchCalendar

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def show = {

        // In the case of an actionSubmit button, rewrite action name from 'index'.
        if(params._action_Show)
            params.action='show'

        // Used by navigation.
        if(params.id == 'nav') {
            params.id = session.currentTaskId ?: null
            redirect(action: show, id: params.id)
            return
        }

        def showTab = [:]
        switch (params.showTab) {
            case "showProcedureTab":
                showTab.procedure =  new String("true")
                break
            case "showRecurrenceTab":
                showTab.recurrence =  new String("true")
                break
            case "showInventoryTab":
                showTab.inventory = new String("true")
                break
            case "showSubTasksTab":
                showTab.subTasks = new String("true")
                break
            default:
                showTab.task = new String("true")
        }

        def taskInstance = Task.get( params.id )

        if(!taskInstance) {
            flash.message = "Task not found with id ${params.id}"
            redirect(action: 'search')
        }
        else {
            // Remember the current task id for use with navigation.
            session.currentTaskId = params.id

            params.max = 10
            params.order = "desc"
            params.sort = "id"

            def entryFaultList = Entry.withCriteria {
                                                                eq("entryType", EntryType.get(1))
                                                                eq("task", taskInstance)
                                                        }

            def entryCauseList = Entry.withCriteria {
                                                                eq("entryType", EntryType.get(2))
                                                                eq("task", taskInstance)
                                                        }

            def entryWorkDoneList = Entry.withCriteria {
                                                                eq("entryType", EntryType.get(3))
                                                                eq("task", taskInstance)
                                                        }

            def subTaskInstanceList = Task.findAllByParentTaskAndTrash(taskInstance, false, params)
            def subTaskInstanceTotal = Task.countByParentTaskAndTrash(taskInstance, false)

            def inventoryMovementList = InventoryMovement.findAllByTask(taskInstance, [max:100, sort:"id", order:"desc", offset:0])

            def taskModificationList = TaskModification.findAllByTask(taskInstance, [max:100, sort:"id", order:"asc", offset:0])

            def assignedGroupList = taskInstance.assignedGroups.sort { p1, p2 -> p1.personGroup.name.compareToIgnoreCase(p2.personGroup.name) }
            def assignedPersonList = taskInstance.assignedPersons.sort { p1, p2 -> p1.person.firstName.compareToIgnoreCase(p2.person.firstName) }

            def taskProcedureInstance = TaskProcedure.get(taskInstance.taskProcedure?.id)
            def taskProcedureExits = new Boolean("true")
            if(!taskProcedureInstance) {
                taskProcedureExits = false
            }

            params.order = "asc"
            params.sort = "procedureStepNumber"
            def maintenanceActionList = MaintenanceAction.findAllByTaskProcedure(taskProcedureInstance, params)

            def taskRecurringScheduleInstance = TaskRecurringSchedule.get(taskInstance.taskRecurringSchedule?.id)
            def taskRecurringScheduleExits= new Boolean("true")
            if(!taskRecurringScheduleInstance) {
                taskRecurringScheduleExits = false
            }

            return [ taskInstance: taskInstance,
                            entryFaultList: entryFaultList,
                            entryCauseList: entryCauseList,
                            entryWorkDoneList: entryWorkDoneList,
                            taskProcedureInstance: taskProcedureInstance,
                            taskProcedureExits: taskProcedureExits,
                            showTab: showTab,
                            subTaskInstanceList: subTaskInstanceList,
                            subTaskInstanceTotal: subTaskInstanceTotal,
                            subTaskInstanceMax: params.max,
                            maintenanceActionList: maintenanceActionList,
                            taskRecurringScheduleInstance: taskRecurringScheduleInstance,
                            taskRecurringScheduleExits: taskRecurringScheduleExits,
                            inventoryMovementList: inventoryMovementList,
                            taskModificationList: taskModificationList,
                            assignedGroupList: assignedGroupList,
                            assignedPersonList: assignedPersonList]
        }
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def restore = {

        def result = taskService.restore(params)

        if(!result.error) {
                flash.message = "Task ${params.id} has been restored."
                redirect(action: show, id: params.id)
                return
        }

        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        if(result.taskInstance)
            redirect(action: show, id: params.id)
        else
            redirect(action: 'search')

    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def trash = {

        def result = taskService.trash(params)

        if(!result.error) {
                flash.message = "Task ${params.id} has been moved to trash."
                redirect(action: 'search')
                return
        }

        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        if(result.taskInstance)
            redirect(action: show, id: params.id)
        else
            redirect(action: 'search')

    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
    def approve = {

        def result = taskService.approve(params)

        if(!result.error) {
                flash.message = "Task ${params.id} has been approved."
                redirect(action: show, id: params.id)
                return
        }

        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        if(result.taskInstance)
            redirect(action: show, id: params.id)
        else
            redirect(action: 'search')

    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
    def renegeApproval = {

        def result = taskService.renegeApproval(params)

        if(!result.error) {
                flash.message = "Task ${params.id} has had approval removed."
                redirect(action: show, id: params.id)
                return
        }

        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        if(result.taskInstance)
            redirect(action: show, id: params.id)
        else
            redirect(action: 'search')

    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def complete = {

        def result = taskService.complete(params)

        if(!result.error) {
                flash.message = "Task ${params.id} has been completed."
                redirect(action: show, id: params.id)
                return
        }

        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        if(result.taskInstance)
            redirect(action: show, id: params.id)
        else
            redirect(action: 'search')

    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def setAttentionFlag = {

        def result = taskService.setAttentionFlag(params)

        if(!result.error) {
                flash.message = "Task ${params.id} has been flagged for attention."
                redirect(action: show, id: params.id)
                return
        }

        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        if(result.taskInstance)
            redirect(action: show, id: params.id)
        else
            redirect(action: 'search')

    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def clearAttentionFlag = {

        def result = taskService.clearAttentionFlag(params)

        if(!result.error) {
                flash.message = "Task ${params.id} attention flag cleared."
                redirect(action: show, id: params.id)
                return
        }

        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        if(result.taskInstance)
            redirect(action: show, id: params.id)
        else
            redirect(action: 'search')

    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def reopen = {

        def result = taskService.reopen(params)

        if(!result.error) {
                flash.message = "Task ${params.id} has been reopened."
                redirect(action: show, id: params.id)
                return
        }

        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        if(result.taskInstance)
            redirect(action: show, id: params.id)
        else
            redirect(action: 'search')

    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def edit = {

        // In the case of an actionSubmit button, rewrite action name from 'index'.
        if(params._action_Edit)
            params.action='edit'

        // Used by navigation.
        if(params.id == 'nav') {
            params.id = session.currentTaskId ?: null
            redirect(action: edit, id: params.id)
            return
        }

        def taskInstance = Task.get( params.id )

        if(!taskInstance) {
            flash.message = "Task not found with id ${params.id}"
            redirect(action: 'search')
        }
        else {
            // Remember the current task id for use with navigation.
            session.currentTaskId = params.id

            if(taskInstance.trash) {
                flash.message = "You may not edit tasks that are in the trash."
                redirect(action: 'show', id: taskInstance.id)
                return
            }
//             def possibleParentList = taskService.possibleParentList(taskInstance)
//             return [ taskInstance : taskInstance, possibleParentList: possibleParentList ]
            return [ taskInstance : taskInstance ]
        }
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def update = {

        def result = taskService.update(params)

        if(!result.error) {
                flash.message = "Task ${params.id} updated"
                redirect(action: show, id: params.id)
                return
        }

        if(result.error.code == "task.modifications.failedToSave")
            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        render(view:'edit',model:[taskInstance:result.taskInstance.attach()])

    }

    /**
    * The create action is used to create scheduled types of tasks.
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
    def create = {
        def taskInstance = new Task()

        // Set the targetStartDate if specified, used by searchCalendar view.
        if(params.year && params.month && params.day) {
            def date = dateUtilService.makeDate(params.year, params.month, params.day)
            taskInstance.targetStartDate = date
            taskInstance.targetCompletionDate = date
        }

        // Default leadPerson to current user, unless supplied in params.
        taskInstance.leadPerson = authService.currentUser

        // Apply params, overiding anything above.
        taskInstance.properties = params

        def scheduledTaskTypes = taskService.scheduledTaskTypes
        def scheduledTaskPriorities = taskService.scheduledTaskPriorities
        taskInstance.scheduled = true
        taskInstance.taskPriority = scheduledTaskPriorities.default
        return ['taskInstance': taskInstance,
                    'scheduledTaskTypes': scheduledTaskTypes,
                    'scheduledTaskPriorities': scheduledTaskPriorities.list]
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def save = {
        def result = taskService.save(params)

        if(!result.error) {
            flash.message = "Task ${result.taskInstance.id} created."
            redirect(action: 'show', id: result.taskInstance.id)
            return
        }

        if(result.error.code == "task.modifications.failedToSave")
            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)


        def scheduledTaskTypes = taskService.scheduledTaskTypes
        def scheduledTaskPriorities = taskService.scheduledTaskPriorities
        render(view:'create', model:[taskInstance:result.taskInstance,
                                                    'scheduledTaskTypes': scheduledTaskTypes,
                                                    'scheduledTaskPriorities': scheduledTaskPriorities.list])
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def listSubTasks = {
        def parentTaskInstance = Task.get(params.id)

        if(!parentTaskInstance) {
            flash.message = "Task not found with id ${params.id}"
            redirect(action: 'search')
        }
        else {
        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
        def subTaskInstanceList = Task.findAllByParentTaskAndTrash(parentTaskInstance, false, params)
        def subTaskInstanceTotal = Task.countByParentTaskAndTrash(parentTaskInstance, false)

        [ taskInstanceList: subTaskInstanceList,
            taskInstanceTotal:  subTaskInstanceTotal,
            parentTaskInstance: parentTaskInstance]
        }
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def createSubTask = {
        def parentTaskInstance = Task.get(params.id)

        if(parentTaskInstance) {

            def result = taskService.createSubTask(parentTaskInstance)
            if(!result.error) {
                flash.message = "Sub Task ${result.taskInstance.id} created, please edit and update to your requirements."
                redirect(action: 'edit', id: result.taskInstance.id)
            }
            else {
                if(result.taskInstance.errors.hasFieldErrors("parentTask")) {
                    flash.errorMessage = g.message(code:"task.operationNotPermittedOnTaskInTrash")
                    redirect(action: 'show', id:  parentTaskInstance.id)
                }
                else {
                    render(view: 'create', model:[taskInstance: result.taskInstance])
                }
            }
        }

        else {
            flash.message = "Task not found with id ${params.id}"
            redirect(action: 'search')
        }
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def createUnscheduled = {
        def taskInstance = new Task()

        // Default leadPerson to current user, unless supplied in params.
        taskInstance.leadPerson = authService.currentUser
        taskInstance.properties = params

        // Always for Unscheduled task.
        taskInstance.taskType = TaskType.get(2) // Unscheduled Breakin.
        def unscheduledTaskPriorities = taskService.unscheduledTaskPriorities
        taskInstance.taskPriority = unscheduledTaskPriorities.default

        return ['taskInstance': taskInstance, 'unscheduledTaskPriorities': unscheduledTaskPriorities.list]
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def saveUnscheduled = {
        def result = taskService.saveUnscheduled(params)

        if(!result.error) {
            flash.message = "Task ${result.taskInstance.id} created."
            redirect(action: 'show', id: result.taskInstance.id)
            return
        }

        if(result.error.code == "task.modifications.failedToSave")
            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        def unscheduledTaskPriorities = taskService.unscheduledTaskPriorities

        render(view:'createUnscheduled',
                    model: ['taskInstance': result.taskInstance, 'unscheduledTaskPriorities': unscheduledTaskPriorities.list])
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def createImmediateCallout = {
        def taskInstance = new Task()

        def entryFaultInstance = new Entry(entryType: EntryType.get(1))  // Fault.
        def entryCauseInstance = new Entry(entryType: EntryType.get(2))  // Cause.
        def entryWorkDoneInstance = new Entry(entryType: EntryType.get(3))  // Work Done.

        return ['taskInstance': taskInstance,
                        'entryFaultInstance': entryFaultInstance,
                        'entryCauseInstance': entryCauseInstance,
                        'entryWorkDoneInstance': entryWorkDoneInstance]
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def saveImmediateCallout = {
        def result = taskService.saveImmediateCallout(params)

        if(!result.error) {
            flash.message = "Task ${result.taskInstance.id} created."
            redirect(action: 'show', id: result.taskInstance.id)
            return
        }

        if(result.error.code == "task.modifications.failedToSave")
            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)

        render(view:'createImmediateCallout',
                    model: ['taskInstance': result.taskInstance,
                                'entryFaultInstance': result.entryFaultInstance,
                                'entryCauseInstance': result.entryCauseInstance,
                                'entryWorkDoneInstance': result.entryWorkDoneInstance])

    }

    /**
    * Render a users total work done hours.
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    def workDone = {
        def result = taskSearchService.getWorkDone(params, RCU.getLocale(request))

        params.message = result.message

        return[entries: result.entries,
                    totalEntries : result.totalEntries,
                    startOfDay: result.startOfDay,
                    person: result.person,
                    totalHours: result.totalHours,
                    totalMinutes: result.totalMinutes]
    } // workDone

    /**
    * Get some integers for use by the month control links.
    */
    private getCalendarMonthControls(Date showDate) {
        def result = [:]
        result.today = [:]
        result.today.date = new Date()
        result.today.month = dateUtilService.getMonthFromDate(result.today.date)
        result.today.year = dateUtilService.getYearFromDate(result.today.date)
        result.nextMonth = [:]
        result.nextMonth.date = dateUtilService.plusMonth(showDate)
        result.nextMonth.month = dateUtilService.getMonthFromDate(result.nextMonth.date)
        result.nextMonth.year = dateUtilService.getYearFromDate(result.nextMonth.date)
        result.previousMonth =  [:]
        result.previousMonth.date = dateUtilService.plusMonth(showDate, -1)
        result.previousMonth.month = dateUtilService.getMonthFromDate(result.previousMonth.date)
        result.previousMonth.year = dateUtilService.getYearFromDate(result.previousMonth.date)
        result.nextYear = [:]
        result.nextYear.date = dateUtilService.plusYear(showDate)
        result.nextYear.month = dateUtilService.getMonthFromDate(result.nextYear.date)
        result.nextYear.year = dateUtilService.getYearFromDate(result.nextYear.date)
        result.previousYear = [:]
        result.previousYear.date = dateUtilService.plusYear(showDate, -1)
        result.previousYear.month = dateUtilService.getMonthFromDate(result.previousYear.date)
        result.previousYear.year = dateUtilService.getYearFromDate(result.previousYear.date)
        return result
    }

} // end of class.
