import org.codehaus.groovy.grails.plugins.springsecurity.Secured
import org.codehaus.groovy.grails.commons.ConfigurationHolder

class AssetDetailedController extends BaseController {

    def csvService
    def filterService
    def exportService

    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', saveCopy:'POST']

    def importAssetTree = {
    }

    def importAssetTreeSave = {
        def result = csvService.importAssetTree(request)

        if(!result.error)
            flash.message = g.message(code: "asset.tree.import.success")
        else
            flash.warning = 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.
    */
    def exportAssetTreeTemplate = {
        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
        response.setHeader("Content-disposition", "attachment; filename=AssetTreeTemplate.csv")
        def s = csvService.buildAssetTreeTemplate()
        render s
    }

    def exportAssetTree = {

        def assetList = Asset.list()

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

    def list = {
        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
        [ assetInstanceList: Asset.list( params ), assetInstanceTotal: Asset.count() ]
    }

    def search = {

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

        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=tasks.${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()

    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)
        }
        else { return [ assetInstance : assetInstance ] }
    }

    def delete = {
        def assetInstance = Asset.get( params.id )
        if(assetInstance) {
            try {
                assetInstance.delete(flush:true)
                flash.message = "Asset ${params.id} deleted"
                redirect(action:search)
            }
            catch(org.springframework.dao.DataIntegrityViolationException e) {
                flash.message = "Asset ${params.id} could not be deleted"
                redirect(action:show,id:params.id)
            }
        }
        else {
            flash.message = "Asset not found with id ${params.id}"
            redirect(action:search)
        }
    }

    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)
        }
        else {
            return [ assetInstance : assetInstance ]
        }
    }

    def update = {
        def assetInstance = Asset.get( params.id )
        if(assetInstance) {
            if(params.version) {
                def version = params.version.toLong()
                if(assetInstance.version > version) {
                    
                    assetInstance.errors.rejectValue("version", "asset.optimistic.locking.failure", "Another user has updated this Asset while you were editing.")
                    render(view:'edit',model:[assetInstance:assetInstance])
                    return
                }
            }
            assetInstance.properties = params
            if(!assetInstance.hasErrors() && assetInstance.save(flush: true)) {
                flash.message = "Asset ${params.id} updated"
                redirect(action:show,id:assetInstance.id)
            }
            else {
                render(view:'edit',model:[assetInstance:assetInstance])
            }
        }
        else {
            flash.message = "Asset not found with id ${params.id}"
            redirect(action:list)
        }
    }

    def create = {
        def assetInstance = new Asset()
        assetInstance.properties = params
        return ['assetInstance':assetInstance]
    }

    def copy = {
        def assetToCopy = Asset.get(params.asset.id)

        if(!assetToCopy) {
            flash.message = "Please select an asset to copy."
            redirect(action: list)
            return
        }

        def assetInstance = new Asset(name: assetToCopy.name, section: assetToCopy.section)
        assetInstance.properties = params
        return ['assetInstance':assetInstance, assetToCopy: assetToCopy]
    }

    def save = {
        def assetInstance = new Asset(params)
        if(!assetInstance.hasErrors() && assetInstance.save(flush: true)) {
            flash.message = "Asset ${assetInstance.id} created"
            redirect(action:show,id:assetInstance.id)
        }
        else {
            render(view:'create',model:[assetInstance:assetInstance])
        }
    }

    def saveCopy = {
        def result = saveCopySrvce(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: list)
            return
        }

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

    def saveCopySrvce(params) {
        Asset.withTransaction { status ->
            def result = [:]

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

            result.assetToCopy = Asset.get(params.assetToCopy?.id)
            if(!result.assetToCopy)
                return fail(code:"default.not.found")

            result.assetInstance =  new Asset(params)

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

            def assetSubItemInstance1

            // Copy subItems from level 2 and bellow.
            def copyAssetSubItem = { assetSubItemToCopy, parentItem ->
                def assetSubItemInstance = new AssetSubItem(name: assetSubItemToCopy.name,
                                                                                            description: assetSubItemToCopy.description,
                                                                                            parentItem: parentItem)

                if(assetSubItemInstance.hasErrors() || !assetSubItemInstance.save())
                    return fail(field:"subItems", code:"default.create.failure")

                def i = 0
                for(assetSubItem in assetSubItemToCopy.subItems) {
                    call(assetSubItem, assetSubItemInstance)
                    // Protect against endless recurrsion.
                    i++
                    if(i > 100)
                        fail(code:"default.create.failure")
                    // Stop if an error is flagged.
                    if(result.error)
                        break
                }
            } //copyAssetSubItem

            // Copy the 1st level of subItems.
            def copyAssetSubItem1 = { assetSubItemToCopy ->
                assetSubItemInstance1 = new AssetSubItem(name: assetSubItemToCopy.name,
                                                                                        description: assetSubItemToCopy.description,
                                                                                        asset: result.assetInstance)

                if(assetSubItemInstance1.hasErrors() || !assetSubItemInstance1.save())
                    return fail(field:"assetSubItems", code:"default.create.failure")

                def i = 0
                for(assetSubItem in assetSubItemToCopy.subItems) {
                    copyAssetSubItem(assetSubItem, assetSubItemInstance1)
                    // Protect against endless recurrsion.
                    i++
                    if(i > 100)
                        fail(code:"default.create.failure")
                    // Stop if an error is flagged.
                    if(result.error)
                        break
                }
            } //copyAssetSubItem1

            def i = 0
            for(assetSubItem in result.assetToCopy.assetSubItems) {
                copyAssetSubItem1(assetSubItem)
                // Protect against endless recurrsion.
                i++
                if(i > 100)
                    fail(code:"default.create.failure")
                // Stop if an error is flagged.
                if(result.error)
                    break
            }

            // Success or not.
            return result

        } //end withTransaction
    } // end saveCopySrvce

} // end class
