
import net.kromhouts.HqlBuilder
import org.apache.commons.lang.WordUtils

class AssetSubItemService {

    boolean transactional = false

    def sessionFactory

    /**
    * Determines and returns sorted list of possible parent items.
    * @param assetSubItemInstance The instance to prepare the list for.
    * @returns A list of the possible parentItems.
    */
    def possibleParentItems(assetSubItemInstance) {
        def criteria = AssetSubItem.createCriteria()
        def possibleParentItems = criteria.list() {
            and {
                eq('isActive', true)
                ne('id', assetSubItemInstance.id)
                assetSubItemInstance.subItems.each() { notEqual('id', it.id) }
                }
        }
        possibleParentItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
    }

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

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

            result.assetSubItemInstance = AssetSubItem.get(params.id)

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

            for(subItem in result.assetSubItemInstance.subItems) {
                if(subItem.maintenanceActions)
                    fail(code:"maintenanceActions.still.associated.subItem")
            }

            if(result.error)
                return result

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

            if(result.assetSubItemInstance.assets)
                return fail(code:"assetSubItem.assets.associated")

            // 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.assetSubItemInstance.delete()
            return result //Success.

        } // withTransaction
    }

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

        result.assetSubItemInstance = new AssetSubItem()
        result.assetSubItemInstance.properties = params

        // pass in an asset to link to if provided.
        if(params.asset?.id)
            result.assetInstance = Asset.get(params.asset.id)

        // success
        return result
    }

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

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

            result.assetSubItemInstance = new AssetSubItem(params)

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

            if(params.asset?.id) {
                result.assetInstance = Asset.get(params.asset.id)

                if(!result.assetInstance)
                    return fail(code:"assetSubItem.asset.not.found")
            }

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

            if(result.assetInstance)
                result.assetInstance.addToAssetSubItems(result.assetSubItemInstance)

            // Success.
            return result

        } //end withTransaction
    } // save()

    /**
    * Get a list of level 1 assetSubItems.
    * @returns By default all level 1 assetSubItems are returned.
    */
    def getLevel1AssetSubItems(params) {

        // A result is returned for every level 1 assetSubItem.
        def q = new HqlBuilder().query {
            select 'assetSubItem'
            from 'AssetSubItem assetSubItem',
                    'inner join assetSubItem.assets as asset'
            where 'asset != null' // ensure that only level 1 assetSubItems are returned.
        }
        def assetSubItems = AssetSubItem.executeQuery(q.query, q.namedParams)

    }

    /**
    * Create recommended extended attributes for all level 1 subItems.
    */
    def createRecommendedExtendedAttributes() {
        def result = [:]

        def hibernateSession = sessionFactory.currentSession

        def assetSubItems = getLevel1AssetSubItems()

        def manufacturer = ExtendedAttributeType.findByName("Manufacturer")
        def modelNumber = ExtendedAttributeType.findByName("Model Number")
        def serialNumber = ExtendedAttributeType.findByName("Serial Number")
        def manufacturedDate = ExtendedAttributeType.findByName("Manufactured Date")

        for(assetSubItem in assetSubItems) {

            def attributeTypes = assetSubItem.assetSubItemExtendedAttributes.collect {it.extendedAttributeType}

            //AssetSubItemExtendedAttribute
            def assetSubItemExtendedAttributeInstance

            if(!attributeTypes.contains(manufacturer)) {
                //AssetSubItemExtendedAttribute #1
                assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "Not Specified",
                                                                                                                    assetSubItem: assetSubItem,
                                                                                                                    extendedAttributeType: manufacturer)
                assetSubItemExtendedAttributeInstance.save()
            }

            if(!attributeTypes.contains(modelNumber)) {
                //AssetSubItemExtendedAttribute #2
                assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "Not Specified",
                                                                                                                    assetSubItem: assetSubItem,
                                                                                                                    extendedAttributeType: modelNumber)
                assetSubItemExtendedAttributeInstance.save()
            }

            if(!attributeTypes.contains(serialNumber)) {
                //AssetSubItemExtendedAttribute #3
                assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "Not Specified",
                                                                                                                    assetSubItem: assetSubItem,
                                                                                                                    extendedAttributeType: serialNumber)
                assetSubItemExtendedAttributeInstance.save()
            }

            if(!attributeTypes.contains(manufacturedDate)) {
                //AssetSubItemExtendedAttribute #4
                assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "Not Specified",
                                                                                                                    assetSubItem: assetSubItem,
                                                                                                                    extendedAttributeType: manufacturedDate)
                assetSubItemExtendedAttributeInstance.save()
            }

            hibernateSession.flush()

        } // for

        // Success.
        return result

    } // createRecommendedExtendedAttributes()

} // end class
