import grails.test.*

/**
* Integration tests for TaskSearchService.
*/
class TaskSearchServiceTests extends GroovyTestCase {

    // Data will be saved, not rolled back.
    // Be sure to clean up in tearDown().
    boolean transactional = false

    def taskService
    def dateUtilService
    def taskSearchService
    def assignedGroupService
    def assignedPersonService

    def taskA
    def taskB
    def taskCount = 0

    // Setup is called before each test.
    protected void setUp() {
        super.setUp()

        // Check environment state.
        assert Task.count() == 0
        assert Entry.count() == 0
        assert TaskModification.count() == 0

        def p = [:]
        def result

        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
                taskPriority:TaskPriority.get(2),
                taskType:TaskType.get(1),
                leadPerson:Person.get(1),
                description:"TestA",
                comment:"Service test task.",
                targetStartDate: dateUtilService.today,
                targetCompletionDate: dateUtilService.today]

        result = taskService.save(p)
        assert result.error == null
        taskCount++
        taskA = result.taskInstance.refresh()

        p.description = "TestB"
        result = taskService.save(p)
        assert result.error == null
        taskCount++
        taskB = result.taskInstance.refresh()
    }

    // Tear down is called after each test.
    protected void tearDown() {
        super.tearDown()

        taskService.delete(taskA)
        taskService.delete(taskB)

        // Ensure that we leave environment clean.
        assert Task.count() == 0
        assert TaskModification.count() == 0
        assert Entry.count() == 0
    }


    /**
    * Test GetTasks.
    */
    void testGetTasks() {
        // Todays tasks should be returned.
        def tasks = taskSearchService.getTasks([:])
        assert tasks.totalCount == taskCount

        // Tasks in the trash should not be returned.
        taskA.trash = true
        taskA.save(flush:true)
        assert taskSearchService.getTasks([:]).totalCount == taskCount - 1
        taskB.trash = true
        taskB.save(flush:true)
        assert taskSearchService.getTasks([:]).totalCount == taskCount - 2

        // Restored tasks should be returned.
        taskA.trash = false
        taskA.save(flush:true)
        assert taskSearchService.getTasks([:]).totalCount == taskCount - 1
        taskB.trash = false
        taskB.save(flush:true)
        assert taskSearchService.getTasks([:]).totalCount == taskCount

        // Tomorrows tasks should not be returned.
        taskA.targetStartDate = dateUtilService.tomorrow
        taskA.targetCompletionDate = dateUtilService.tomorrow
        taskA.save(flush:true)
        assert taskSearchService.getTasks([:]).totalCount == taskCount - 1

        // Tomorrows tasks should be returned, if we ask for them.
        assert taskSearchService.getTasks([:], dateUtilService.today, dateUtilService.tomorrow+1).totalCount == taskCount

        // Yesterdays tasks should not be returned.
        taskA.targetStartDate = dateUtilService.yesterday
        taskA.targetCompletionDate = dateUtilService.yesterday
        taskA.save(flush:true)
        assert taskSearchService.getTasks([:]).totalCount == taskCount - 1

        // Yesterdays tasks should be returned, if we ask for them.
        assert taskSearchService.getTasks([:], dateUtilService.yesterday, dateUtilService.tomorrow).totalCount == taskCount

        // Tasks that span today should be returned.
        taskA.targetStartDate = dateUtilService.yesterday
        taskA.targetCompletionDate = dateUtilService.tomorrow
        taskA.save(flush:true)
        assert taskSearchService.getTasks([:]).totalCount == taskCount
    } // testGetTasks()

    /**
    * Test GetPersonsTasks.
    */
    void testGetPersonsTasks() {

        def p = [:]
        def params = [:]

        // Todays tasks should be returned, since Person #1 is lead and created the tasks.
        def tasks = taskSearchService.getPersonsTasks(params)
        assert tasks.totalCount == taskCount

        // Tasks in the trash should not be returned.
        taskA.trash = true
        taskA.save(flush:true)
        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 1
        taskB.trash = true
        taskB.save(flush:true)
        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 2

        // Restored tasks should be returned.
        taskA.trash = false
        taskA.save(flush:true)
        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 1
        taskB.trash = false
        taskB.save(flush:true)
        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount

        // Tomorrows tasks should not be returned.
        taskA.targetStartDate = dateUtilService.tomorrow
        taskA.targetCompletionDate = dateUtilService.tomorrow
        taskA.save(flush:true)
        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 1

        // Tomorrows tasks should be returned, if we ask for them.
        assert taskSearchService.getPersonsTasks(params, null, dateUtilService.today, dateUtilService.tomorrow+1).totalCount == taskCount

        // Yesterdays tasks should not be returned.
        taskA.targetStartDate = dateUtilService.yesterday
        taskA.targetCompletionDate = dateUtilService.yesterday
        taskA.save(flush:true)
        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 1

        // Yesterdays tasks should be returned, if we ask for them.
        assert taskSearchService.getPersonsTasks(params, null, dateUtilService.yesterday, dateUtilService.tomorrow).totalCount == taskCount

        // Tasks that span today should be returned.
        taskA.targetStartDate = dateUtilService.yesterday
        taskA.targetCompletionDate = dateUtilService.tomorrow
        taskA.save(flush:true)
        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount

        // Tasks for a different person should not be returned.
        taskA.leadPerson = Person.get(2)
        taskA.save(flush:true)
        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 1

        // Tasks for a specified leadPerson should be returned.
        // But only if approved since this person did not create the tasks.
        taskA.leadPerson = Person.get(2)
        taskA.save(flush:true)
        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 0
        taskA.approved = true
        taskA.save(flush:true)
        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 1
        // Moving the task to the trash, stops it being returned.
        taskA.trash = true
        taskA.save(flush:true)
        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 0

        // Tasks assigned to a person should be returned.
        // But only if approved.
        p = [person: Person.get(2),
                task: taskB,
                estimatedHour: 1,
                estimatedMinute: 20]
        assert assignedPersonService.save(p).error == null
        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 0
        taskB.approved = true
        taskB.save(flush:true)
        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 1

        // Tasks assigned to a person via a group should be returned.
        // But only if approved.
        Person.get(2).addToPersonGroups(PersonGroup.read(1)).save(flush:true)
        taskA.trash = false
        taskA.approved = false
        taskA.save(flush:true)
        p = [personGroup: PersonGroup.read(1),
                task: taskA,
                estimatedHour: 2,
                estimatedMinute: 30]
        assert assignedGroupService.save(p).error == null
        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 1 // Only taskB from above.
        taskA.approved = true
        taskA.save(flush:true)
        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 2 // taskA and taskB.

    } // testGetTasks()

    void testGetBudgetTasks() {

        def tasks
        def params = [:]
        def today = dateUtilService.today
        def yesterday = dateUtilService.yesterday
        def tomorrow = dateUtilService.tomorrow
        def unplanned = TaskBudgetStatus.read(1)
        def planned = TaskBudgetStatus.read(2)

        assert planned != null
        assert unplanned != null

        // Default is to return planned.
        // TaskA and taskB should be unplanned and therefore not returned.
        tasks = taskSearchService.getBudgetTasks(params)
        assert tasks.totalCount == 0
        tasks = taskSearchService.getBudgetTasks(params, planned)
        assert tasks.totalCount == 0

        tasks = taskSearchService.getBudgetTasks(params, unplanned)
        assert tasks.totalCount == taskCount
        assert tasks.contains(taskA)
        assert tasks.contains(taskB)

        // Planned tasks are returned.
        taskA.taskBudgetStatus = planned
        taskA.save(flush:true)
        tasks = taskSearchService.getBudgetTasks(params, planned)
        assert tasks.totalCount == 1
        assert tasks.contains(taskA)

        // Tasks are returned when dates and budget status are specified.
        tasks = taskSearchService.getBudgetTasks(params, planned, today, tomorrow)
        assert tasks.totalCount == 1
        assert tasks.contains(taskA)
        tasks = taskSearchService.getBudgetTasks(params, unplanned, today, tomorrow)
        assert tasks.totalCount == 1
        assert tasks.contains(taskB)

        // No tasks for yesterday
        tasks = taskSearchService.getBudgetTasks(params, null, yesterday, today)
        assert tasks.totalCount == 0

        // Tasks that span today are returned.
        taskA.targetStartDate = yesterday
        taskA.targetCompletionDate = tomorrow+2
        taskA.save(flush:true)
        tasks = taskSearchService.getBudgetTasks(params, planned, today, tomorrow)
        assert tasks.totalCount == 1
        assert tasks.contains(taskA)

    } // testGetBudgetTasks()

} // end class