import org.codehaus.groovy.grails.commons.ConfigurationHolder

/**
* Provides a data service to create base and demo data.
* Beware that most, if not all, BASE data is referenced by "Id" throughout the program.
* This allows changing the text of the 'name' property to something of the same meaning.
* But be sure to maintain the correct Id during creation, indicated by #1, #2 etc.
* Task.list()[0] is used to allow integration testing with DEMO data, where Id's may change due to create-delete.
*/
class  CreateDataService {

    boolean transactional = false

    def authService
    def taskService
    def dateUtilService
    def appConfigService
    def searchableService
    def inventoryItemService
    def assignedGroupService
    def assignedPersonService

    def grailsApplication

/*******************************************
Start of Group methods.
Generally use these methods to create data.
*******************************************/

    /**
    * Always call this at startup to ensure that we have admin access
    * and that the system pseudo person is available.
    */
    def ensureSystemAndAdminAccess() {
        if(!Authority.findByAuthority("ROLE_AppAdmin") ) {
            log.warn "ROLE_AppAdmin not found, calling createAdminAuthority()."
            createAdminAuthority()
        }
        if(!Person.findByLoginName("system") ) {
            log.warn "LoginName 'system' not found, calling createSystemPerson()."
            createSystemPerson()
        }
        if(!Person.findByLoginName("admin") ) {
            log.warn "LoginName 'admin' not found, calling createAdminPerson()."
            createAdminPerson()
        }
    }

    /**
    * Create the base data required for the application to function.
    */
    def createBaseData() {

        if(appConfigService.exists("baseDataCreated")) {
            log.info "Base data previously created."
            return false
        }

        log.info "Creating base data."

        // Person and Utils
        createBaseAuthorities()
        createBasePersonGroupTypes()
        createBasePersonGroups()
        createBaseDefinitions()
        createBaseUnitsOfMeasure()
        createBasePeriods()
        createBaseSupplierTypes()
        createBaseAddressTypes()
        createBaseContactTypes()
        createBaseMaintenancePolicies()
        createBaseInventoryItemPurchaseTypes()

        // Assets
        createBaseExtenededAttributeTypes()

        // Inventory
        createBaseInventoryTypes()
        createBaseInventoryMovementTypes()

        // Tasks
        createBaseTaskGroups()
        createBaseTaskStatus()
        createBaseTaskPriorities()
        createBaseTaskBudgetStatus()
        createBaseTaskTypes()
        createBaseTaskModificationTypes()
        createBaseEntryTypes()

        // Record that data has been created.
        appConfigService.set("baseDataCreated")
    }

    /**
    * Create demo data for some example sites.
    */
    def createDemoData() {

        if(!appConfigService.exists("baseDataCreated")) {
            log.error "Demo data cannot be created until base data has been created."
            return false
        }

        if(appConfigService.exists("demoDataCreated")) {
            log.error "Demo data has already been created, will NOT recreate."
            return false
        }

        if(appConfigService.exists("demoDataCreationDisabled")) {
            log.error "Demo data creation has been disabled, will NOT create."
            return false
        }

        log.info "Creating demo data..."

        // Person and Utils
        createDemoSites()
        createDemoDepartments()
        createDemoSuppliers()
        createDemoProductionReference()
        createDemoPurchasingGroups()  /// @todo: Perhaps a 'createQuickStartData' method?
        createDemoCostCodes()
        createDemoPersons()

        // Assets
        createDemoSections()
        createDemoAssetTree()
        createDemoAssetExtendedAttributes()
        createDemoAssetSubItemExtendedAttributes()

        // Inventory
        createDemoInventoryStores()  /// @todo: Perhaps a 'createQuickStartData' method?
        createDemoInventoryLocations()
        createDemoInventoryGroups() /// @todo: Perhaps a 'createQuickStartData' method?
        createDemoInventoryItems()

        // Tasks
        createDemoTasks()
        createDemoEntries()
        createDemoAssignedGroups()
        createDemoAssignedPersons()
        createDemoTaskProcedure()
        createDemoMaintenanceActions()
        createDemoTaskRecurringSchedules()

        // Record that data has been created.
        appConfigService.set("demoDataCreated")
    }

/******************
Start of Person
*******************/

    def createAdminAuthority() {
        def authInstance

        // Authority #1
        authInstance = new Authority(description:"Application Admin, not required for daily use! \
                                                                                Grants full admin access to the application.",
                                        authority:"ROLE_AppAdmin")
        saveAndTest(authInstance)
    }

    def createBaseAuthorities() {

        def authInstance

        // Authority #2
        authInstance = new Authority(description:"Business Manager, grants full management access.",
                                                            authority:"ROLE_Manager")
        saveAndTest(authInstance)

        // Authority #3
        authInstance = new Authority(description:"Application User, all application users need this base role \
                                                                                    to allow login.",
                                                            authority:"ROLE_AppUser")
        saveAndTest(authInstance)

        // Authority #4
        authInstance = new Authority(description:"Task Manager",
                                                            authority:"ROLE_TaskManager")
        saveAndTest(authInstance)

        // Authority #5
        authInstance = new Authority(description:"Task User",
                                                            authority:"ROLE_TaskUser")
        saveAndTest(authInstance)

        // Authority #6
        authInstance = new Authority(description:"Inventory Manager",
                                                            authority:"ROLE_InventoryManager")
        saveAndTest(authInstance)

        // Authority #7
        authInstance = new Authority(description:"Inventory User",
                                                            authority:"ROLE_InventoryUser")
        saveAndTest(authInstance)

        // Authority #8
        authInstance = new Authority(description:"Asset Manager",
                                                            authority:"ROLE_AssetManager")
        saveAndTest(authInstance)

        // Authority #9
        authInstance = new Authority(description:"Asset User",
                                                            authority:"ROLE_AssetUser")
        saveAndTest(authInstance)

        // Authority #10
        authInstance = new Authority(description:"Production Manager",
                                                            authority:"ROLE_ProductionManager")
        saveAndTest(authInstance)

        // Authority #11
        authInstance = new Authority(description:"Production User",
                                                            authority:"ROLE_ProductionUser")
        saveAndTest(authInstance)
    }

    void createBasePersonGroupTypes() {

        //PersonGroupType.
        def personGroupTypeInstance
        personGroupTypeInstance = new PersonGroupType(name:"Team")
        saveAndTest(personGroupTypeInstance)
        personGroupTypeInstance = new PersonGroupType(name:"Contractor")
        saveAndTest(personGroupTypeInstance)
        personGroupTypeInstance = new PersonGroupType(name:"Project Team")
        saveAndTest(personGroupTypeInstance)
    }

    void createBasePersonGroups() {

        //PersonGroup
        def personGroupInstance
        personGroupInstance = new PersonGroup(personGroupType:PersonGroupType.get(1),
                                                                                name:"Electrical - General")
        saveAndTest(personGroupInstance)
        personGroupInstance = new PersonGroup(personGroupType:PersonGroupType.get(1),
                                                                                name:"Mechanical - General")
        saveAndTest(personGroupInstance)
        personGroupInstance = new PersonGroup(personGroupType:PersonGroupType.get(1),
                                                                                name:"Production")
        saveAndTest(personGroupInstance)
        personGroupInstance = new PersonGroup(personGroupType:PersonGroupType.get(2),
                                                                                name:"AirCon Contractor")
        saveAndTest(personGroupInstance)
        personGroupInstance = new PersonGroup(personGroupType:PersonGroupType.get(3),
                                                                                name:"gnuMims")
        saveAndTest(personGroupInstance)
    }

