Index: trunk/grails-app/domain/TaskRecurringSchedule.groovy
===================================================================
--- trunk/grails-app/domain/TaskRecurringSchedule.groovy	(revision 444)
+++ trunk/grails-app/domain/TaskRecurringSchedule.groovy	(revision 445)
@@ -12,8 +12,10 @@
     Integer generateAhead = 1
     Integer subTasksGenerated = 0
+    Integer maxSubTasks = 0
     Date nextGenerationDate = new Date()
-    Date nextTargetStartDate = new Date()
+    Date nextTargetStartDate = new Date()+1
     Date nextTargetCompletionDate = new Date()
     boolean enabled = true
+    boolean useTargetCompletionDate = false
 
 //     static hasMany = []
Index: trunk/grails-app/i18n/messages.properties
===================================================================
--- trunk/grails-app/i18n/messages.properties	(revision 444)
+++ trunk/grails-app/i18n/messages.properties	(revision 445)
@@ -129,9 +129,17 @@
 taskRecurringSchedule.generateAhead=Generate Ahead
 taskRecurringSchedule.generateAhead.help=How far ahead of the next target start date to generate sub tasks. \
-This allows work packs to be built and work load to be seen and planned. \
-Only generate ahead as far as short term planning is done, since all generated sub task values will be set and therefore \
-time consuming to change.
+    This allows work packs to be built and work load to be seen and planned. \
+    Only generate ahead as far as short term planning is done, since all generated sub task \
+    values will be set and therefore time consuming to change.
+taskRecurringSchedule.maxSubTasks=Max Sub Tasks
+taskRecurringSchedule.maxSubTasks.help=Maximum number of sub tasks to generate. Set to 0 \
+    for no limit.
+taskRecurringSchedule.useTargetCompletionDate=Target Completion
+taskRecurringSchedule.useTargetCompletionDate.help=On to use the parent task's target completion date. \
+    Off to continue generation past the parent task's target completion date.
 taskRecurringSchedule.enabled=Enabled
-taskRecurringSchedule.enabled.help=On to enable automatic sub task generation. Off to stop automatic sub task generation.
+taskRecurringSchedule.enabled.help=On to enable automatic sub task generation. \
+    Off to stop automatic sub task generation. <br /><br />\
+    The system will turn this off if there are no further sub tasks to be generated.
 
 task.primaryAsset=Primary Asset
