import org.codehaus.groovy.grails.plugins.springsecurity.Secured
import org.codehaus.groovy.grails.commons.ConfigurationHolder
import com.zeddware.grails.plugins.filterpane.FilterUtils

@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
class InventoryItemPurchaseDetailedController extends BaseController {

    def authService
    def filterService
    def exportService
    def dateUtilService
    def inventoryPurchaseService
    def purchaseOrderService

    def index = {
        redirect(action:'search', params:params)
    }

    // the delete, save and update actions only accept POST requests
    static allowedMethods = [delete:'POST', save:'POST', update:'POST']

    def setSearchParamsMax = {
        def max = 1000
        if(params.newMax?.isInteger()) {
            def i = params.newMax.toInteger()
            if(i > 0 && i <= max)
                session.inventoryItemPurchaseSearchParamsMax = params.newMax
            if(i > max)
                session.inventoryItemPurchaseSearchParamsMax = max
        }
        forward(action: 'search', params: params)
    }

    def search = {

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

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

        def inventoryItemPurchaseList = []
        def inventoryItemPurchaseTotal
        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.inventoryItemPurchaseQuickSearch)
                params.quickSearch = session.inventoryItemPurchaseQuickSearch
            else if(session.inventoryItemPurchaseSearchFilterParams) {
                session.inventoryItemPurchaseSearchFilterParams.each() { params[it.key] = it.value }
                params.filter = session.inventoryItemPurchaseSearchFilter
                isFilterApplied = FilterUtils.isFilterApplied(params)
            }
        }

        // Remember sort if supplied, otherwise try to restore.
        if(params.sort && params.order) {
            // Reset to defaultSort if requested.
            if(params.sort == 'defaultSort') {
                params.sort = null
                params.order = null
                session.removeAttribute("inventoryItemPurchaseSearchSort")
                session.removeAttribute("inventoryItemPurchaseSearchOrder")
            }
            else {
                session.inventoryItemPurchaseSearchSort = params.sort
                session.inventoryItemPurchaseSearchOrder = params.order
            }
        }
        else if(session.inventoryItemPurchaseSearchSort && session.inventoryItemPurchaseSearchOrder) {
            params.sort = session.inventoryItemPurchaseSearchSort
            params.order = session.inventoryItemPurchaseSearchOrder
        }
        else {
            params.sort = "id"
            params.order = "asc"
        }

        if(isFilterApplied) {
            // filterPane:
            //if(params.sort == "attentionFlag") // See ticket #64 in Trac.
                //params.sort = "id"

            // Call filterService.
            inventoryItemPurchaseList = filterService.filter( params, InventoryItemPurchase )
            inventoryItemPurchaseTotal = filterService.count( params, InventoryItemPurchase )
            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
            // Remember search.
            session.inventoryItemPurchaseSearchFilterParams = new LinkedHashMap(filterParams)
            session.inventoryItemPurchaseSearchFilter = new LinkedHashMap(params.filter)
            session.removeAttribute("inventoryItemPurchaseQuickSearch")
        }
        else {
            // Quick Search:

            if(params.quickSearch == "searchAllOrders") {
                def orderType = InventoryItemPurchaseType.read(1)
                inventoryItemPurchaseList = InventoryItemPurchase.findAllByInventoryItemPurchaseType(orderType,
                                                                                                                                                                [max:params.max,
                                                                                                                                                                offset:params.offset,
                                                                                                                                                                sort:params.sort,
                                                                                                                                                                order:params.order])
                inventoryItemPurchaseTotal = InventoryItemPurchase.countByInventoryItemPurchaseType(orderType)
                if(inventoryItemPurchaseTotal > 0) { params.message = "All Orders." }
                else { params.message = "No orders found." }
            }
            else if(params.quickSearch == "searchAllReceived") {
                def receivedBackOrderType = InventoryItemPurchaseType.read(2)
                def receivedCompleteType = InventoryItemPurchaseType.read(3)
                inventoryItemPurchaseList = InventoryItemPurchase.findAllByInventoryItemPurchaseTypeOrInventoryItemPurchaseType(receivedBackOrderType,
                                                                                                                                                                                                                receivedCompleteType,
                                                                                                                                                                                                                [max:params.max,
                                                                                                                                                                                                                offset:params.offset,
                                                                                                                                                                                                                sort:params.sort,
                                                                                                                                                                                                                order:params.order])
                inventoryItemPurchaseTotal = InventoryItemPurchase.countByInventoryItemPurchaseTypeOrInventoryItemPurchaseType(receivedBackOrderType,
                                                                                                                                                                                                                receivedCompleteType)
                if(inventoryItemPurchaseTotal > 0) { params.message = "All Received." }
                else { params.message = "No orders found." }
            }
            else {
                //Default:
                inventoryItemPurchaseList = InventoryItemPurchase.list(max:params.max,
                                                                                                            offset:params.offset,
                                                                                                            sort:params.sort,
                                                                                                            order:params.order)
                inventoryItemPurchaseTotal = InventoryItemPurchase.count()
                if(inventoryItemPurchaseTotal > 0) { params.message = "All Purchases." }
                else { params.message = "No orders found." }
            }

            filterParams.quickSearch = params.quickSearch
            // Remember search.
            session.removeAttribute("inventoryItemPurchaseSearchFilterParams")
            session.removeAttribute("inventoryItemPurchaseSearchFilter")
            session.inventoryItemPurchaseQuickSearch = params.quickSearch
        }

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

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

            String title
            if(params.quickSearch)
                title = "${params.quickSearch} inventory purchases."
            else
                title = "Filtered inventory purchases."

            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
            response.setHeader("Content-disposition", "attachment; filename=Purchases.${params.extension}")
            List fields = ["purchaseOrderNumber", "date", "costCode", "quantity", "orderValueAmount", "invoiceNumber",
                                    "inventoryItemPurchaseType"]
            Map labels = ["purchaseOrderNumber": "Order Number", "date": "Date", "costCode": "Cost Code",
                                    "quantity": "Quantity", "orderValueAmount": "Order \$", "invoiceNumber": "Invoice Number",
                                    "inventoryItemPurchaseType": "Type"]
            Map formatters = [ date: dateFmt]
            Map parameters = [title: title, separator: ","]

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

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

        // Get some associatedProperty values for filterpane.
        def associatedPropertyValues = [:]
        def startOfYearRange = dateUtilService.getYearFromDate(dateUtilService.plusYear(new Date(), -10))
        def endOfYearRange = dateUtilService.getYearFromDate(dateUtilService.plusYear(new Date(), 10))
        associatedPropertyValues.yearRange = startOfYearRange..endOfYearRange

        return[ inventoryItemPurchaseList: inventoryItemPurchaseList,
                        inventoryItemPurchaseTotal: inventoryItemPurchaseTotal,
                        filterParams: filterParams,
                        associatedPropertyValues: associatedPropertyValues ]

    } // end search()

    def show = {
        def inventoryItemPurchaseInstance = InventoryItemPurchase.read( params.id )
        params.returnTo = params.returnTo ?: 'inventoryItem'

        if(!inventoryItemPurchaseInstance) {
            flash.message = "InventoryItemPurchase not found with id ${params.id}"
            redirect(controller: 'inventoryItemDetailed', action:'search')
        }
        else { return [ inventoryItemPurchaseInstance : inventoryItemPurchaseInstance ] }
    }

    def delete = {
        def result = inventoryPurchaseService.delete(params)

        if(!result.error) {
            flash.message = g.message(code: "default.delete.success", args: ["InventoryItemPurchase", params.id])
            if(params.returnTo == 'inventoryItem') {
                redirect(controller: 'inventoryItemDetailed',
                                action: 'show',
                                id: result.inventoryItemId,
                                params: [showTab: "showPurchasingTab"])
            }
            else {
                redirect(action: 'search')
            }
            return
        }

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

        if(result.error.code == "default.not.found") {
            redirect(controller: 'inventoryItemDetailed', action: 'search')
            return
        }

        redirect(action:show, id: params.id)
    }

    def edit = {
        def result = inventoryPurchaseService.edit(params)
        params.returnTo = params.returnTo ?: 'inventoryItem'

        def costCodes = []

        if(!result.error) {
            if(inventoryPurchaseService.isPersonInPurchasingGroup(result.inventoryItemPurchaseInstance.costCode.purchasingGroup))
                costCodes = inventoryPurchaseService.getCostCodesByPerson()

            return [ inventoryItemPurchaseInstance : result.inventoryItemPurchaseInstance,
                            'costCodes': costCodes ]
        }

        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
        redirect(controller: 'inventoryItemDetailed', action:'search', params:params)
    }

    def update = {
        def result = inventoryPurchaseService.update(params)

        if(!result.error) {
            flash.message = g.message(code: "default.update.success", args: ["Inventory Purchase", params.id])
            redirect(action:show, id: params.id)
            return
        }

        if(result.error.code == "default.not.found") {
            flash.message = g.message(code: result.error.code, args: result.error.args)
            redirect(controller: 'inventoryItemDetailed', action:'search', params:params)
            return
        }

        result.inventoryItemPurchaseInstance.attach()
        result.inventoryItemPurchaseInstance.costCode.attach()
        result.inventoryItemPurchaseInstance.costCode.purchasingGroup.attach()

        def costCodes = []
        if(inventoryPurchaseService.isPersonInPurchasingGroup(result.inventoryItemPurchaseInstance.costCode.purchasingGroup))
            costCodes = inventoryPurchaseService.getCostCodesByPerson()

        render(view:'edit', model:[inventoryItemPurchaseInstance: result.inventoryItemPurchaseInstance,
                                                'costCodes': costCodes])
    }

    def create = {
        def inventoryItemPurchaseInstance = new InventoryItemPurchase()
        inventoryItemPurchaseInstance.properties = params
        params.returnTo = params.returnTo ?: 'inventoryItem'

        if(!inventoryItemPurchaseInstance.inventoryItem) {
            flash.message = "Please select an inventory item then the 'purchasing' tab."
            redirect(controller: 'inventoryItemDetailed', action: 'search')
            return
        }

        def costCodes = inventoryPurchaseService.getCostCodesByPerson()

        def purchaseOrderNumbers = [purchaseOrderService.findNextUnusedPurchaseOrderNumber()]
        purchaseOrderNumbers += purchaseOrderService.findDraftPurchaseOrderNumbers()

        return ['inventoryItemPurchaseInstance': inventoryItemPurchaseInstance,
                'costCodes': costCodes, 
                'purchaseOrderNumbers': purchaseOrderNumbers]
    }

    def save = {
        def result = inventoryPurchaseService.save(params)

        if(!result.error) {
            flash.message = g.message(code: "default.create.success", args: ["Inventory Purchase", ''])
            if(params.returnTo == 'inventoryItem') {
                redirect(controller: 'inventoryItemDetailed',
                                action: 'show',
                                id: result.inventoryItemId,
                                params: [showTab: "showPurchasingTab"])
            }
            else {
                redirect(action: 'search')
            }
            return
        }

        def costCodes = inventoryPurchaseService.getCostCodesByPerson()

        params.errorMessage = g.message(code: result.error.code, args: result.error.args)
        render(view:'create', model:['inventoryItemPurchaseInstance': result.inventoryItemPurchaseInstance,
                                                    'costCodes': costCodes])
    }

    def receive = {
        def inventoryItemPurchaseInstance = InventoryItemPurchase.read( params.id )

        if(!inventoryItemPurchaseInstance) {
            flash.message = "InventoryItemPurchase not found with id ${params.id}"
            redirect(controller: 'inventoryItemDetailed', action:'search')
            return
        }

        inventoryItemPurchaseInstance.properties = params
        params.returnTo = params.returnTo ?: 'inventoryItem'
        def calcQuantities = inventoryPurchaseService.calcQuantities(inventoryItemPurchaseInstance)
        inventoryItemPurchaseInstance.quantity = calcQuantities.thisOrderRemaining
        inventoryItemPurchaseInstance.orderValueAmount = calcQuantities.thisOrderRemainingAmount
        return ['inventoryItemPurchaseInstance':inventoryItemPurchaseInstance,
                        'orderId': inventoryItemPurchaseInstance.id]
    }

    def receiveSave = {
        def result = inventoryPurchaseService.receiveSave(params)

        if(!result.error) {
            flash.message = g.message(code: "default.create.success", args: ["Inventory Purchase", ''])
            if(params.returnTo == 'inventoryItem') {
                redirect(controller: 'inventoryItemDetailed',
                                action: 'show',
                                id: result.inventoryItemId,
                                params: [showTab: "showPurchasingTab"])
            }
            else {
                redirect(action: 'search')
            }
            return
        }

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

        if(result.error.code == "default.not.found") {
            redirect(controller: 'inventoryItemDetailed', action: 'search')
            return
        }

        // Prevent lazy initialization error.
        result.inventoryItemPurchaseInstance.costCode.attach()

        render(view:'receive',
                        model:['inventoryItemPurchaseInstance': result.inventoryItemPurchaseInstance,
                                    'orderId': result.orderId])
    }

    def approveInvoicePayment = {
        // Read the values from Order Received.
        def inventoryItemPurchaseInstance = InventoryItemPurchase.read( params.id )

        if(!inventoryItemPurchaseInstance) {
            flash.message = "InventoryItemPurchase not found with id ${params.id}"
            redirect(controller: 'inventoryItemDetailed', action:'search')
            return
        }

        inventoryItemPurchaseInstance.properties = params
        params.returnTo = params.returnTo ?: 'inventoryItem'
        return ['inventoryItemPurchaseInstance':inventoryItemPurchaseInstance,
                        'receivedId': inventoryItemPurchaseInstance.id]
    }

    def approveInvoicePaymentSave = {
        def result = inventoryPurchaseService.approveInvoicePaymentSave(params)

        if(!result.error) {
            flash.message = g.message(code: "default.create.success", args: ["Inventory Purchase", ''])
            if(params.returnTo == 'inventoryItem') {
                redirect(controller: 'inventoryItemDetailed',
                                action: 'show',
                                id: result.inventoryItemId,
                                params: [showTab: "showPurchasingTab"])
            }
            else {
                redirect(action: 'search')
            }
            return
        }

        if(result.error.code == "default.not.found") {
            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
            redirect(controller: 'inventoryItemDetailed', action: 'search')
            return
        }

        // Prevent lazy initialization error.
        result.inventoryItemPurchaseInstance.costCode.attach()

        render(view:'approveInvoicePayment',
                    model:['inventoryItemPurchaseInstance': result.inventoryItemPurchaseInstance,
                                    'receivedId': result.receivedId])
    }
}