    def createSystemPerson() {
        //Person
        def passClearText = "pass"
        def passwordEncoded = authService.encodePassword(passClearText)
        def personInstance

        //Person #1
        personInstance = new Person(loginName:"system",
                                    firstName:"gnuMims",
                                    lastName:"System",
                                    description:'''This is a pseudo person that the application uses to insert data. DO NOT
                                                        assign login authorities or change the details of this person.''',
                                    pass:passClearText,
                                    password:passwordEncoded)
        saveAndTest(personInstance)
    }

    def createAdminPerson() {
        //Person
        def passClearText = "pass"
        def passwordEncoded = authService.encodePassword(passClearText)
        def personInstance

        //Person #2
        personInstance = new Person(loginName:"admin",
                                    firstName:"Admin",
                                    lastName:"Powers",
                                    description:'''Every time the application starts it ensures that the 'admin' login name is available.
                                                        DO update the password and other details but keep the login name as 'admin'. ''',
                                    pass:passClearText,
                                    password:passwordEncoded)
        saveAndTest(personInstance)
        personInstance.addToAuthorities(Authority.get(1))
    }

    def createBasePersons() {
    }

    def createDemoPersons() {
        //Person
        def passClearText = "pass"
        def passwordEncoded = authService.encodePassword(passClearText)
        def personInstance

        //Person #1 is system.
        //Person #2 is admin.

        //Person #3
        personInstance = new Person(loginName:"manager",
                                    firstName:"Demo",
                                    lastName:"Manager",
                                    pass:passClearText,
                                    password:passwordEncoded)
        saveAndTest(personInstance)
        personInstance.addToAuthorities(Authority.get(2)) // ROLE_Manager.
        personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
        personInstance.addToPersonGroups(PersonGroup.get(1))
        personInstance.addToPurchasingGroups(PurchasingGroup.get(1))
        personInstance.addToPurchasingGroups(PurchasingGroup.get(2))

        //Person #4
        personInstance = new Person(loginName:"user",
                                    firstName:"Demo",
                                    lastName:"User",
                                    pass:passClearText,
                                    password:passwordEncoded)
        saveAndTest(personInstance)
        personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
        personInstance.addToAuthorities(Authority.get(5)) // ROLE_TaskManager.
        personInstance.addToAuthorities(Authority.get(7)) // ROLE_InventoryUser.
        personInstance.addToAuthorities(Authority.get(9)) // ROLE_AssetUser.
        personInstance.addToPersonGroups(PersonGroup.get(1))

        //Person #5
        personInstance = new Person(loginName:"craig",
                                    firstName:"Craig",
                                    lastName:"SuperSparky",
                                    pass:passClearText,
                                    password:passwordEncoded)
        saveAndTest(personInstance)
        personInstance.addToAuthorities(Authority.get(3))
        personInstance.addToAuthorities(Authority.get(5))
        personInstance.addToAuthorities(Authority.get(7))
        personInstance.addToAuthorities(Authority.get(9))
        personInstance.addToPersonGroups(PersonGroup.get(1))

        //Person #6
        personInstance = new Person(loginName:"john",
                                    firstName:"John",
                                    lastName:"SuperFitter",
                                    pass:passClearText,
                                    password:passwordEncoded)
        saveAndTest(personInstance)
        personInstance.addToAuthorities(Authority.get(3))
        personInstance.addToAuthorities(Authority.get(5))
        personInstance.addToAuthorities(Authority.get(7))
        personInstance.addToAuthorities(Authority.get(9))
        personInstance.addToPersonGroups(PersonGroup.get(2))

        //Person #7
        personInstance = new Person(loginName:"production manager",
                                    firstName:"Production",
                                    lastName:"Manager",
                                    pass:passClearText,
                                    password:passwordEncoded)
        saveAndTest(personInstance)
        personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
        personInstance.addToAuthorities(Authority.get(10)) // ROLE_ProductionManager.
        personInstance.addToPersonGroups(PersonGroup.get(3))

        //Person #8
        personInstance = new Person(loginName:"production",
                                    firstName:"Production",
                                    lastName:"User",
                                    pass:passClearText,
                                    password:passwordEncoded)
        saveAndTest(personInstance)
        personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
        personInstance.addToAuthorities(Authority.get(11)) // ROLE_ProductionUser.
        personInstance.addToPersonGroups(PersonGroup.get(3))

        //Person #9
        personInstance = new Person(loginName:"testmanager",
                                    firstName:"Test",
                                    lastName:"Manager",
                                    pass:passClearText,
                                    password:passwordEncoded)
        saveAndTest(personInstance)
        personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
        personInstance.addToAuthorities(Authority.get(4)) // ROLE_TaskManager.
        personInstance.addToAuthorities(Authority.get(6)) // ROLE_InventoryManager.
        personInstance.addToAuthorities(Authority.get(8)) // ROLE_AssetManager.
        personInstance.addToPersonGroups(PersonGroup.get(3))
    }

/***********************
START OF UTILITIES
***********************/

    //These can redefined by the site at deployment time.
    /// @todo: build an admin view so that only the value (definition) can be changed.
    def createBaseDefinitions() {
        appConfigService.set("Department Definition", "A department as recongised by accounting.")
        appConfigService.set("Site Definition", "The plant, work or production site.")
        appConfigService.set("Section Definition", "A logical grouping of assets, which may be an area, system or process \
                                            as determined by design.")
        appConfigService.set("Asset Definition",
                                            "The complete asset as it is known on the site. \
                                            Often purchased as a whole with the primary purpose of returning value by performing a function. \
                                            An asset is made up of 1 or more sub assets and performs a complete function as specified by the designer.")
        appConfigService.set("Asset Sub Item 1 Name",
                                            "Sub Asset")
        appConfigService.set("Asset Sub Item 1 Definition",
                                            "A machine that performs part of a complete asset's function and often has a model number.")
        appConfigService.set("Asset Sub Item 2 Name",
                                            "Functional Assembly")
        appConfigService.set("Asset Sub Item 2 Definition",
                                            "Functional Assemblies are taken from the designer's functional list for the sub asset and are made up of sub \
                                            assemblies that together perform that function.")
        appConfigService.set("Asset Sub Item 3 Name",
                                            "Sub Assembly Group")
        appConfigService.set("Asset Sub Item 3 Definition",
                                            "Group or type of part.")
        appConfigService.set("Asset Sub Item 4 Name",
                                            "Component Item")
        appConfigService.set("Asset Sub Item 4 Definition",
                                            "The smallest part that would be analysed for failure.")
    }

    def createDemoSites() {
        //Site
        def siteInstance

        siteInstance = new Site(name: "CSM",
                                                    description: "Creek Side Mill")
        saveAndTest(siteInstance)

        siteInstance = new Site(name: "Jasper Street Depot",
                                                    description: "Storage depot on Jasper Street.")
        saveAndTest(siteInstance)

        siteInstance = new Site(name: "River Press",
                                                    description: "Printing press site")
        saveAndTest(siteInstance)
    }

    def createDemoDepartments() {

        //Department
        def departmentInstance

        //Department #1
        departmentInstance = new Department(name: "Print Centre",
                                                                                description: "Printing Department",
                                                                                site: Site.get(1))
        saveAndTest(departmentInstance)

        //Department #2
        departmentInstance = new Department(name: "Pulp Mill",
                                                                                description: "Business Department",
                                                                                site: Site.get(2))
        saveAndTest(departmentInstance)
    }