Index: trunk/grails-app/services/TaskRecurringScheduleService.groovy
===================================================================
--- trunk/grails-app/services/TaskRecurringScheduleService.groovy	(revision 444)
+++ trunk/grails-app/services/TaskRecurringScheduleService.groovy	(revision 445)
@@ -15,6 +15,4 @@
     def generateAll() {
 
-        def taskRecurringScheduleList = TaskRecurringSchedule.findAllByEnabled(true)
-
         // Prevent errors if base data has not yet been created.
         if(!appConfigService.exists("baseDataCreated")) {
@@ -26,32 +24,77 @@
         }
 
-        taskRecurringScheduleList.each() {
+        def p = [:]
+        def targetCompletionDate
+        def nextTargetCompletionDate
+        def tomorrow = dateUtilService.tomorrow
+
+        def taskRecurringScheduleList = TaskRecurringSchedule.findAllByEnabled(true)
+
+        // Stop generation if max reached.
+        def maxSubTasksReached = {
+            if( (it.maxSubTasks > 0) && (it.subTasksGenerated >= it.maxSubTasks) ) {
+                it.enabled = false
+                return true
+            }
+            return false
+        }
+
+        // Stop generation by targetCompletionDate.
+        def targetCompletionDateReached = {
+            if( it.useTargetCompletionDate) {
+                targetCompletionDate = dateUtilService.getMidnight(it.task.targetCompletionDate)
+                nextTargetCompletionDate = dateUtilService.getMidnight(it.nextTargetCompletionDate)
+                if(nextTargetCompletionDate > targetCompletionDate) {
+                    it.enabled = false
+                    return true
+                }
+            }
+            return false
+        }
+
+        // Main loop.
+        for(it in taskRecurringScheduleList) {
+
+            if(maxSubTasksReached(it))
+                continue
+
+            if(targetCompletionDateReached(it))
+                continue
 
             if (dateUtilService.tomorrow > it.nextGenerationDate) {
-                    def p = [:]
+                p = [:]
 
-                    // Build the required params.
-                    p.targetStartDate = it.nextTargetStartDate
-                    p.targetCompletionDate = it.nextTargetCompletionDate
-                    if(it.task.taskProcedure) p.taskProcedure = it.task.taskProcedure
-                    if(it.task.assignedGroups) p.assignedGroups = new ArrayList(it.task.assignedGroups)
-                    if(it.task.assignedPersons) p.assignedPersons = new ArrayList(it.task.assignedPersons)
+                // Build the subTask params.
+                p.targetStartDate = it.nextTargetStartDate
+                p.targetCompletionDate = it.nextTargetCompletionDate
+                if(it.task.taskProcedure) p.taskProcedure = it.task.taskProcedure
+                if(it.task.assignedGroups) p.assignedGroups = new ArrayList(it.task.assignedGroups)
+                if(it.task.assignedPersons) p.assignedPersons = new ArrayList(it.task.assignedPersons)
 
-                    def result = taskService.createSubTask(it.task, p)
-                    if( !result.error ) {
-                        it.lastGeneratedSubTask = result.taskInstance
-                        it.subTasksGenerated++
-                        it.setNextTargetStartDate()
-                        it.setNextGenerationDate()
-                        it.setNextTargetCompletionDate()
-                    }
-                    else {
-                        log.error "Sub task generation for recurring schedule ${it.id} failed."
-                        log.error result.taskInstance.errors
-                    }
+                def result = taskService.createSubTask(it.task, p)
+                if( !result.error ) {
+                    it.lastGeneratedSubTask = result.taskInstance
+                    it.subTasksGenerated++
+                    it.setNextTargetStartDate()
+                    it.setNextGenerationDate()
+                    it.setNextTargetCompletionDate()
+                }
+                else {
+                    log.error "Sub task generation for recurring schedule ${it.id} failed."
+                    log.error result.taskInstance.errors
+                }
             }
 
-        }
-    }
+            // Run the completion reached checks for a second time so
+            // that this recurring schedule does not run again if
+            // there are no more subTasks to be generated.
+            if(maxSubTasksReached(it))
+                continue
+
+            if(targetCompletionDateReached(it))
+                continue
+
+        } // for()
+    } // generateAll()
 
     /**
Index: trunk/grails-app/views/taskDetailed/show.gsp
===================================================================
--- trunk/grails-app/views/taskDetailed/show.gsp	(revision 444)
+++ trunk/grails-app/views/taskDetailed/show.gsp	(revision 445)
@@ -561,4 +561,10 @@
 
                                         <tr class="prop">
+                                            <td valign="top" class="name">Enabled:</td>
+
+                                            <td valign="top" class="value">${fieldValue(bean:taskRecurringScheduleInstance, field:'enabled')}</td>
+                                        </tr>
+
+                                        <tr class="prop">
                                             <td valign="top" class="name">Next Generation Date:</td>
 
@@ -598,10 +604,4 @@
                                                 <g:formatDate date="${taskRecurringScheduleInstance.nextTargetCompletionDate}" format="EEE, dd-MMM-yyyy"/>
                                             </td>
-                                        </tr>
-
-                                        <tr class="prop">
-                                            <td valign="top" class="name">Enabled:</td>
-
-                                            <td valign="top" class="value">${fieldValue(bean:taskRecurringScheduleInstance, field:'enabled')}</td>
                                         </tr>
 
Index: trunk/grails-app/views/taskRecurringScheduleDetailed/create.gsp
===================================================================
--- trunk/grails-app/views/taskRecurringScheduleDetailed/create.gsp	(revision 444)
+++ trunk/grails-app/views/taskRecurringScheduleDetailed/create.gsp	(revision 445)
@@ -81,4 +81,29 @@
                                 </td>
                             </tr>
+                      
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="maxSubTasks">Max Sub Tasks:</label>
+                                </td>
+                                <td valign="top" class="value" >
+                                    <input type="text" class="time ${hasErrors(bean:taskRecurringScheduleInstance,field:'maxSubTasks','errors')}"
+                                        id="maxSubTasks" name="maxSubTasks" value="${fieldValue(bean:taskRecurringScheduleInstance,field:'maxSubTasks')}" />
+                                        <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.maxSubTasks" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="useTargetCompletionDate">Use Target Completion Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskRecurringScheduleInstance,field:'useTargetCompletionDate','errors')}">
+                                    <g:checkBox name="useTargetCompletionDate"
+                                                            value="${taskRecurringScheduleInstance?.useTargetCompletionDate}" >
+                                    </g:checkBox>
+                                    <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.useTargetCompletionDate" />
+                                    <g:formatDate date="${taskRecurringScheduleInstance.task.targetCompletionDate}"
+                                                                    format="EEE, dd-MMM-yyyy"/>
+                                </td>
+                            </tr>
                         
                             <tr class="prop">
Index: trunk/grails-app/views/taskRecurringScheduleDetailed/edit.gsp
===================================================================
--- trunk/grails-app/views/taskRecurringScheduleDetailed/edit.gsp	(revision 444)
+++ trunk/grails-app/views/taskRecurringScheduleDetailed/edit.gsp	(revision 445)
@@ -34,4 +34,14 @@
                                 <td valign="top" name="recForTask" class="value">
                                     <g:link controller="taskDetailed" action="show" id="${taskRecurringScheduleInstance?.task?.id}">${taskRecurringScheduleInstance?.task?.encodeAsHTML()}</g:link>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="enabled">Enabled:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskRecurringScheduleInstance,field:'enabled','errors')}">
+                                    <g:checkBox name="enabled" value="${taskRecurringScheduleInstance?.enabled}" ></g:checkBox>
+                                        <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.enabled" />
                                 </td>
                             </tr>
@@ -82,12 +92,27 @@
                                 </td>
                             </tr>
+                      
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="maxSubTasks">Max Sub Tasks:</label>
+                                </td>
+                                <td valign="top" class="value" >
+                                    <input type="text" class="time ${hasErrors(bean:taskRecurringScheduleInstance,field:'maxSubTasks','errors')}"
+                                        id="maxSubTasks" name="maxSubTasks" value="${fieldValue(bean:taskRecurringScheduleInstance,field:'maxSubTasks')}" />
+                                        <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.maxSubTasks" />
+                                </td>
+                            </tr>
                         
                             <tr class="prop">
                                 <td valign="top" class="name">
-                                    <label for="enabled">Enabled:</label>
+                                    <label for="useTargetCompletionDate">Use Target Completion Date:</label>
                                 </td>
-                                <td valign="top" class="value ${hasErrors(bean:taskRecurringScheduleInstance,field:'enabled','errors')}">
-                                    <g:checkBox name="enabled" value="${taskRecurringScheduleInstance?.enabled}" ></g:checkBox>
-                                        <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.enabled" />
+                                <td valign="top" class="value ${hasErrors(bean:taskRecurringScheduleInstance,field:'useTargetCompletionDate','errors')}">
+                                    <g:checkBox name="useTargetCompletionDate"
+                                                                value="${taskRecurringScheduleInstance?.useTargetCompletionDate}" >
+                                    </g:checkBox>
+                                    <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.useTargetCompletionDate" />
+                                    <g:formatDate date="${taskRecurringScheduleInstance.task.targetCompletionDate}"
+                                                                    format="EEE, dd-MMM-yyyy"/>
                                 </td>
                             </tr>
Index: trunk/grails-app/views/taskRecurringScheduleDetailed/show.gsp
===================================================================
--- trunk/grails-app/views/taskRecurringScheduleDetailed/show.gsp	(revision 444)
+++ trunk/grails-app/views/taskRecurringScheduleDetailed/show.gsp	(revision 445)
@@ -33,4 +33,21 @@
                             <td valign="top" class="value">${taskRecurringScheduleInstance.encodeAsHTML()}</td>
                         </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Enabled:</td>
+
+                            <td valign="top" class="value">${fieldValue(bean:taskRecurringScheduleInstance, field:'enabled')}</td>
+                        </tr>
+
+                        <g:if test="${taskRecurringScheduleInstance.useTargetCompletionDate}" >
+                            <tr class="prop">
+                                <td valign="top" class="name">Task Target Completion:</td>
+
+                                <td valign="top" class="value">
+                                    <g:formatDate date="${taskRecurringScheduleInstance.task.targetCompletionDate}"
+                                                                    format="EEE, dd-MMM-yyyy"/>
+                                </td>
+                            </tr>
+                        </g:if>
 
                         <tr class="prop">
@@ -74,10 +91,4 @@
                         </tr>
 
-                        <tr class="prop">
-                            <td valign="top" class="name">Enabled:</td>
-
-                            <td valign="top" class="value">${fieldValue(bean:taskRecurringScheduleInstance, field:'enabled')}</td>
-                        </tr>
-
                     </tbody>
                 </table>
@@ -100,4 +111,14 @@
                             </td>
                         </tr>
+
+                        <g:if test="${taskRecurringScheduleInstance.maxSubTasks > 0}" >
+                            <tr class="prop">
+                                <td valign="top" class="name">Max Sub Tasks:</td>
+
+                                <td valign="top" class="value">
+                                    ${fieldValue(bean:taskRecurringScheduleInstance, field:'maxSubTasks')}
+                                </td>
+                            </tr>
+                        </g:if>
 
                         <g:if test="${taskRecurringScheduleInstance.lastGeneratedSubTask}">
