import grails.util.GrailsUtil

/**
* Provides a data service to create a large volume of test data for load testing.
*/
class  CreateBulkDataService {

    boolean transactional = false

    def personService
    def taskService
    def dateUtilService
    def appConfigService
    def assignedGroupService
    def assignedPersonService

    def sessionFactory
    def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP

    def startTime
    def lastBatchStarted

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

    /**
    * Make a run of data creation.
    */
    def create() {
        if(!GrailsUtil.environment == "development") {
            log.error "Dev environment not detected, will NOT create bulk data."
            return false
        }

        log.info "Creating BULK data..."

        // Person and Utils
        log.info "Creating persons..."
        createBulkTestPersons()

//         createBulkTestSites()
//         createBulkTestDepartments()
//         createBulkTestSuppliers()
//         createBulkTestManufacturers()

        // Tasks
        log.info "Creating tasks..."
        createBulkTestTasks()

//         createBulkTestEntries()
//         createBulkTestAssignedGroups()
//         createBulkTestAssignedPersons()
//         createBulkTestTaskRecurringSchedules()

        // Inventory
//         createBulkTestInventoryStores()  /// @todo: Perhaps a 'createQuickStartData' method?
//         createBulkTestInventoryLocations()
//         createBulkTestInventoryGroups() /// @todo: Perhaps a 'createQuickStartData' method?
//         createBulkTestInventoryItems()

        // Assets
//         createBulkTestLifePlan()
//         createBulkTestTaskProcedure()
//         createBulkTestMaintenanceActions()
//         createBulkTestSystemSections()
//         createBulkTestAssetTypes()
//         createBulkTestAssemblies()
//         createBulkTestSubAssemblies()
//         createBulkTestComponentItems()
//         createBulkTestAssets()
//         createBulkTestAssetExtenedAttributes()

        log.info "Creating BULK data...complete."
        return true

    }

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

    def createBulkTestPersons() {
        //Person
        def passClearText = "pass"
        def passwordEncoded = personService.encodePassword(passClearText)
        def personInstance

        def start = Person.count() + 1
        def end = start + 100

        def range = start..end

        def loginName = "BtLoginName"
        String btLoginName
        def firstName = "BtFirstName"
        String btFirstName
        def lastName = "BtLastName"

        def authority2 = Authority.get(2)
        def authority3 = Authority.get(3)
        def personGroup1 = PersonGroup.get(1)
        def personGroup2 = PersonGroup.get(2)
        def personGroup3 = PersonGroup.get(3)
        def personGroup4 = PersonGroup.get(4)
        def personGroup5 = PersonGroup.get(5)

        range.each() {

            btLoginName = loginName + it
            btFirstName = firstName + it

            personInstance = new Person(loginName: btLoginName,
                                        firstName: btFirstName,
                                        lastName: lastName,
                                        pass: passClearText,
                                        password: passwordEncoded,
                                        email: "bulkTest@example.com")
            saveAndTest(personInstance)
            personInstance.addToAuthorities(authority2)
            personInstance.addToAuthorities(authority3)
            personInstance.addToPersonGroups(personGroup1)
            personInstance.addToPersonGroups(personGroup2)
            personInstance.addToPersonGroups(personGroup3)
            personInstance.addToPersonGroups(personGroup4)
            personInstance.addToPersonGroups(personGroup5)

        }

    } // createBulkTestPersons()

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

    def createBulkTestTasks() {

        def taskResult
        def p = [:]

        def start = Task.count() + 1
        def end = start + 10000

        def range = start..end


        def taskGroup1 = TaskGroup.get(1)
        def taskPriority2 = TaskPriority.get(2)
        def taskType1 = TaskType.get(1)
        def leadPerson2 = Person.get(2)

        def description = "Bulk test data "
        String btDescription
        def comment1 = "Has been noted as problematic, try recalibrating."
        def today = dateUtilService.today

        startTime = System.currentTimeMillis()
        lastBatchStarted = startTime

        range.each() {

            if(it % 100 == 0) {
                logStatus("Creating task #" + it)
                cleanUpGorm()
            }

            btDescription = description + it

            //Task #1
            p = [taskGroup: taskGroup1,
                    taskPriority: taskPriority2,
                    taskType: taskType1,
                    leadPerson: leadPerson2,
                    description: btDescription,
                    comment: comment1,
                    targetStartDate: today]

            taskResult = taskService.create(p)
        }

    }

    def createBulkTestEntries() {

        def entryResult
        def p = [:]

        def range = 1..10
        def task1 = Task.get(1)
        def entryType1 = EntryType.get(1)
        def comment1 = "This is a bulk test entry."
        def durationMinute1 = 20

        range.each() {

            p = [task: task1,
                    entryType: entryType1,
                    comment: comment1,
                    durationMinute: durationMinute1]

            entryResult = taskService.createEntry(p)

        }

    } // createBulkTestEntries()

    /**
    * This cleans up the hibernate session and a grails map.
    * For more info see: http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/
    * The hibernate session flush is normal for hibernate.
    * The map is apparently used by grails for domain object validation errors.
    * A starting point for clean up is every 100 objects.
    */
    def cleanUpGorm() {
        def session = sessionFactory.currentSession
        session.flush()
        session.clear()
        propertyInstanceMap.get().clear()
    }

    def logStatus(String message) {
        def batchEnded = System.currentTimeMillis()
        def seconds = (batchEnded-lastBatchStarted)/1000
        def total = (batchEnded-startTime)/1000
        log.info "${message}, last: ${seconds}s, total: ${total}s"
        lastBatchStarted = batchEnded
    }


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

} // end class.