    def createBaseUnitsOfMeasure() {

        //UnitOfMeasure
        def unitOfMeasureInstance

        //UnitOfMeasure #1
        unitOfMeasureInstance = new UnitOfMeasure(name: "each")
        saveAndTest(unitOfMeasureInstance)

        //UnitOfMeasure #2
        unitOfMeasureInstance = new UnitOfMeasure(name: "meter(s)")
        saveAndTest(unitOfMeasureInstance)

        //UnitOfMeasure #3
        unitOfMeasureInstance = new UnitOfMeasure(name: "box(es)")
        saveAndTest(unitOfMeasureInstance)

        //UnitOfMeasure #4
        unitOfMeasureInstance = new UnitOfMeasure(name: "litre(s)")
        saveAndTest(unitOfMeasureInstance)

        //UnitOfMeasure #5
        unitOfMeasureInstance = new UnitOfMeasure(name: "kilogram(s)")
        saveAndTest(unitOfMeasureInstance)

        //UnitOfMeasure #6
        unitOfMeasureInstance = new UnitOfMeasure(name: "gram(s)")
        saveAndTest(unitOfMeasureInstance)
    }

    def createBasePeriods() {

        //Period
        def periodInstance

        //Period #1
        periodInstance = new Period(period: "Day(s)")
        saveAndTest(periodInstance)

        //Period #2
        periodInstance = new Period(period: "Week(s)")
        saveAndTest(periodInstance)

        //Period #3
        periodInstance = new Period(period: "Month(s)")
        saveAndTest(periodInstance)

        //Period #4
        periodInstance = new Period(period: "Year(s)")
        saveAndTest(periodInstance)
    }

    def createBaseSupplierTypes() {

        // SupplierType
        def supplierTypeInstance

        // SupplierType #1
        supplierTypeInstance = new SupplierType(name: "Unknown",
                                                                    description: "Unknown supplier type")
        saveAndTest(supplierTypeInstance)

        // SupplierType #2
        supplierTypeInstance = new SupplierType(name: "OEM",
                                                                    description: "Original equipment supplier")
        saveAndTest(supplierTypeInstance)

        // SupplierType #3
        supplierTypeInstance = new SupplierType(name: "Local",
                                                                    description: "Local supplier")
        saveAndTest(supplierTypeInstance)
    }

    def createBaseAddressTypes() {

        // AddressType
        def addressTypeInstance

        // AddressType #1
        addressTypeInstance = new AddressType(name: "Postal",
                                                                                description: "A postal address.")
        saveAndTest(addressTypeInstance)

        // AddressType #2
        addressTypeInstance = new AddressType(name: "Physical",
                                                                                description: "A physical address.")
        saveAndTest(addressTypeInstance)

        // AddressType #3
        addressTypeInstance = new AddressType(name: "Postal & Physical",
                                                                                description: "An address that is both the postal and physical address.")
        saveAndTest(addressTypeInstance)

        // AddressType #4
        addressTypeInstance = new AddressType(name: "Invoice",
                                                                                description: "An address to send invoices to.")
        saveAndTest(addressTypeInstance)

        // AddressType #5
        addressTypeInstance = new AddressType(name: "Delivery",
                                                                                description: "An address to send deliveries to.")
        saveAndTest(addressTypeInstance)
    }

    def createBaseContactTypes() {

        // ContactType
        def contactTypeInstance

        // ContactType #1
        contactTypeInstance = new ContactType(name: "Email",
                                                                                description: "Email address.")
        saveAndTest(contactTypeInstance)

        // ContactType #2
        contactTypeInstance = new ContactType(name: "Alternate Email",
                                                                                description: "Alternate email address.")
        saveAndTest(contactTypeInstance)

        // ContactType #3
        contactTypeInstance = new ContactType(name: "Mobile",
                                                                                description: "Modile phone number.")
        saveAndTest(contactTypeInstance)

        // ContactType #4
        contactTypeInstance = new ContactType(name: "Work Phone",
                                                                                description: "Work phone number.")
        saveAndTest(contactTypeInstance)

        // ContactType #5
        contactTypeInstance = new ContactType(name: "Home Phone",
                                                                                description: "Home phone number.")
        saveAndTest(contactTypeInstance)

        // ContactType #6
        contactTypeInstance = new ContactType(name: "Work Fax",
                                                                                description: "Work fax number.")
        saveAndTest(contactTypeInstance)

        // ContactType #7
        contactTypeInstance = new ContactType(name: "Home Fax",
                                                                                description: "Home fax number.")
        saveAndTest(contactTypeInstance)

        // ContactType #8
        contactTypeInstance = new ContactType(name: "Web Site",
                                                                                description: "Web site address.")
        saveAndTest(contactTypeInstance)

        // ContactType #9
        contactTypeInstance = new ContactType(name: "Person",
                                                                                description: "Contact person.")
        saveAndTest(contactTypeInstance)
    }

    def createBaseInventoryItemPurchaseTypes() {

        // InventoryItemPurchaseType
        def inventoryItemPurchaseTypeInstance

        // InventoryItemPurchaseType #1
        inventoryItemPurchaseTypeInstance = new InventoryItemPurchaseType(name: "Order Placed",
                                                                                description: "Order has been placed.")
        saveAndTest(inventoryItemPurchaseTypeInstance)

        // InventoryItemPurchaseType #2
        inventoryItemPurchaseTypeInstance = new InventoryItemPurchaseType(name: "Received B/order To Come",
                                                                                description: "Order has been partially received.")
        saveAndTest(inventoryItemPurchaseTypeInstance)

        // InventoryItemPurchaseType #3
        inventoryItemPurchaseTypeInstance = new InventoryItemPurchaseType(name: "Received Complete",
                                                                                description: "Order has been partially received.")
        saveAndTest(inventoryItemPurchaseTypeInstance)

        // InventoryItemPurchaseType #4
        inventoryItemPurchaseTypeInstance = new InventoryItemPurchaseType(name: "Invoice Approved",
                                                                                description: "Invoice approved for payment.")
        saveAndTest(inventoryItemPurchaseTypeInstance)
    }

    def createDemoSuppliers() {

        // Supplier
        def supplierInstance

        // Supplier #1
        supplierInstance = new Supplier(name: "OEM Distributors",
                                                                        supplierType: SupplierType.get(2))
        saveAndTest(supplierInstance)

        // Supplier #2
        supplierInstance = new Supplier(name: "Mex Holdings",
                                                                        supplierType: SupplierType.get(3))
        saveAndTest(supplierInstance)
    }

    def createDemoProductionReference() {

        // ProductionReference
        def productionReferenceInstance

        // ProductionReference #1
        productionReferenceInstance = new ProductionReference(name: "Monday Production")
        saveAndTest(productionReferenceInstance)

        // ProductionReference #2
        productionReferenceInstance = new ProductionReference(name: "Tuesday Production")
        saveAndTest(productionReferenceInstance)
    }

    void createDemoPurchasingGroups() {

        // PurchasingGroup
        def purchasingGroupInstance

        purchasingGroupInstance = new PurchasingGroup(name:"R&M")
        saveAndTest(purchasingGroupInstance)

        purchasingGroupInstance = new PurchasingGroup(name:"Raw Materials")
        saveAndTest(purchasingGroupInstance)

        purchasingGroupInstance = new PurchasingGroup(name:"Safety")
        saveAndTest(purchasingGroupInstance)
    }

