Index: trunk/grails-app/services/TaskSearchService.groovy
===================================================================
--- trunk/grails-app/services/TaskSearchService.groovy	(revision 700)
+++ trunk/grails-app/services/TaskSearchService.groovy	(revision 701)
@@ -1,3 +1,4 @@
 import grails.orm.PagedResultList
+import org.hibernate.FetchMode as FM
 
 /**
@@ -348,3 +349,123 @@
     } // getWorkDone()
 
+    /**
+    * Get work load by task group and date.
+    * Group ID's and date range may be specified in params otherwise no group and today are used.
+    * @param params The request params.
+    * @returns A map containing the results.
+    */
+    def getWorkLoad(params, locale) {
+        def result = [:]
+        def max = 1000
+
+        // TaskStatus..
+        result.taskStatusList = []
+        if(params.taskStatusList instanceof String)
+            result.taskStatusList << TaskStatus.get(params.taskStatusList.toInteger())
+        else if(params.taskStatusList)
+            result.taskStatusList = TaskStatus.getAll( params.taskStatusList.collect {it.toInteger()} )
+
+        // TaskGroups.
+        result.taskGroups = []
+        if(params.taskGroups instanceof String)
+            result.taskGroups << TaskGroup.get(params.taskGroups.toInteger())
+        else if(params.taskGroups)
+            result.taskGroups = TaskGroup.getAll( params.taskGroups.collect {it.toInteger()} )
+
+        // Start Date.
+        if(params.startDate_year && params.startDate_month && params.startDate_day)
+            result.startDate = dateUtilService.makeDate(params.startDate_year, params.startDate_month, params.startDate_day)
+        else
+            result.startDate = dateUtilService.today
+
+        // End Date.
+        if(params.endDate_year && params.endDate_month && params.endDate_day)
+            result.endDate = dateUtilService.makeDate(params.endDate_year, params.endDate_month, params.endDate_day)
+        else
+            result.endDate = result.startDate
+
+        // Normalise date range.
+        if(result.endDate < result.startDate)
+            result.endDate = result.startDate
+
+        def formattedStartDate = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.startDate)
+        def formattedEndDate = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.endDate)
+
+        def getMessage = { Map m ->
+            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
+        }
+
+        result.tasks = new PagedResultList([], 0)
+
+        if(result.taskGroups && result.taskStatusList) {
+
+            result.tasks = Task.createCriteria().list(max: max) {
+                eq("trash", false)
+                lt("targetStartDate", result.endDate+1)
+                ge("targetCompletionDate", result.startDate)
+                inList("taskStatus", result.taskStatusList)
+                inList("taskGroup", result.taskGroups)
+                order("taskStatus", "asc")
+                order("taskPriority", "asc")
+                order("targetStartDate", "asc")
+                fetchMode("assignedGroups", FM.EAGER)
+                fetchMode("assignedGroups.personGroup", FM.EAGER)
+            } // createCriteria
+
+        }
+
+        result.tasks.list.unique()
+        result.totalHours = 0
+        result.totalMinutes = 0
+        result.workLoadGroups = [:]
+
+        // Exit early!
+        if(result.tasks.totalCount > result.tasks.size()) {
+            result.errorMessage = getMessage(code:"task.search.text.work.load.too.many.results",
+                                                                args:[result.tasks.size(), result.tasks.totalCount])
+            return result
+        }
+        else if(result.tasks.size() > 0)
+            result.message = getMessage(code:"task.search.text.work.load.message",
+                                                                args:[formattedStartDate, formattedEndDate])
+        else
+            result.message = getMessage(code:"task.search.text.work.load.none.found",
+                                                                args:[formattedStartDate, formattedEndDate])
+
+        // Collect all assignedGroups.
+        def assignedGroups = []
+        for(task in result.tasks) {
+            for(assignedGroup in task.assignedGroups) {
+                assignedGroups << assignedGroup
+            }
+        }
+
+        // Calculate work load for each personGroup and minute totals.
+        def tempHours = 0
+        def tempMinutes = 0
+        def personGroup
+        for(assignedGroup in assignedGroups) {
+            personGroup = assignedGroup.personGroup
+            if(!result.workLoadGroups.containsKey(personGroup)) {
+                result.workLoadGroups[personGroup] = [hours: 0, minutes: 0]
+            }
+
+            tempMinutes = (assignedGroup.estimatedHour*60) + assignedGroup.estimatedMinute
+            result.totalMinutes += tempMinutes
+            result.workLoadGroups[personGroup].minutes += tempMinutes
+        }
+
+        // Resolve totals and sort.
+        result.workLoadGroups.each { workLoadGroup ->
+            workLoadGroup.value.hours =  (workLoadGroup.value.minutes / 60).toInteger()
+            workLoadGroup.value.minutes = workLoadGroup.value.minutes % 60
+        }
+        result.workLoadGroups = result.workLoadGroups.sort { p1, p2 -> p1.key.name.compareToIgnoreCase(p2.key.name) }
+        result.totalHours = (result.totalMinutes / 60).toInteger()
+        result.totalMinutes = result.totalMinutes % 60
+
+        // Success.
+        return result
+    } // getWorkLoad()
+
 } // end class
