function AddSearchButton(inputId) {
    var buttonId = inputId + '-search-button';
    var $tag = $('#' + inputId);
	$tag.width($tag.width()-25);
	$tag.after('<img id="' + buttonId + '" src="/media/img/icons/magnifier.png" style="margin-left: 4px; cursor: pointer">');
    return buttonId
}

var SearchWindow = function() {

    this.setup = function(options) {
        this.title = options.title || 'Search';
        this.containerId = 'search-window-' + Math.ceil((Math.random() * 10000000));
        this.submitButtonValue = options.submitButtonValue || 'Search';

        this.openerButtonId = options.openerButtonId || 'search-window-opener';
        this.searchUrl = options.searchUrl;
        this.initialValue = null;
        this.multiple = options.multiple === false ? false : true;

        this.dialogOptions = options.dialogOptions || {
            autoOpen: false,
            width:500,
            position:'center',
		    minWidth:430,
		    width:430,
		    show:'slide'
            }

        this.formHtml = '<form>' +
            '<input class="text" type="text" style="width:82%">' +
            '<input type="submit" value="' + this.submitButtonValue +'"/>' +
            '</form>';

        this.cacheHtml = '<div id="' + this.containerId +'" class="search-window" title="' + this.title + '">' +
            this.formHtml + '<ul class="search-window-result"></ul></div>';

        this.$openerButton = $('#' + this.openerButtonId);
        this.$openerButton.click($.proxy(this, 'open'));
    }

    this.onOpen = function() {}

    this.getFormData = function() {
        var $input = this.$form.find('input[type=text]');
        return $input.val();
    }

    this.submitForm = function(event) {
        this.search(this.getFormData());
        return false;
    }

    this.formatItem =  function(data) {
        return '<li>' + data['display'] + '<span style="display: none">' + data['value'] + '</span></li>';
    }

    this.getValue = function($item) {
        // If an item shoud return other value than
        // is displayed in the result list,
        // override this function.
        // Example: display `name`, return `id`.
        return $item.find('span').html();
    }

    this.updateResultList = function(data) {
        this.$resultList.html('');
        var html = '';
        for (var i=0; i<data.length; i++) {
            html += this.formatItem(data[i]);
        }
        this.$resultList.html(html);
        var $items = this.$container.find('li');
        $items.click($.proxy(this, 'onClick'));
        this.setSelected($items);
    }

    this.setSelected = function($items) {}

    this.open = function() {
        $('#' + this.containerId).remove();
        $('body').append(this.cacheHtml);
        this.$container = $('#' + this.containerId);
        this.$form = this.$container.find('form');
        this.$form.submit($.proxy(this, 'submitForm'));
        this.$resultList = this.$container.find('ul');
        this.$container.dialog(this.dialogOptions);
        this.$container.dialog('open');
        this.onOpen();
        return false;
    }

    this.close = function() {
        this.$container.dialog('close');
    }

    this.block = function() {
        this.$container.dialog('disable');
    }
    this.unblock = function() {
        this.$container.dialog('enable');
    }

    this.search = function(data) {
        $.ajax({
    		url: this.searchUrl,
    		data: {
                'q': data
                },
    		dataType: 'json',
    		beforeSend: $.proxy(function(){
    			this.block();
    		}, this),
    		success: $.proxy(function(data, status){
    			this.updateResultList(data);
    		}, this),
    		complete: $.proxy(function(){
    			this.unblock();
    		}, this)
		})
    }

    this.onClick = function(event) {
        var $item = $(event.target);
        $item.hasClass('selected') ? this.unselect($item) : this.select($item);
        if (!this.multiple) this.close();
    }

    this.select = function($item) {
        $item.addClass('selected');
        this.updateOpener('add', $item);
    }

    this.unselect = function($item) {
        $item.removeClass('selected');
        this.updateOpener('remove', $item);
    }

}

var SearchForTextInput = function() {

    this.onOpen = function() {
        this.$searchInput = this.$form.find('input.text');
        this.$openerInput = $('#' + this.openerInputId);
        this.setInitialValue();
    }

    this.setInitialValue = function() {
        // The goal of this function is to substract a value from opener input
        // to be placed in search input as initial.
        // Values which look like search result will not be taken.
        // Perhaps this logic should be overriden in a subclass,
        // because values in opener input not always would be
        // in format `Firstname Lastname (username)`.
        var openerValue = $.trim(this.$openerInput.val());
        if (openerValue.charAt(openerValue.length-1) == ',') return;
        var values = this.getOpenerValues();
        if (values) {
            var initialValue = $.trim(values[values.length - 1]);
            if (initialValue.search(/[\(\) ]/) == -1) {
                this.initialValue = initialValue;
                this.$searchInput.val(initialValue);
            }
        }
    }

    this.getOpenerValues = function() {
        var data = [];
        $.each(this.$openerInput.val().split(','), function(k, v) {
            var val = $.trim(v);
            if (val) data.push($.trim(v));
        });
        return data;
    }

    this.setOpenerValues = function(values) {
        this.$openerInput.val(values.join(', '));
    }

    this.updateOpener = function(mode, $item) {
        var values = this.getOpenerValues();
        var current = this.getValue($item);
        var indexes = [];
        $.each(values, function(k, v) {
            if (v == current) indexes.push(k);
        });
        if (mode == 'add' && indexes.length == 0) {
            if (this.multiple) {
                if (this.initialValue && values[values.length - 1] == this.initialValue) {
                    values.splice(values.length - 1);
                }
            }
            else {
                values = [];
            }
            values.push(current);
        }
        if (mode == 'remove' && indexes.length > 0) {
            $.each(indexes, function(k, v) {
                values.splice(v, 1);
            });
        }
        this.setOpenerValues(values);
    }

    this.setSelected = function($items) {
        if (!$items) $items = this.$container.find('li');
        var values = this.getOpenerValues();
        $.each($items.get(), $.proxy(function(k, v){
            var $item = $(v);
            if ($.inArray(this.getValue($item), values) != -1) {
                $item.addClass('selected');
            }
         }, this));
    }

    this.setup = function(options) {
        $.proxy(SearchForTextInput.prototype.setup, this)(options);
        this.openerInputId = options.openerInputId;
    }
}

SearchForTextInput.prototype = new SearchWindow();