    def createDemoCostCodes() {

        // CostCode
        def costCodeInstance

        // CostCode #1
        costCodeInstance = new CostCode(name: "Reelstand.172",
                                                                    purchasingGroup: PurchasingGroup.get(1))
        saveAndTest(costCodeInstance)

        // CostCode #2
        costCodeInstance = new CostCode(name: "Reelstand.CAPEX",
                                                                    purchasingGroup: PurchasingGroup.get(1))
        saveAndTest(costCodeInstance)

        // CostCode #2
        costCodeInstance = new CostCode(name: "PrintUnit.123",
                                                                    purchasingGroup: PurchasingGroup.get(3))
        saveAndTest(costCodeInstance)
    }

/*********************
START OF TASK
*********************/

    def createBaseTaskGroups() {
        //TaskGroup
        def taskGroupInstance

        //TaskGroup #1
        taskGroupInstance = new TaskGroup(name:"Engineering Activites",
                                                                            description:"Engineering daily activities")
        saveAndTest(taskGroupInstance)

        //TaskGroup #2
        taskGroupInstance = new TaskGroup(name:"Production Activites",
                                                                            description:"Production daily activities")
        saveAndTest(taskGroupInstance)

        //TaskGroup #3
        taskGroupInstance = new TaskGroup(name:"New Projects",
                                                                            description:"New site projects")
        saveAndTest(taskGroupInstance)

        //TaskGroup #4
        taskGroupInstance = new TaskGroup(name:"Electrical Dayshift",
                                                                            description:"Group for dayshift electrical tasks")
        saveAndTest(taskGroupInstance)

        //TaskGroup #5
        taskGroupInstance = new TaskGroup(name:"Electrical Nightshift",
                                                                            description:"Group for dayshift mechanical tasks")
        saveAndTest(taskGroupInstance)

        //TaskGroup #6
        taskGroupInstance = new TaskGroup(name:"Mechanical Dayshift",
                                                                            description:"Group for nightshift electrical tasks")
        saveAndTest(taskGroupInstance)

        //TaskGroup #7
        taskGroupInstance = new TaskGroup(name:"Mechanical Nightshift",
                                                                            description:"Group for nightshift mechanical tasks")
        saveAndTest(taskGroupInstance)
    }

    def createBaseTaskStatus() {

        //TaskStatus
        def taskStatusInstance

        taskStatusInstance = new TaskStatus(name:"Not Started") // #1
        saveAndTest(taskStatusInstance)

        taskStatusInstance = new TaskStatus(name:"In Progress") // #2
        saveAndTest(taskStatusInstance)

        taskStatusInstance = new TaskStatus(name:"Complete") // #3
        saveAndTest(taskStatusInstance)
    }

    def createBaseTaskPriorities() {

        //TaskPriority
        def taskPriorityInstance

        taskPriorityInstance = new TaskPriority(name:"0 - Immediate") // #1
        saveAndTest(taskPriorityInstance)

        taskPriorityInstance = new TaskPriority(name:"1 - Very High") // #2
        saveAndTest(taskPriorityInstance)

        taskPriorityInstance = new TaskPriority(name:"2 - High") // #3
        saveAndTest(taskPriorityInstance)

        taskPriorityInstance = new TaskPriority(name:"3 - Normal") // #4
        saveAndTest(taskPriorityInstance)

        taskPriorityInstance = new TaskPriority(name:"4 - Low") // #5
        saveAndTest(taskPriorityInstance)

        taskPriorityInstance = new TaskPriority(name:"5 - Minor") //  #6
        saveAndTest(taskPriorityInstance)
    }

    def createBaseTaskBudgetStatus() {

        //TaskBudgetStatus
        def taskBudgetStatusInstance

        taskBudgetStatusInstance = new TaskBudgetStatus(name:"Unplanned") // #1
        saveAndTest(taskBudgetStatusInstance)

        taskBudgetStatusInstance = new TaskBudgetStatus(name:"Planned") // #2
        saveAndTest(taskBudgetStatusInstance)
    }

    def createBaseTaskTypes() {

        //TaskType
        def taskTypeInstance

        taskTypeInstance = new TaskType(name:"Immediate Callout") // #1
        saveAndTest(taskTypeInstance)

        taskTypeInstance = new TaskType(name:"Unscheduled Breakin") // #2
        saveAndTest(taskTypeInstance)

        taskTypeInstance = new TaskType(name:"Scheduled") // #3
        saveAndTest(taskTypeInstance)

        taskTypeInstance = new TaskType(name:"Preventative Maintenance") // #4
        saveAndTest(taskTypeInstance)

        taskTypeInstance = new TaskType(name:"Project") // #5
        saveAndTest(taskTypeInstance)

        taskTypeInstance = new TaskType(name:"Parent PM") // #6
        saveAndTest(taskTypeInstance)
    }

