import org.codehaus.groovy.grails.plugins.springsecurity.Secured
import org.codehaus.groovy.grails.commons.ConfigurationHolder
import org.apache.commons.lang.WordUtils

@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
class AssetDetailedController extends BaseController {

    def assetCsvService
    def filterService
    def exportService
    def assetService
    def assetTreeService
    def taskService

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

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
    def index = { redirect(action:search,params:params) }

    /**
    * Set session.assetSearchParamsMax
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
    def setSearchParamsMax = {
        def max = 1000
        if(params.newMax?.isInteger()) {
            def i = params.newMax.toInteger()
            if(i > 0 && i <= max)
                session.assetSearchParamsMax = params.newMax
            if(i > max)
                session.assetSearchParamsMax = max
        }
        forward(action: 'search', params: params)
    }

    /**
    * Build and return the asset tree response for the AJAX request.
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
    def assetTree = {
        def s = assetTreeService.buildAssetTree(params, session)
        render s
    }

    /**
    * Build and return the compact asset tree response.
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
    def assetTreeCompact = {
        def assetInstance = Asset.read(params.id)
        if(!assetInstance) {
            render g.message(code: 'default.not.found', args: ['Asset',params.id])
            return
        }

        render(template:"/shared/assetTreeCompact", model:['assetInstance':assetInstance])
    }

    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
    def exportAssetTreeHtml = {
        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
        response.setHeader("Content-disposition", "attachment; filename=AssetTree.html")
        def s = assetTreeService.buildAssetTree(params, session)
        render s
    }

    /**
    * Save the asset tree status in the current http session.
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
    def saveAssetTreeStatus = {
        session.assetTreeVisibleBranches = params.assetTreeVisibleBranches
    }

    /**
    * Disaply the import view.
    */
    def importAssetTree = {
    }

    /**
    * Handle the import save.
    */
    def importAssetTreeSave = {
        def result = assetCsvService.importAssetTree(request)

        if(!result.error) {
            flash.message = g.message(code: "asset.tree.import.success")
            redirect(action:search)
            return
        }

        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
        redirect(action: importAssetTree)
    }

    /**
    * Export a csv template.
    * NOTE: IE has a 'validating' bug in dev mode that causes the export to take a long time!
    * This does not appear to be a problem once deployed to Tomcat.
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
    def exportAssetTreeTemplate = {
        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
        response.setHeader("Content-disposition", "attachment; filename=AssetTreeTemplate.csv")
        def s = assetCsvService.buildAssetTreeTemplate()
        render s
    }

    /**
    * Export a csv test file.
    */
    def exportAssetTreeTest = {
        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
        response.setHeader("Content-disposition", "attachment; filename=AssetTreeTestFile.csv")
        def s = assetCsvService.buildAssetTreeTest()
        render s
    }

    /**
    * Export the entire asset tree as a csv file.
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
    def exportAssetTree = {

        def assetList = Asset.list()

        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
        response.setHeader("Content-disposition", "attachment; filename=AssetTree.csv")
        def s = assetCsvService.buildAssetTree(assetList)
        render s
    }

    /**
    * Search action.
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
    def search = {

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

        params.max = Math.min( params.max ? params.max.toInteger() : 10,  1000)

        def assetInstanceList = []
        def assetInstanceTotal
        def filterParams = [:]

        // Quick Search:
        if(!params.filter) {
            assetInstanceList = Asset.list( params )
            assetInstanceTotal = Asset.count()
            filterParams.quickSearch = params.quickSearch
        }
        else {
        // filterPane:
            assetInstanceList = filterService.filter( params, Asset )
            assetInstanceTotal = filterService.count( params, Asset )
            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
        }

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

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

//             def fmtAsset = { m ->
//                     def r = ''
//                     def assetInstance = Asset.findByName(m)
// 
//                     r +=  assetInstance
//                     r += ", "
// 
//                     def  lastSubAsset = assetInstance.subAssets.size() - 1
//                     assetInstance.subAssets.eachWithIndex() { obj, i ->
//                         r += "\"" + obj + "\""
//                         if( i < lastSubAsset )
//                             r += ", "
//                     }
//                     return r
//             }

//             def fmtSubAsset = { m ->
//                     def r = ''
//                     m.each() {
//                         def machine = Machine.findByName(it)
//                         def assemblies = machine.assemblies
//                         r += machine.name
//                         r += " "
//                         r += assemblies
//                         r += " "
//                     }
//                     return r
//             }

            String title = "Asset List."

            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
            response.setHeader("Content-disposition", "attachment; filename=Assets.${params.extension}")
            List fields = ["section.site",
                                "section",
                                "name",
                                "description"]
            Map labels = ["section.site": "Site",
                                "section": "Section",
                                "name": "Asset",
                                "description": "Description"]
//             Map labels
//             Map formatters = ["subAsset.name": fmtSubAsset]
            Map formatters = [:]
            Map parameters = [title: title, separator: ","]

            exportService.export(params.format,
                                                response.outputStream,
                                                assetInstanceList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) },
                                                fields,
                                                labels,
                                                formatters,
                                                parameters)
        }

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

        return[ assetInstanceList: assetInstanceList,
                assetInstanceTotal: assetInstanceTotal,
                filterParams: filterParams ]

    } // end search()

    /**
    * Show action.
    */
    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
    def show = {

        // In the case of an actionSubmit button, rewrite action name from 'index'.
        if(params._action_Show)
            params.action='show'

        def assetInstance = Asset.get( params.id )

        if(!assetInstance) {
            flash.message = "Asset not found with id ${params.id}"
            redirect(action:search)
            return
        }

        return [ assetInstance : assetInstance,
                        parentPMs: taskService.getParentPMs(assetInstance)]
    }

