import org.hibernate.FetchMode as FM

class AssignedGroupService {

    boolean transactional = false

    def authService

    def delete(params) {
        AssignedGroup.withTransaction { status ->
            def result = [:]

            def fail = { Map m ->
                status.setRollbackOnly()
                if(result.assignedGroupInstance && m.field)
                    result.assignedGroupInstance.errors.rejectValue(m.field, m.code)
                result.error = [ code: m.code, args: ["AssignedGroup", params.id] ]
                return result
            }

            result.assignedGroupInstance = AssignedGroup.get(params.id)

            if(!result.assignedGroupInstance)
                return fail(code:"default.not.found")

            def taskModification = new TaskModification(person: authService.currentUser,
                                                    taskModificationType: TaskModificationType.get(10),
                                                    task: result.assignedGroupInstance.task)

            if(!taskModification.save())
                return fail(field:"taskModifications", code:"task.modifications.failedToSave")

            try {
                result.assignedGroupInstance.delete(flush:true)
                return result //Success.
            }
            catch(org.springframework.dao.DataIntegrityViolationException e) {
                return fail(code:"default.delete.failure")
            }

        } //end withTransaction
    } // end delete()

    def edit(params) {
        def result = [:]
        def fail = { Map m ->
            result.error = [ code: m.code, args: ["AssignedGroup", params.id] ]
            return result
        }

        result.assignedGroupInstance = AssignedGroup.createCriteria().get {
            idEq(params.id.toLong())
            fetchMode("personGroup", FM.EAGER)
            fetchMode("personGroup.persons", FM.EAGER)
        }

        if(!result.assignedGroupInstance)
            return fail(code:"default.not.found")

        result.personGroup = result.assignedGroupInstance.personGroup
        result.personsInGroup = result.personGroup.persons.sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }

        // Success.
        return result
    }

    def update(params) {
        AssignedGroup.withTransaction { status ->
            def result = [:]

            def fail = { Map m ->
                status.setRollbackOnly()
                if(result.assignedGroupInstance && m.field)
                    result.assignedGroupInstance.errors.rejectValue(m.field, m.code)
                result.error = [ code: m.code, args: ["AssignedGroup", params.id] ]
                return result
            }

            result.personGroup = PersonGroup.createCriteria().get {
                idEq(params.personGroup.id.toLong())
                fetchMode("persons", FM.EAGER)
            }

            // Prevent a null property reference.
            if(!result.personGroup)
                return fail(code:"personGroup.not.found")

            result.personsInGroup = result.personGroup.persons.sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }

            result.assignedGroupInstance = AssignedGroup.get(params.id)

            if(!result.assignedGroupInstance)
                return fail(code:"default.not.found")

            // Optimistic locking check.
            if(params.version) {
                if(result.assignedGroupInstance.version > params.version.toLong())
                    return fail(field:"version", code:"default.optimistic.locking.failure")
            }

            result.assignedGroupInstance.properties = params

            if(result.assignedGroupInstance.hasErrors() || !result.assignedGroupInstance.save())
                return fail(code:"default.update.failure")

            def taskModification = new TaskModification(person: authService.currentUser,
                                                    taskModificationType: TaskModificationType.get(10),
                                                    task: result.assignedGroupInstance.task)

            if(!taskModification.save())
                return fail(field:"taskModifications", code:"task.modifications.failedToSave")

            // Success.
            return result

        } //end withTransaction
    }  // end update()

    def create(params) {
        def result = [:]
        def fail = { Map m ->
            result.error = [ code: m.code, args: ["AssignedGroup", params.id] ]
            return result
        }

        if(!params.task?.id)
            fail(code:"assignedGroup.task.not.found")

        result.assignedGroupInstance = new AssignedGroup()
        result.assignedGroupInstance.properties = params

        result.personGroup = PersonGroup.list().sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }[0] // Get the first result.
        result.personsInGroup = result.personGroup.persons.sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }

        // Success.
        return result
    }

    def save(params) {
        AssignedGroup.withTransaction { status ->
            def result = [:]

            def fail = { Map m ->
                status.setRollbackOnly()
                if(result.assignedGroupInstance && m.field)
                    result.assignedGroupInstance.errors.rejectValue(m.field, m.code)
                result.error = [ code: m.code, args: ["AssignedGroup", params.id] ]
                return result
            }

            result.personGroup = PersonGroup.createCriteria().get {
                idEq(params.personGroup.id.toLong())
                fetchMode("persons", FM.EAGER)
            }

            // Prevent a null property reference.
            if(!result.personGroup)
                return fail(code:"personGroup.not.found")

            result.personsInGroup = result.personGroup.persons.sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }

            result.assignedGroupInstance = new AssignedGroup()
            result.assignedGroupInstance.properties = params

            if(result.assignedGroupInstance.hasErrors() || !result.assignedGroupInstance.save())
                return fail(code:"default.create.failure")

            // Record a taskModification for everyone except "system".
            if(authService.currentUser.id != 1) {
                def taskModification = new TaskModification(person: authService.currentUser,
                                                        taskModificationType: TaskModificationType.get(10),
                                                        task: result.assignedGroupInstance.task)

                if(!taskModification.save())
                    return fail(field:"taskModifications", code:"task.modifications.failedToSave")
            }

            // Success.
            return result

        } //end withTransaction
    } // end save()

    def personsInGroup(params) {
        def result = [:]

        def fail = { Map m ->
            result.error = [ code: m.code, args: ["PersonGroup", params.personGroup?.id] ]
            return result
        }

        if(!params.personGroup?.id?.isLong())
            return fail(code:"default.not.found")

        result.personGroup = PersonGroup.createCriteria().get {
            idEq(params.personGroup.id.toLong())
            fetchMode("persons", FM.EAGER)
        }

        if(!result.personGroup)
            return fail(code:"default.not.found")

        result.personsInGroup = result.personGroup.persons.sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }

        // Success.
        return result
    }

} // end class