    def createBaseTaskModificationTypes() {

        //ModificationType
        def taskModificationTypeInstance
        taskModificationTypeInstance = new TaskModificationType(name:"Created").save()  // #1
        taskModificationTypeInstance = new TaskModificationType(name:"Started").save()  // #2
        taskModificationTypeInstance = new TaskModificationType(name:"Modified").save()  // #3
        taskModificationTypeInstance = new TaskModificationType(name:"Completed").save()  // #4
        taskModificationTypeInstance = new TaskModificationType(name:"Reopened").save()  // #5
        taskModificationTypeInstance = new TaskModificationType(name:"Trashed").save()  // #6
        taskModificationTypeInstance = new TaskModificationType(name:"Restored").save()  // #7
        taskModificationTypeInstance = new TaskModificationType(name:"Approved").save()  // #8
        taskModificationTypeInstance = new TaskModificationType(name:"Renege approval").save()  // #9
        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Assigned Groups)").save()  // #10
        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Assigned Persons)").save()  // #11
        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Flagged for attention)").save()  // #12
        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Attention flag cleared)").save()  // #13
    }

    def createDemoTasks() {

        def taskResult
        def p = [:]

        //Task #1
        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
                taskPriority:TaskPriority.get(1),
                taskType:TaskType.get(1),
                leadPerson:Person.get(2),
                primaryAsset:Asset.get(4),
                description:"Level sensor not working",
                comment:"Has been noted as problematic, try recalibrating.",
                targetStartDate: dateUtilService.today,
                targetCompletionDate: dateUtilService.today]

        taskResult = taskService.save(p)
        taskService.approve(taskResult.taskInstance)

        //Task #2
        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
                taskPriority:TaskPriority.get(2),
                taskType:TaskType.get(3),
                leadPerson:Person.get(5),
                primaryAsset:Asset.get(4),
                description:"Some follow-up work",
                comment:"Some help required",
                targetStartDate: dateUtilService.tomorrow,
                targetCompletionDate: dateUtilService.tomorrow,
                parentTask: Task.list()[0]]

        taskResult = taskService.save(p)
        taskService.approve(taskResult.taskInstance)

        //Task #3
        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
                taskPriority:TaskPriority.get(2),
                taskType:TaskType.get(3),
                leadPerson:Person.get(5),
                primaryAsset:Asset.get(4),
                description:"A Sub Task can be created from the 'Sub Task' tab.",
                comment:"Some help required",
                targetStartDate: dateUtilService.yesterday,
                targetCompletionDate: dateUtilService.yesterday,
                parentTask: Task.list()[0]]

        taskResult = taskService.save(p)
        taskService.approve(taskResult.taskInstance)

        //Task #4
        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
                taskPriority:TaskPriority.get(2),
                taskType:TaskType.get(2),
                leadPerson:Person.get(4),
                primaryAsset:Asset.get(4),
                description:"Please replace sensor at next available opportunity.",
                comment:"Nothing else has worked. So we now require the part to be replaced.",
                targetStartDate: dateUtilService.today,
                targetCompletionDate: dateUtilService.oneWeekFromNow,
                parentTask: Task.list()[0]]

        taskResult = taskService.save(p)
        taskService.approve(taskResult.taskInstance)

        //Task #5
        p = [taskGroup:TaskGroup.findByName("Production Activites"),
                taskPriority:TaskPriority.get(2),
                taskType:TaskType.get(3),
                leadPerson:Person.get(6),
                primaryAsset:Asset.get(1),
                description:"Production Task",
                comment:"Production task for specific production run or shift",
                targetStartDate: dateUtilService.today - 6,
                targetCompletionDate: dateUtilService.today - 6]

        taskResult = taskService.save(p)
        taskService.approve(taskResult.taskInstance)

        //Task #6
        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
                taskPriority:TaskPriority.get(4),
                taskType:TaskType.get(6),
                leadPerson:Person.get(4),
                primaryAsset:Asset.get(2),
                description:"This is a recurring preventative maintenance task.",
                comment:"If there is a parent task specified then this is a generated sub task, if there is a recurring schedule specified then this is a parent task.",
                targetStartDate: dateUtilService.today,
                targetCompletionDate: dateUtilService.today + 30]

        taskResult = taskService.save(p)
        taskService.approve(taskResult.taskInstance)

        //Task #7
        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
                taskPriority:TaskPriority.get(4),
                taskType:TaskType.get(6),
                leadPerson:Person.get(4),
                primaryAsset:Asset.get(2),
                description:"100hr Service.",
                comment:"Based on OEM service.",
                targetStartDate: dateUtilService.today,
                targetCompletionDate: dateUtilService.today + 1]

        taskResult = taskService.save(p)
        taskService.approve(taskResult.taskInstance)
    }

    def createBaseEntryTypes() {

        //EntryType
        def entryTypeInstance

        entryTypeInstance = new EntryType(name:"Fault") // #1
        saveAndTest(entryTypeInstance)

        entryTypeInstance = new EntryType(name:"Cause") // #2
        saveAndTest(entryTypeInstance)

        entryTypeInstance = new EntryType(name:"Work Done") // #3
        saveAndTest(entryTypeInstance)

        entryTypeInstance = new EntryType(name:"Production Note") // #4
        saveAndTest(entryTypeInstance)

        entryTypeInstance = new EntryType(name:"Work Request") // #5
        saveAndTest(entryTypeInstance)
    }

    def createDemoEntries() {

        def entryResult
        def p = [:]

        //Entry #1
        p = [task: Task.list()[0],
                entryType: EntryType.get(1),
                comment: "This level sensor is causing us trouble.",
                durationMinute: 20]

        entryResult = taskService.saveEntry(p)

        //Entry #2
        p = [task: Task.list()[0],
                entryType: EntryType.get(3),
                comment: "Cleaned sensor, see how it goes.",
                durationMinute: 30]

        entryResult = taskService.saveEntry(p)

        //Entry #3
        p = [task: Task.list()[0],
                entryType: EntryType.get(3),
                comment: "Checked up on it later and sensor is dropping out intermittently, created sub task to replace sensor.",
                durationMinute: 20]

        entryResult = taskService.saveEntry(p)

        //Entry #4
        p = [task: Task.list()[4],
                entryType: EntryType.get(3),
                comment: "Work done as per procedure.",
                durationMinute: 55]

        entryResult = taskService.saveEntry(p)
    }

    def createDemoAssignedGroups() {

        def result
        def p = [:]

        //AssignedGroup #1
        p = [personGroup: PersonGroup.get(1),
                task: Task.list()[0],
                estimatedHour: 2,
                estimatedMinute: 30]
        result = assignedGroupService.save(p)

        //AssignedGroup #2
        p = [personGroup: PersonGroup.get(2),
                task: Task.list()[0],
                estimatedHour: 1,
                estimatedMinute: 0]
        result = assignedGroupService.save(p)
    }

    def createDemoAssignedPersons() {

        def result
        def p = [:]

        //AssignedPerson #1
        p = [person: Person.get(3), // Demo Manager.
                task: Task.list()[5],
                estimatedHour: 1,
                estimatedMinute: 20]
        result = assignedPersonService.save(p)

        //AssignedPerson #2
        p = [person: Person.get(4), // Demo User.
                task: Task.list()[5],
                estimatedHour: 1,
                estimatedMinute: 20]
        result = assignedPersonService.save(p)

        //AssignedPerson #3
        p = [person: Person.get(3), // Demo Manager.
                task: Task.list()[6],
                estimatedHour: 3,
                estimatedMinute: 30]
        result = assignedPersonService.save(p)

        //AssignedPerson #4
        p = [person: Person.get(4), // Demo User.
                task: Task.list()[6],
                estimatedHour: 3,
                estimatedMinute: 30]
        result = assignedPersonService.save(p)
    }

    def createBaseMaintenancePolicies() {

        //MaintenancePolicy
        def maintenancePolicyInstance

        //MaintenancePolicy #1
        maintenancePolicyInstance = new MaintenancePolicy(name: "Fixed Time")
        saveAndTest(maintenancePolicyInstance)

        //MaintenancePolicy #2
        maintenancePolicyInstance = new MaintenancePolicy(name: "Condition Based Online")
        saveAndTest(maintenancePolicyInstance)

        //MaintenancePolicy #3
        maintenancePolicyInstance = new MaintenancePolicy(name: "Condition Based Offline")
        saveAndTest(maintenancePolicyInstance)

        //MaintenancePolicy #4
        maintenancePolicyInstance = new MaintenancePolicy(name: "Design Out")
        saveAndTest(maintenancePolicyInstance)

        //MaintenancePolicy #5
        maintenancePolicyInstance = new MaintenancePolicy(name: "Operate To Failure")
        saveAndTest(maintenancePolicyInstance)

        //MaintenancePolicy #6
        maintenancePolicyInstance = new MaintenancePolicy(name: "Regulatory Requirement")
        saveAndTest(maintenancePolicyInstance)

        //MaintenancePolicy #7
        maintenancePolicyInstance = new MaintenancePolicy(name: "Hidden Function Test")
        saveAndTest(maintenancePolicyInstance)
    }

    def createDemoTaskProcedure() {

        //TaskProcedure
        def taskProcedureInstance
        def taskInstance
        def person = Person.get(3)

        taskInstance = Task.list()[6]
        taskProcedureInstance = new TaskProcedure(linkedTask: taskInstance,
                                                                                    createdBy: person,
                                                                                    lastUpdatedBy: person)
        saveAndTest(taskProcedureInstance)
        taskProcedureInstance.addToTasks(taskInstance)

        taskInstance = Task.list()[4]
        taskProcedureInstance = new TaskProcedure(linkedTask: taskInstance,
                                                                                    createdBy: person,
                                                                                    lastUpdatedBy: person)
        saveAndTest(taskProcedureInstance)
        taskProcedureInstance.addToTasks(taskInstance)
    }

    def createDemoMaintenanceActions() {

        //MaintenanceAction
        def maintenanceActionInstance
        def taskProcedure = TaskProcedure.get(1)
        def assetSubItem = AssetSubItem.get(6)

        //MaintenanceAction #1
        maintenanceActionInstance = new MaintenanceAction(description: "Check all E-stops, activate E-stops S1-S12 and ensure machine cannot run",
                                                                                                        procedureStepNumber: 10,
                                                                                                        assetSubItem: assetSubItem,
                                                                                                        taskProcedure: taskProcedure)
        taskProcedure.addToMaintenanceActions(maintenanceActionInstance)

        //MaintenanceAction #2
        maintenanceActionInstance = new MaintenanceAction(description: "Do more pushups",
                                                                                                        procedureStepNumber: 20,
                                                                                                        assetSubItem: assetSubItem,
                                                                                                        taskProcedure: taskProcedure)
        taskProcedure.addToMaintenanceActions(maintenanceActionInstance)

        //MaintenanceAction #3
        maintenanceActionInstance = new MaintenanceAction(description: "Ok just one more pushup",
                                                                                                        procedureStepNumber: 30,
                                                                                                        assetSubItem: assetSubItem,
                                                                                                        taskProcedure: taskProcedure)
        taskProcedure.addToMaintenanceActions(maintenanceActionInstance)

        saveAndTest(taskProcedure)
    }

    def createDemoTaskRecurringSchedules() {

        //TaskRecurringSchedule
        def taskRecurringScheduleInstance

        //TaskRecurringSchedule #1
        taskRecurringScheduleInstance = new TaskRecurringSchedule(task: Task.list()[0],
                                                                                                    recurEvery: 1,
                                                                                                    recurPeriod: Period.get(2),
                                                                                                    nextTargetStartDate: dateUtilService.today,
                                                                                                    generateAhead: 1,
                                                                                                    taskDuration: 2,
                                                                                                    taskDurationPeriod: Period.get(1),
                                                                                                    enabled: false)
        saveAndTest(taskRecurringScheduleInstance)

        //TaskRecurringSchedule #2
        taskRecurringScheduleInstance = new TaskRecurringSchedule(task: Task.list()[5],
                                                                                                    recurEvery: 1,
                                                                                                    recurPeriod: Period.get(1),
                                                                                                    nextTargetStartDate: dateUtilService.today,
                                                                                                    generateAhead: 1,
                                                                                                    taskDuration: 1,
                                                                                                    taskDurationPeriod: Period.get(1),
                                                                                                    enabled: true)
        saveAndTest(taskRecurringScheduleInstance)

        //TaskRecurringSchedule #3
        taskRecurringScheduleInstance = new TaskRecurringSchedule(task: Task.list()[6],
                                                                                                    recurEvery: 1,
                                                                                                    recurPeriod: Period.get(1),
                                                                                                    nextTargetStartDate: dateUtilService.today,
                                                                                                    generateAhead: 1,
                                                                                                    taskDuration: 1,
                                                                                                    taskDurationPeriod: Period.get(1),
                                                                                                    enabled: true)
        saveAndTest(taskRecurringScheduleInstance)
    }