    /**
    * Delete action.
    */
    def delete = {
        def result = assetService.delete(params)

        if(!result.error) {
            flash.message = g.message(code: "default.delete.success", args: ["Asset", params.id])
            redirect(action:search)
            return
        }

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

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

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

    /**
    * Edit action.
    */
    def edit = {

        // In the case of an actionSubmit button, rewrite action name from 'index'.
        if(params._action_Edit)
            params.action='edit'

        def assetInstance = Asset.get( params.id )

        if(!assetInstance) {
            flash.message = "Asset not found with id ${params.id}"
            redirect(action:search)
            return
        }

        return [ assetInstance : assetInstance,
                        possibleAssetSubItems: assetService.possibleAssetSubItems(),
                        parentPMs: taskService.getParentPMs(assetInstance) ]

    }

    /**
    * Update action.
    */
    def update = {
        def assetInstance = Asset.get( params.id )

        if(!assetInstance) {
            flash.message = "Asset not found with id ${params.id}"
            redirect(action:search)
            return
        }

        if(params.version) {
            def version = params.version.toLong()
            if(assetInstance.version > version) {

                assetInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
                render(view:'edit',model:[assetInstance:assetInstance,
                                                            possibleAssetSubItems: assetService.possibleAssetSubItems(),
                                                            parentPMs: taskService.getParentPMs(assetInstance)] )
                return
            }
        }

        assetInstance.properties = params

        use(WordUtils) {
            assetInstance.name = assetInstance.name.capitalize()
            assetInstance.description = assetInstance.description.capitalize()
        }

        assetInstance.setAssetSubItemsFromCheckBoxList(params.assetSubItems)

        if(!assetInstance.hasErrors() && assetInstance.save(flush: true)) {
            flash.message = "Asset '${assetInstance.name}' updated"
            redirect(action:show,id:assetInstance.id)
        }
        else {
            render(view:'edit',model:[assetInstance:assetInstance,
                                                        possibleAssetSubItems: assetService.possibleAssetSubItems(),
                                                        parentPMs: taskService.getParentPMs(assetInstance)] )
        }

    }

    /**
    * Create action.
    */
    def create = {
        def result = assetService.create(params)

        if(!result.error)
            return [assetInstance: result.assetInstance]

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

    /**
    * Copy action.
    */
    def copy = {
        def result = assetService.copy(params)

        if(!result.error)
            return [assetInstance: result.assetInstance, assetToCopy: result.assetToCopy]

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

    /**
    * Save action.
    */
    def save = {
        def result = assetService.save(params)

        if(!result.error) {
            flash.message = g.message(code: "default.create.success", args: ["Asset",  "'${result.assetInstance.name}'"])
            redirect(action:show, id: result.assetInstance.id)
            return
        }

        render(view:'create', model:[assetInstance: result.assetInstance])
    }

    /**
    * Copy save action.
    */
    def saveCopy = {
        def result = assetService.saveCopy(params)

        if(!result.error) {
            flash.message = g.message(code: "default.create.success", args: ["Asset", result.assetInstance.id])
            redirect(action:show, id: result.assetInstance.id)
            return
        }

        if(result.error.code == "default.not.found") {
            flash.message = g.message(code: result.error.code, args: ["Asset", params.assetToCopy?.id])
            redirect(action: search)
            return
        }

        flash.errorMessage = g.message(code: result.error.code, args: ["Asset"])

        render(view:'copy', model:[assetInstance: result.assetInstance, assetToCopy: result.assetToCopy])
    }

} // end class
