/*
 * Inspector autocomplete editor class.
 *
 * Depends on october.autocomplete.js
 */
+function ($) { "use strict";

    var Base = $.oc.inspector.propertyEditors.string,
        BaseProto = Base.prototype

    var AutocompleteEditor = function(inspector, propertyDefinition, containerCell, group) {
        this.autoUpdateTimeout = null

        Base.call(this, inspector, propertyDefinition, containerCell, group)
    }

    AutocompleteEditor.prototype = Object.create(BaseProto)
    AutocompleteEditor.prototype.constructor = Base

    AutocompleteEditor.prototype.dispose = function() {
        this.clearAutoUpdateTimeout()
        this.removeAutocomplete()

        BaseProto.dispose.call(this)
    }

    AutocompleteEditor.prototype.build = function() {
        var container = document.createElement('div'),
            editor = document.createElement('input'),
            placeholder = this.propertyDefinition.placeholder !== undefined ? this.propertyDefinition.placeholder : '',
            value = this.inspector.getPropertyValue(this.propertyDefinition.property)

        editor.setAttribute('type', 'text')
        editor.setAttribute('class', 'string-editor')
        editor.setAttribute('placeholder', placeholder)

        container.setAttribute('class', 'autocomplete-container')

        if (value === undefined) {
            value = this.propertyDefinition.default
        }

        if (value === undefined) {
            value = ''
        }

        editor.value = value

        $.oc.foundation.element.addClass(this.containerCell, 'text autocomplete')

        container.appendChild(editor)
        this.containerCell.appendChild(container)

        if (this.propertyDefinition.items !== undefined) {
            this.buildAutoComplete(this.propertyDefinition.items)
        }
        else {
            this.loadDynamicItems()
        }
    }

    AutocompleteEditor.prototype.buildAutoComplete = function(items) {
        var input = this.getInput()

        if (items === undefined) {
            items = []
        }

        var $input = $(input),
            autocomplete = $input.data('autocomplete')

        if (!autocomplete) {
            $input.autocomplete({
                source: this.prepareItems(items),
                matchWidth: true
            })
        }
        else {
            autocomplete.source = this.prepareItems(items)
        }
    }

    AutocompleteEditor.prototype.removeAutocomplete = function() {
        var input = this.getInput()

        $(input).autocomplete('destroy')
    }

    AutocompleteEditor.prototype.prepareItems = function(items) {
        var result = {}

        if ($.isArray(items)) {
            for (var i = 0, len = items.length; i < len; i++) {
                result[items[i]] = items[i]
            }
        }
        else {
            result = items
        }

        return result
    }

    AutocompleteEditor.prototype.supportsExternalParameterEditor = function() {
        return false
    }

    AutocompleteEditor.prototype.getContainer = function() {
        return this.getInput().parentNode
    }

    AutocompleteEditor.prototype.registerHandlers = function() {
        BaseProto.registerHandlers.call(this)

        $(this.getInput()).on('change', this.proxy(this.onInputKeyUp))
    }

    AutocompleteEditor.prototype.unregisterHandlers = function() {
        BaseProto.unregisterHandlers.call(this)

        $(this.getInput()).off('change', this.proxy(this.onInputKeyUp))
    }

    AutocompleteEditor.prototype.saveDependencyValues = function() {
        this.prevDependencyValues = this.getDependencyValues()
    }

    AutocompleteEditor.prototype.getDependencyValues = function() {
        var result = ''

        for (var i = 0, len = this.propertyDefinition.depends.length; i < len; i++) {
            var property = this.propertyDefinition.depends[i],
                value = this.inspector.getPropertyValue(property)

            if (value === undefined) {
                value = '';
            }

            result += property + ':' + value + '-'
        }

        return result
    }

    AutocompleteEditor.prototype.onInspectorPropertyChanged = function(property, value) {
        if (!this.propertyDefinition.depends || this.propertyDefinition.depends.indexOf(property) === -1) {
            return
        }

        this.clearAutoUpdateTimeout()

        if (this.prevDependencyValues === undefined || this.prevDependencyValues != dependencyValues) {
            this.autoUpdateTimeout = setTimeout(this.proxy(this.loadDynamicItems), 200)
        }
    }

    AutocompleteEditor.prototype.clearAutoUpdateTimeout = function() {
        if (this.autoUpdateTimeout !== null) {
            clearTimeout(this.autoUpdateTimeout)
            this.autoUpdateTimeout = null
        }
    }

    //
    // Dynamic items
    //

    AutocompleteEditor.prototype.showLoadingIndicator = function() {
        $(this.getContainer()).loadIndicator()
    }

    AutocompleteEditor.prototype.hideLoadingIndicator = function() {
        if (this.isDisposed()) {
            return
        }

        var $container = $(this.getContainer())

        $container.loadIndicator('hide')
        $container.loadIndicator('destroy')

        $container.removeClass('loading-indicator-container')
    }

    AutocompleteEditor.prototype.loadDynamicItems = function() {
        if (this.isDisposed()) {
            return
        }

        this.clearAutoUpdateTimeout()

        var container = this.getContainer(),
            data = this.getRootSurface().getValues(),
            $form = $(container).closest('form')

        $.oc.foundation.element.addClass(container, 'loading-indicator-container size-small')
        this.showLoadingIndicator()

        if (this.triggerGetItems(data) === false) {
            return
        }

        data['inspectorProperty'] = this.getPropertyPath()
        data['inspectorClassName'] = this.inspector.options.inspectorClass

        $form.request('onInspectableGetOptions', {
            data: data,
        })
        .done(this.proxy(this.itemsRequestDone))
        .always(this.proxy(this.hideLoadingIndicator))
    }

    AutocompleteEditor.prototype.triggerGetItems = function(values) {
        var $inspectable = this.getInspectableElement()
        if (!$inspectable) {
            return true
        }

        var itemsEvent = $.Event('autocompleteitems.oc.inspector')

        $inspectable.trigger(itemsEvent, [{
            values: values, 
            callback: this.proxy(this.itemsRequestDone),
            property: this.inspector.getPropertyPath(this.propertyDefinition.property),
            propertyDefinition: this.propertyDefinition
        }])

        if (itemsEvent.isDefaultPrevented()) {
            return false
        }

        return true
    }

    AutocompleteEditor.prototype.itemsRequestDone = function(data) {
        if (this.isDisposed()) {
            // Handle the case when the asynchronous request finishes after
            // the editor is disposed
            return
        }

        this.hideLoadingIndicator()

        var loadedItems = {}

        if (data.options) {
            for (var i = data.options.length-1; i >= 0; i--) {
                loadedItems[data.options[i].value] = data.options[i].title
            }
        }

        this.buildAutoComplete(loadedItems)
    }

    $.oc.inspector.propertyEditors.autocomplete = AutocompleteEditor
}(window.jQuery);