/*************************
START OF INVENTORY
**************************/

    def createDemoInventoryStores() {

        //InventoryStore
        def inventoryStoreInstance

        inventoryStoreInstance = new InventoryStore(site: Site.get(1), name: "Store #1")
        saveAndTest(inventoryStoreInstance)

        inventoryStoreInstance = new InventoryStore(site: Site.get(2), name: "Store #2")
        saveAndTest(inventoryStoreInstance)
    }

    def createDemoInventoryLocations() {

        // InventoryLocation
        def inventoryLocation

        inventoryLocation = new InventoryLocation(inventoryStore: InventoryStore.get(1), name: "A1-2")
        saveAndTest(inventoryLocation)

        inventoryLocation = new InventoryLocation(inventoryStore: InventoryStore.get(2), name: "C55")
        saveAndTest(inventoryLocation)
    }

    def createDemoInventoryGroups() {

        //InventoryGroup
        def inventoryGroupInstance

        //InventoryGroup #1
        inventoryGroupInstance = new InventoryGroup(name: "Misc")
        saveAndTest(inventoryGroupInstance)

        //InventoryGroup #2
        inventoryGroupInstance = new InventoryGroup(name: "Electrical")
        saveAndTest(inventoryGroupInstance)

        //InventoryGroup #3
        inventoryGroupInstance = new InventoryGroup(name: "Mechanical")
        saveAndTest(inventoryGroupInstance)

        //InventoryGroup #4
        inventoryGroupInstance = new InventoryGroup(name: "Production")
        saveAndTest(inventoryGroupInstance)
    }

    def createBaseInventoryTypes() {

        //InventoryType
        def inventoryTypeInstance

        //InventoryType #1
        inventoryTypeInstance = new InventoryType(name: "Consumable",
                                                                                description: "Standard inventory items that are received as new.")
        saveAndTest(inventoryTypeInstance)

        //InventoryType #2
        inventoryTypeInstance = new InventoryType(name: "Rotable",
                                                                                description: "Repairable inventory items that are to be tracked as rotables.")
        saveAndTest(inventoryTypeInstance)

        //InventoryType #3
        inventoryTypeInstance = new InventoryType(name: "Service",
                                                                                description: "Provided services from contractors etc.")
        saveAndTest(inventoryTypeInstance)

        //InventoryType #4
        inventoryTypeInstance = new InventoryType(name: "Tool",
                                                                                description: "Tools that are held as inventory.")
        saveAndTest(inventoryTypeInstance)
    }

    def createBaseInventoryMovementTypes() {

        // InventoryMovementType
        def inventoryMovementTypeInstance

        // InventoryMovementType #1
        inventoryMovementTypeInstance = new InventoryMovementType(name: "Used",
                                                                                                                        incrementsInventory: false)
        saveAndTest(inventoryMovementTypeInstance)

        // InventoryMovementType #2
        inventoryMovementTypeInstance = new InventoryMovementType(name: "Repaired",
                                                                                                                        incrementsInventory: true)
        saveAndTest(inventoryMovementTypeInstance)

        // InventoryMovementType #3
        inventoryMovementTypeInstance = new InventoryMovementType(name: "Purchase Received",
                                                                                                                        incrementsInventory: true)
        saveAndTest(inventoryMovementTypeInstance)

        // InventoryMovementType #4
        inventoryMovementTypeInstance = new InventoryMovementType(name: "Correction Increase",
                                                                                                                        incrementsInventory: true)
        saveAndTest(inventoryMovementTypeInstance)

        // InventoryMovementType #5
        inventoryMovementTypeInstance = new InventoryMovementType(name: "Correction Decrease",
                                                                                                                        incrementsInventory: false)
        saveAndTest(inventoryMovementTypeInstance)
    }

    def createDemoInventoryItems() {

        //InventoryItem
        def inventoryItemInstance
        def currency = Currency.getInstance('AUD')

        def pictureResource = grailsApplication.mainContext.getResource('images/logo.png')

        //InventoryItem #1
        inventoryItemInstance = new InventoryItem(inventoryGroup: InventoryGroup.get(1),
                                                                                    inventoryType: InventoryType.get(1),
                                                                                    unitOfMeasure: UnitOfMeasure.get(2),
                                                                                    inventoryLocation: InventoryLocation.get(1),
                                                                                    name: "Hemp rope",
                                                                                    description: "Natural hemp rope.",
                                                                                    estimatedUnitPriceAmount: 1.23,
                                                                                    estimatedUnitPriceCurrency: currency,
                                                                                    unitsInStock: 2,
                                                                                    reorderPoint: 0)
        saveAndTest(inventoryItemInstance)
        inventoryItemService.savePicture(inventoryItemInstance, pictureResource)

        //InventoryItem #2
        inventoryItemInstance = new InventoryItem(inventoryGroup: InventoryGroup.get(1),
                                                                                    inventoryType: InventoryType.get(1),
                                                                                    unitOfMeasure: UnitOfMeasure.get(2),
                                                                                    inventoryLocation: InventoryLocation.get(1),
                                                                                    name: "Cotton Rope 12mm",
                                                                                    description: "A soft natural rope made from cotton.",
                                                                                    estimatedUnitPriceAmount: 2.50,
                                                                                    estimatedUnitPriceCurrency: currency,
                                                                                    unitsInStock: 2,
                                                                                    reorderPoint: 0)
        saveAndTest(inventoryItemInstance)
        inventoryItemService.savePicture(inventoryItemInstance, pictureResource)

        //InventoryItem #3
        inventoryItemInstance = new InventoryItem(inventoryGroup: InventoryGroup.get(3),
                                                                                    inventoryType: InventoryType.get(1),
                                                                                    unitOfMeasure: UnitOfMeasure.get(1),
                                                                                    inventoryLocation: InventoryLocation.get(2),
                                                                                    name: "2305-2RS",
                                                                                    description: "Bearing 25x62x24mm double row self aligning ball",
                                                                                    estimatedUnitPriceAmount: 5,
                                                                                    estimatedUnitPriceCurrency: currency,
                                                                                    unitsInStock: 3,
                                                                                    reorderPoint: 2)
        saveAndTest(inventoryItemInstance)
        inventoryItemService.savePicture(inventoryItemInstance, pictureResource)

        //InventoryItem #4
        inventoryItemInstance = new InventoryItem(inventoryGroup: InventoryGroup.get(2),
                                                                                    inventoryType: InventoryType.get(1),
                                                                                    unitOfMeasure: UnitOfMeasure.get(1),
                                                                                    inventoryLocation: InventoryLocation.get(2),
                                                                                    name: "L1592-K10",
                                                                                    description: "10kW contactor",
                                                                                    estimatedUnitPriceAmount: 180,
                                                                                    estimatedUnitPriceCurrency: currency,
                                                                                    unitsInStock: 4,
                                                                                    reorderPoint: 0)
        saveAndTest(inventoryItemInstance)
        inventoryItemService.savePicture(inventoryItemInstance, pictureResource)

        //InventoryItem #5
        inventoryItemInstance = new InventoryItem(inventoryGroup: InventoryGroup.get(3),
                                                                                    inventoryType: InventoryType.get(1),
                                                                                    unitOfMeasure: UnitOfMeasure.get(1),
                                                                                    inventoryLocation: InventoryLocation.get(2),
                                                                                    name: "6205-ZZ",
                                                                                    description: "Bearing 25x52x15mm single row ball shielded",
                                                                                    estimatedUnitPriceAmount: 3.45,
                                                                                    estimatedUnitPriceCurrency: currency,
                                                                                    unitsInStock: 5,
                                                                                    reorderPoint: 2)
        saveAndTest(inventoryItemInstance)
        inventoryItemService.savePicture(inventoryItemInstance, pictureResource)
    }

