
import org.apache.commons.lang.WordUtils

class AssetService {

    boolean transactional = false

    def assetSubItemService

    /**
    * Determines and returns a possible list of asset sub items.
    * @returns A list of the possible assetSubItems.
    */
    def possibleAssetSubItems() {
        def criteria = AssetSubItem.createCriteria()
        def possibleAssetSubItems = criteria.list() {
            and {
                eq('isActive', true)
                isNull("parentItem")
                }
        }
    }

    def delete(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.assetInstance = Asset.get(params.id)

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

            if(result.assetInstance.maintenanceActions)
                return fail(code:"maintenanceActions.still.associated")

            // Remove orphan assetSubItems.
            def assetSubItems = new ArrayList(result.assetInstance.assetSubItems) // avoid ConcurrentModificationException.
            def r
            for(assetSubItem in assetSubItems) {
                result.assetInstance.removeFromAssetSubItems(assetSubItem)
                if(!assetSubItem.assets && !assetSubItem.parentItem) {
                    r = assetSubItemService.delete(id: assetSubItem.id)
                    if(r.error) {
                        log.debug r.error
                        fail(code:"asset.subItems.delete.failure")
                        break
                    }
                }
            }

            if(result.error)
                return result

            // Success.
            // We have handled all the foreign keys so the delete should go forward.
            // Can't flush here due to cascading from Section and Site.
            // And without flush there is no point it trying to catch the dao.DataIntegrityViolationException
            // since that will only happen after leaving the transaction.
            result.assetInstance.delete()
            return result

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

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

        result.assetInstance = new Asset()
        result.assetInstance.properties = params

        // success
        return result
    }

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

        result.assetToCopy = Asset.get(params.assetToCopy?.id)

        if(!result.assetToCopy)
            return fail(code: "asset.copy.asset.required")

        result.assetInstance = new Asset(name: result.assetToCopy.name,
                                                            description: result.assetToCopy.description,
                                                            comment: result.assetToCopy.comment,
                                                            section: result.assetToCopy.section)

        result.assetInstance.properties = params

        // success
        return result
    }

    def save(params) {
        def result = [:]
        def fail = { Map m ->
            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.assetInstance = new Asset(params)

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

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

        // success
        return result
    }

    def saveCopy(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")

            if(!params.copyMethod)
                fail(code:"asset.copy.method.required")

            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")

                result.assetInstance.addToAssetSubItems(assetSubItemInstance1)

                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 linkAssetSubItem = { assetSubItemToLink ->
                result.assetInstance.addToAssetSubItems(assetSubItemToLink)
            }

            def i = 0
            for(assetSubItem in result.assetToCopy.assetSubItems) {

                if(params.copyMethod == "copy")
                    copyAssetSubItem1(assetSubItem)
                else
                    linkAssetSubItem(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