"use strict";

(function($) {
$.widget("cgpma.textfield", {

    options: {
        value: "",
        baseValue: "",
        autocompleteMaxItemCount: 15,
        autocompleteSort: false,
        autocompleteSuggestions: null,
        autocompleteIsAdvisory: false,
        autocompleteCSSClasses: ""
    },

    isFocused: function() {
        var widget = this;
        return widget.$input.is(":focus");
    },

    focus: function() {
        var widget = this;
        return widget.$input.focus();
    },

    getTextRange: function() {
        var widget = this;
        return widget.$input.textrange();
    },

    setTextRange: function(textRange) {
        var widget = this;
        if (textRange.start != textRange.end) {
            return widget.$input.textrange("set", textRange.start, textRange.end);
        }
        return widget.$input.textrange("setcursor", textRange.position);
    },

    _create : function() {
        var widget = this;
        widget.$element = this.element;
        widget.$input = $.bem.generateElement("input", "cgpma", "textfield-input");
        widget.$input.appendTo(widget.$element);

        widget.$input.data("widget",  widget);

        widget._applyAutocompleteSuggestions();

        widget.$input.bind("input",   widget.__handleInputChange);
        widget.$input.bind("keydown", widget.__handleInputKeyDown);
        widget.$input.bind("keyup",   widget.__handleInputKeyUp);
        widget.$input.bind("click",   widget.__handleInputClick);

    },

    _applyAutocompleteSuggestions: function() {
        var widget = this;

        if (widget.$input.data("ui-autocomplete")) {
            widget.$input.autocomplete("destroy");
        }

        var autocompleteSuggestions = widget.options.autocompleteSuggestions;
        if (!autocompleteSuggestions) {
            return;
            delete widget._invertedAutocompleteSuggestions;
        }
        widget._invertedAutocompleteSuggestions = _.invert(autocompleteSuggestions);

        widget.$input.autocomplete({
            delay : 0,
            minLength : 0,
            source : $.proxy(widget, "_autocompleteSource")
        });

        widget.$input.autocomplete(
        "widget").addClass(widget.options.autocompleteCSSClasses);

        widget._on(widget.$input, {
            autocompleteselect : widget.__handleInputChange,
            autocompleteopen : widget.__handleAutocompleteOpen,
            autocompleteclose : widget.__handleAutocompleteClose,
            //autocompletechange : widget.__handleInputChange
        });
    },

    _autocompleteSource: function(request, response) {
        var widget = this;

        var matcher = new RegExp($.ui.autocomplete
                .escapeRegex(_.str.trim(request.term)), "i");

        var responseItems = [];
        _.each(widget.options.autocompleteSuggestions, function(kindName, kind) {
            if (widget.options.autocompleteAlwaysFull || !request.term || matcher.test(kindName)) {
                responseItems.push({
                    label : kindName,
                    value : kindName,
                });
            };
        });

        if (responseItems.length == 1 && responseItems[0].label === request.term) {
            responseItems = [];
        }
        if (responseItems.length > widget.options.autocompleteMaxItemCount) {
            responseItems = responseItems.slice(0, widget.options.autocompleteMaxItemCount);
        }
        if (widget.options.autocompleteSort) {
            responseItems = _.sortBy(responseItems, "label");
        }

        response(responseItems);
    },

    _createShowAllButton : function() {
        return;
        var input = this.input, wasOpen = false;
        $("<a>").attr("tabIndex", -1).attr("title",
                "Show All Items").tooltip().appendTo(
                this.wrapper).button({
            icons : {
                primary : "ui-icon-triangle-1-s"
            },
            text : false
        }).removeClass("ui-corner-all").addClass(
                "custom-combobox-toggle ui-corner-right")
                .mousedown(
                        function() {
                            wasOpen = input.autocomplete(
                                    "widget")
                                    .is(":visible");
                        }).click(function() {
                    input.focus();
                    // Close if already visible
                    if (wasOpen) {
                        return;
                    }
                    // Pass empty string as value to search
                    // for, displaying all results
                    input.autocomplete("search", "");
                });
    },

    _isAutocompleteVisible : function() {
        var widget = this;
        if (widget.$input.data("ui-autocomplete")) {
            return widget.$input.autocomplete("widget").is(":visible");
        } else {
            return false;
        }
    },

    _destroy : function() {
        this.$input.removeData();
    },

    _setOption: function (key, value) {
        var widget = this;

        // Check if such option exists, throw an error if not
        if (!widget.options.hasOwnProperty(key)) {
            throw "Option " + key + " does not exist";
        }

        // Check if value matches what it was, do nothing if yes
        if (value === widget.options[key] || (_.isArray(value) && _.isEqual(value, widget.options[key]))) {
            return;
        }

        // Save old option value
        var prev = widget.options[key];

        // Apply the option
        this._super(key, value);

        // Call corresponding update method depending on the option key
        switch (key) {

        case "value":
            this._applyValue();
            break;

        case "baseValue":
            this._updateStatus();
            break;

        case "autocompleteSuggestions":
            this._applyAutocompleteSuggestions();
            break;
        }
        widget._trigger("change" + key.toLowerCase(), null, {newValue: value, prevValue: prev});
    },

    _realValueToInputValue: function(realValue) {
        var widget = this;

        var value = realValue;
        var valueInOptionsIsString = _.isString(value);
        var trimmedValueInOptions = valueInOptionsIsString ? _.str.trim(value) : value;
        var trimmedCharsOnLeft = valueInOptionsIsString ? value.indexOf(trimmedValueInOptions) : null;
        var trimmedCharsOnRight = valueInOptionsIsString ? value.length - trimmedValueInOptions.length - trimmedCharsOnLeft : null;

        if (valueInOptionsIsString && widget.options.autocompleteSuggestions && widget.options.autocompleteSuggestions[trimmedValueInOptions] !== undefined) {
            value = value.substring(0, trimmedCharsOnLeft) + widget.options.autocompleteSuggestions[trimmedValueInOptions] + value.substring(value.length - trimmedCharsOnRight);
        }
        if (valueInOptionsIsString && value.length >= 4 && value.substring(0, 2) == "__" && value.substring(value.length - 2) == "__") {
            value = value.substring(2, value.length - 2);
        }

        return value;

    },

    _inputValueToRealValue: function(inputValue) {
        var widget = this;

        var value = inputValue;
        var trimmedValueInInput = _.str.trim(value);
        var trimmedCharsOnLeft  = value.indexOf(trimmedValueInInput);
        var trimmedCharsOnRight = value.length - trimmedValueInInput.length - trimmedCharsOnLeft;

        if (widget.options.autocompleteSuggestions && widget.options.autocompleteSuggestions[trimmedValueInInput] && widget.options.autocompleteSuggestions[trimmedValueInInput] !== trimmedValueInInput) {
            value = "__" + value + "__";
        }
        if (widget._invertedAutocompleteSuggestions && widget._invertedAutocompleteSuggestions[trimmedValueInInput] !== undefined) {
            value = value.substring(0, trimmedCharsOnLeft) + widget._invertedAutocompleteSuggestions[trimmedValueInInput] + value.substring(value.length - trimmedCharsOnRight);
        }

        return value;
    },

    _applyValue: function() {
        var widget = this;

        var inputValue = widget._realValueToInputValue(widget.options.value);

        if (inputValue !== widget.$input.val() && !widget._doNotUpdateInputOnValueChange) {
            widget.$input.val(inputValue);
        }
        widget._updateStatus();
    },

    _updateStatus: function() {
        var widget = this;
        widget.$element.toggleClass("cgpma__textfield_status_modified", widget.options.baseValue !== widget.options.value);
    },

    __handleInputChange: function() {

        // this can be an instance of the widget or the DOM node
        var $input = null;
        if (this.element) {
            $input = this.$input;
        } else {
            $input = $(this);
        }
        var widget = $input.data("widget");
        var valueInInput = $input.val();

        if (arguments[1] && arguments[1].item) {
            valueInInput = arguments[1].item.value;
        }

        var realValue = widget._inputValueToRealValue(valueInInput);

        widget._setOption("value", realValue);
    },

    __handleInputKeyDown: function(event) {
        var $this = $(this);
        var widget = $this.data("widget");
        if (event.keyCode == 13) {
            //widget._lastInputChangeWasCausedByAutocomplete = widget.$nput.autocomplete("widget").is(":visible");
        }
        if (event.keyCode == 38 || event.keyCode == 40) { // up or down
            if (widget.$input.data("ui-autocomplete")) {
                if (!widget._isAutocompleteVisible()) {
                    widget.$input.autocomplete("search", "");
                } else {
                    widget._doNotUpdateInputOnValueChange = true;
                    widget._setOption("value", widget._inputValueToRealValue(widget.$input.val()));
                    delete widget._doNotUpdateInputOnValueChange;
                }
            }
        }
    },

    __handleInputKeyUp: function(event) {
        var $this = $(this);
        var widget = $this.data("widget");
        if (event.keyCode == 13) {
            if (widget._lastInputChangeWasCausedByAutocomplete) {
                widget._lastInputChangeWasCausedByAutocomplete = false;
            } else {
                widget._trigger("apply");
                if (widget.$input.data("ui-autocomplete")) {
                    widget.$input.autocomplete("close");
                }
            }
        }
        if (event.keyCode == 27) {
            if (!widget._isAutocompleteVisible()) {
                widget._trigger("discard");
            }
            event.preventDefault();
        }
    },

    __handleAutocompleteOpen: function(event) {
        var widget = this;
        widget.$element.addClass("cgpma__textfield_autocomplete-is-open");
    },

    __handleAutocompleteClose: function(event) {
        var widget = this;
        widget.$element.removeClass("cgpma__textfield_autocomplete-is-open");
    },

    __handleInputClick: function() {
        var $this = $(this);
        var widget = $this.data("widget");
        if (widget.$input.data("ui-autocomplete")) {
            widget.$input.autocomplete("search", "");
        }
    }

});
})(jQuery);