function CreateSuggest() {
    this.selector = $("[data-suggest]").not('[data-auto-initialize="false"]');
    this.minimumInputLength = 1;
    this.allowClear = false;
    this.method = 'GET';
    this.signals = {
        onSelect: new signals.Signal(),
        onLoad: new signals.Signal()
    }
}

CreateSuggest.prototype.init = function () {

    var _this = this;

    var updateSelected = function(el) {
        var results = [];
        var _target = $(el.target);

        if (_target.data("type") === "external_db") {
            return false;
        }

        if ($(el).is("input")) {
            var elementId = el.data('select2').containerSelector;
            results   = $(elementId).find('.select2-search-choice');
        } else {
            results = $(this.data('select2').containerSelector).find('.select2-search-choice');
        }

        results.each(function(i, e) {
            var $this = $(e);

            $this.find('.popovers').popover({html : true});

            if(!$this.find('[data-enabled]').data('enabled')) {
                $this.addClass('disabled');
            }

            if($this.find('[data-future]').data('future')) {
                $this.addClass('future');
            }
        });
    };

    _this.selector.each(function (i, e) {
        var input = $(e);

        input.select2({
            multiple: input.data('multiple') ? true : false,
            separator: input.data('separator') ? input.data('separator') : '|',
            ajax: {
                url: input.data('url'),
                dataType: 'json',
                delay: 250,
                type: _this.method,
                data: function (term, page) {
                    return _this.resolveData(input, term, page);
                },
                results: function (data) {
                    return data;
                },
                cache: true
            },
            format: function (state) {
                return state.text;
            },
            formatSelection: function(object) {

                var enabled = object.enabled ? object.enabled  : "true";
                var future  = object.future ? object.future : "false";

                return '<div class="popovers"  data-container="body" data-placement="bottom"  data-content="" data-trigger="hover" data-future="'+ future +'" data-enabled="'+ enabled +'">' + object.text + '</div>';
            },
            formatResult: function (data) {

                var el = '<div>' + data['text'];
                var extended = data["description"]||"";
                var text = "";

                if (data["future"] || data["enabled"]) {
                    if(data["future"] !== false ) {
                        text = data["future"];
                        el += '<span>' + text + '</span>';
                    } else if(data["enabled"] === false ) {
                        text = Translator.trans('cs_core.label.disabled');
                        el += ' <strong>' + text + '</strong>';
                    }
                }

                if($.trim(extended) !== "") {
                    el += '<span>' + extended + '</span>';
                }

                return el +  '</div>';
            },
            formatResultCssClass: function(object) {
                if (object.future !== false && typeof object.future !== "undefined") {
                    return "future";
                }

                if (object.enabled === false && typeof object.enabled !== "undefined") {
                    return "disabled";
                }
            },

            initSelection: function(element, callback) {

                var transFormerValue = input.val();

                if (!transFormerValue) {
                    setTimeout(function(){
                        callback([]);
                        _this.signals.onLoad.dispatch(input);
                    }, 100);

                    return;
                }

                var data = $.parseJSON(transFormerValue);


                if (input.data('multiple')) {
                    input.val('');
                }

                setTimeout(function() {
                    _this.signals.onLoad.dispatch(input);
                    updateSelected(input);
                }, 100);

                return callback(data);
            },
            minimumInputLength: _this.minimumInputLength,
            formatNoMatches: Translator.trans('common.no_results'),
            formatSearching: Translator.trans('related_content.suggest.searching'),
            formatInputTooShort: Translator.trans('related_content.suggest.empty_message', {'chars' : 1}),
            placeholder: Translator.trans('related_content.suggest.placeholder'),
            allowClear: input.data('allow-clear'),
            dropdownCssClass: input.data('dropdown-css-class')
        });

        input.on('select2-close', updateSelected.bind(input));

        input.select2("container").find("ul.select2-choices").sortable({
            containment: 'parent',
            start: function() { input.select2("onSortStart"); },
            update: function() { input.select2("onSortEnd"); }
        });

        if(!input.val()) {
            input.select2('val', [])
        };
    });

    _this.selector.on('select2-selecting',function(e){
        _this.signals.onSelect.dispatch(e);
    });
};

CreateSuggest.prototype.resolveData = function(element,term, page){

    var ids  = [];
    var data = $(element).select2("data");

    // Get id's in use to exclude them for next request

    if (data) {
        if (typeof data == "object") {
            if (_.has(data, "id")) {
                ids.push(data.id);
            }
        } else {
            $.each(data, function(key, object){
                if (_.has(object, "id")) {
                    ids.push(object.id);
                }
            });
        }

    }

    if (element.data("type") === "common" || !element.data("type")) {
        var subsites = [];

        if ($("#subsite-select").length) {
            var subsiteSelected = $("#subsite-select").val();
            if (subsiteSelected) {
                subsites.push($("#subsite-select").val());
            }
        }

        return {
            'class': element.data('class'),
            'property': element.data('property'),
            'term': term,
            'page': page,
            'limit': element.data('limit'),
            'findByProperties': element.data('find-by-properties'),
            'labelProperties': element.data('label-properties'),
            'onlyPublished': element.data('only-published'),
            'contentType': element.data('content-type'),
            'queryOptions': element.data('query-options'),
            'content-types': element.data('content-types'),
            'exclude': ids,
            'subsites': subsites
        };
    } else if (element.data("type") === "external_db") {
        return {
            "conn": element.data('conn'),
            "query": element.data('suggest-query'),
            'term': term,
            'page': page,
            'exclude': ids
        };
    }

};

CreateSuggest.prototype.setSelector = function(selector){
    this.selector = selector;

    return this;
};

CreateSuggest.prototype.setAllowClear = function(allowClear){
    this.allowClear = allowClear;

    return this;
};

CreateSuggest.prototype.setMinimumInputLength = function(minimumInputLength){
    this.minimumInputLength = minimumInputLength;

    return this;
};

CreateSuggest.prototype.setMethod = function(method){
    this.method = method;

    return this;
};

CreateSuggest.prototype.onSelect = function(callback){
    this.signals.onSelect.add(callback);

    return this;
};

var Suggest = new CreateSuggest();