/*******************
START OF ASSET
*******************/

    def createBaseExtenededAttributeTypes() {

        //ExtendedAttributeType
        def extendedAttributeTypeInstance

        //ExtendedAttributeType #1
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Model Number")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #2
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Purchase Cost")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #3
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Serial Number")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #4
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Manufactured Date")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #5
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Location Description")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #6
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Cost Centre")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #7
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Cost Code")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #8
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Manufacturer")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #9
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "ecr")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #10
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Risk Level")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #11
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Safe Work Procedure")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #12
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Regulatory Requirement")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #13
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Maintenance % Completion")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #14
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Registration Required")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #15
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Registration Expiry Date")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #16
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Asset Condition")
        saveAndTest(extendedAttributeTypeInstance)

        //ExtendedAttributeType #17
        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Asset Number")
        saveAndTest(extendedAttributeTypeInstance)
    }

    def createDemoSections() {

        //Section
        def sectionInstance

        //Section #1
        sectionInstance = new Section(name: "A-Press",
                                                                description: "Press Section",
                                                                site: Site.get(3),
                                                                department: Department.get(1))
        saveAndTest(sectionInstance)

        //Section #2
        sectionInstance = new Section(name: "CSM-Delig",
                                                                description: "Pulp Delignification",
                                                                site: Site.get(1),
                                                                department: Department.get(2))
        saveAndTest(sectionInstance)

        //Section #3
        sectionInstance = new Section(name: "CSM-Aux",
                                                                description: "Auxilliary Section",
                                                                site: Site.get(1),
                                                                department: Department.get(1))
        saveAndTest(sectionInstance)
    }

    def createDemoAssetTree() {

        //Asset
        def assetInstance

        //Asset #1
        def assetInstance1 = new Asset(name: "Print Tower 22",
                                                                description: "Complete Printing Asset #22",
                                                                comment: "Includes everthing directly attached to the tower.",
                                                                section: Section.get(1))
        saveAndTest(assetInstance1)

        //Asset #2
        def assetInstance2 = new Asset(name: "Print Tower 21",
                                                                description: "Complete Printing Asset #21",
                                                                section: Section.get(1))
        saveAndTest(assetInstance2)

        //Asset #3
        def assetInstance3 = new Asset(name: "Print Tower 23",
                                                                description: "Complete Printing Asset #23",
                                                                section: Section.get(1))
        saveAndTest(assetInstance3)

        //Asset #4
        def assetInstance4 = new Asset(name: "C579",
                                                                description: "RO #1",
                                                                section: Section.get(2))
        saveAndTest(assetInstance4)

        //AssetSubItem
        def assetSubItemInstance

        //AssetSubItem #1 Level1
        def assetSubItemInstance1 = new AssetSubItem(name: "Print Tower",
                                                                                            description: "Common sub asset.")
        saveAndTest(assetSubItemInstance1)

        // Add assetSubItemInstance1 to some assets.
        assetInstance1.addToAssetSubItems(assetSubItemInstance1)
        assetInstance2.addToAssetSubItems(assetSubItemInstance1)
        assetInstance3.addToAssetSubItems(assetSubItemInstance1)

        //AssetSubItem #2 Level1
        def assetSubItemInstance2 = new AssetSubItem(name: "C579-44",
                                                                                            description: "Tanks and towers")
        saveAndTest(assetSubItemInstance2)

        // Add assetSubItemInstance2 to some assets.
        assetInstance4.addToAssetSubItems(assetSubItemInstance2)

        //AssetSubItem #3 Level1
        def assetSubItemInstance3 = new AssetSubItem(name: "C579-20",
                                                                                            description: "Control Loops")
        saveAndTest(assetSubItemInstance3)

        // Add assetSubItemInstance3 to some assets.
        assetInstance4.addToAssetSubItems(assetSubItemInstance3)

        //AssetSubItem #4 Level2
        assetSubItemInstance = new AssetSubItem(name: "C579-TK-0022",
                                                                                            description: "Blow Tank",
                                                                                            parentItem: AssetSubItem.get(2))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #5 Level2
        assetSubItemInstance = new AssetSubItem(name: "C579-TK-0023",
                                                                                            description: "Reactor Tower",
                                                                                            parentItem: AssetSubItem.get(2))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #6 Level2
        assetSubItemInstance = new AssetSubItem(name: "Print Unit",
                                                                                    description: "Print Unit - Common Level 2 sub item.",
                                                                                    parentItem: AssetSubItem.get(1))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #7 Level2
        assetSubItemInstance = new AssetSubItem(name: "1925365",
                                                                                    description: "Agitator",
                                                                                    parentItem: AssetSubItem.get(4))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #8 Level2
        assetSubItemInstance = new AssetSubItem(name: "1925366",
                                                                                    description: "Scraper",
                                                                                    parentItem: AssetSubItem.get(4))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #9 Level3
        assetSubItemInstance = new AssetSubItem(name: "Motor",
                                                                                    description: "Motor - Level 3 sub item",
                                                                                    parentItem: AssetSubItem.get(6))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #10 Level3
        assetSubItemInstance = new AssetSubItem(name: "Gearbox",
                                                                                    description: "Gearbox - Level 3 sub item, gearbox",
                                                                                    parentItem: AssetSubItem.get(6))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #11 Level4
        assetSubItemInstance = new AssetSubItem(name: "DS Bearing",
                                                                                    description: "Drive Side Bearing",
                                                                                    parentItem: AssetSubItem.get(9))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #12 Level4
        assetSubItemInstance = new AssetSubItem(name: "NDS Bearing",
                                                                                    description: "Non Drive Side Bearing",
                                                                                    parentItem: AssetSubItem.get(9))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #13 Level2
        assetSubItemInstance = new AssetSubItem(name: "C579-F-0001",
                                                                                    description: "Weak Caustic Flow",
                                                                                    parentItem: AssetSubItem.get(3))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #14 Level3
        assetSubItemInstance = new AssetSubItem(name: "C579-FT-0002",
                                                                                    description: "Weak Caustic Flow Transmitter",
                                                                                    parentItem: AssetSubItem.get(13))
        saveAndTest(assetSubItemInstance)

        //AssetSubItem #15 Level3
        assetSubItemInstance = new AssetSubItem(name: "C579-PT-0003",
                                                                                    description: "Weak Caustic Pressure Transmitter",
                                                                                    parentItem: AssetSubItem.get(13))
        saveAndTest(assetSubItemInstance)
    } // createDemoAssetTree()

    def createDemoAssetSubItemExtendedAttributes() {

        //AssetSubItemExtendedAttribute
        def assetSubItemExtendedAttributeInstance

        //AssetSubItemExtendedAttribute #1
        assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "United Press",
                                                                                                                    assetSubItem: AssetSubItem.get(1),
                                                                                                                    extendedAttributeType: ExtendedAttributeType.get(8)) // Manufacturer.
        saveAndTest(assetSubItemExtendedAttributeInstance)

        //AssetSubItemExtendedAttribute #2
        assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "PU Mark 2",
                                                                                                                    assetSubItem: AssetSubItem.get(1),
                                                                                                                    extendedAttributeType: ExtendedAttributeType.get(1)) // Model Number.
        saveAndTest(assetSubItemExtendedAttributeInstance)

        //AssetSubItemExtendedAttribute #3
        assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "765895",
                                                                                                                    assetSubItem: AssetSubItem.get(1),
                                                                                                                    extendedAttributeType: ExtendedAttributeType.get(3)) // Serial Number.
        saveAndTest(assetSubItemExtendedAttributeInstance)

        //AssetSubItemExtendedAttribute #4
        assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "Jan-2003",
                                                                                                                    assetSubItem: AssetSubItem.get(1),
                                                                                                                    extendedAttributeType: ExtendedAttributeType.get(4)) // Manufactured Date.
        saveAndTest(assetSubItemExtendedAttributeInstance)

    }

    def createDemoAssetExtendedAttributes() {

        //AssetExtendedAttribute
        def assetExtendedAttributeInstance

        //AssetExtendedAttribute #1
        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "On the far side of Tank 5",
                                                                                                            asset: Asset.get(1),
                                                                                                            extendedAttributeType: ExtendedAttributeType.get(5)) // Location Description.
        saveAndTest(assetExtendedAttributeInstance)

        //AssetExtendedAttribute #2
        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "3",
                                                                                                            asset: Asset.get(1),
                                                                                                            extendedAttributeType: ExtendedAttributeType.get(9)) // ecr.
        saveAndTest(assetExtendedAttributeInstance)

        //AssetExtendedAttribute #3
        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "RP-001",
                                                                                                            asset: Asset.get(1),
                                                                                                            extendedAttributeType: ExtendedAttributeType.get(17)) // Asset Number.
        saveAndTest(assetExtendedAttributeInstance)

        //AssetExtendedAttribute #4
        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Good",
                                                                                                            asset: Asset.get(1),
                                                                                                            extendedAttributeType: ExtendedAttributeType.get(16)) // Asset Condition.
        saveAndTest(assetExtendedAttributeInstance)

        //AssetExtendedAttribute #5
        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "TBA",
                                                                                                            asset: Asset.get(1),
                                                                                                            extendedAttributeType: ExtendedAttributeType.get(13)) // Maintenance % Completion.
        saveAndTest(assetExtendedAttributeInstance)

        //AssetExtendedAttribute #6
        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Y",
                                                                                                            asset: Asset.get(1),
                                                                                                            extendedAttributeType: ExtendedAttributeType.get(14)) // Registration Required.
        saveAndTest(assetExtendedAttributeInstance)

        //AssetExtendedAttribute #7
        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Feb-2009",
                                                                                                            asset: Asset.get(1),
                                                                                                            extendedAttributeType: ExtendedAttributeType.get(15)) // Registration Expiry Date.
        saveAndTest(assetExtendedAttributeInstance)

        //AssetExtendedAttribute #8
        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "N",
                                                                                                            asset: Asset.get(1),
                                                                                                            extendedAttributeType: ExtendedAttributeType.get(12)) // Regulatory Requirement.
        saveAndTest(assetExtendedAttributeInstance)

        //AssetExtendedAttribute #9
        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Med",
                                                                                                            asset: Asset.get(1),
                                                                                                            extendedAttributeType: ExtendedAttributeType.get(10)) // Risk Level.
        saveAndTest(assetExtendedAttributeInstance)

        //AssetExtendedAttribute #10
        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "WP-003",
                                                                                                            asset: Asset.get(1),
                                                                                                            extendedAttributeType: ExtendedAttributeType.get(11)) // Safe Work Procedure.
        saveAndTest(assetExtendedAttributeInstance)
    }

    /**
    * SearchableIndex and mirroring is disabled at startup.
    * Use this to start indexing after creating bootstrap data.
    * @param indexInNewThread Whether to run the index in a new thread, defaults to true.
    */
    def startSearchableIndex(Boolean indexInNewThread = true) {
        log.info "Start mirroring searchable index."
        ConfigurationHolder.config.appSearchable.cascadeOnUpdate = true
        searchableService.startMirroring()
        if(indexInNewThread) {
            Thread.start {
                log.info "Rebuilding searchable index, bulkIndex (new thread)."
                searchableService.index()
                log.info "Rebuilding searchable index, complete."
            }
        }
        else {
            log.info "Rebuilding searchable index, bulkIndex."
            searchableService.index()
            log.info "Rebuilding searchable index, complete."
        }
    }

    /**
    * Searchable index and mirroring during bulk data creation may be slow.
    * Use this to stop indexing and restart with startSearchableIndex() after data creation.
    */
    def stopSearchableIndex() {
        log.info "Stop mirroring searchable index."
        ConfigurationHolder.config.appSearchable.cascadeOnUpdate = false
        searchableService.stopMirroring()
    }

    /**
    * Call this function instead of .save()
    */
    private boolean saveAndTest(object) {
        if(!object.save()) {
//             DemoDataSuccessful = false
            log.error "'${object}' failed to save!"
            log.error object.errors
            return false
        }
        return true
    }

} // end of class
