/*!
 * jQuery Rolotec SOLR-Autocomplete
 * Copyright (c) 2011 Rolotec AG
 * Version: 1.0.0 18.05.2011
 * http://www.rolotec.ch
 *
 * Requires: jQuery v1.4.4 or later
 */
(function($) {

    $.fn.solrautocomplete = function(options) {

        $.fn.solrautocomplete.defaults = {
            url: undefined,
            linkDetail: undefined,
            linkResult: undefined,
            fields: undefined,
            delay: 0,
            minChars: 3,
            showHits: true,
            highlight: true,
            multiterm: false,
            hitMessage: "number hits: ",
            noHitMessage: "no hits"
        };

        return this.each(function() {
            // retreve options
            var opts = $.extend(true, {}, $.fn.solrautocomplete.defaults, options || {});
            if (opts.url == undefined)
                alert("parameter 'url' is mandatory");
            if (opts.fields == undefined)
                alert("parameter 'fields' is mandatory");
            else {
                opts.hover = false;
                opts.doRequest = $.fn.solrautocomplete.doRequest;
                opts.displayResult = $.fn.solrautocomplete.displayResult;
                if (opts.multiterm)
                    opts.highlighter = $.fn.solrautocomplete.multitermhighlighter;
                else
                    opts.highlighter = $.fn.solrautocomplete.highlighter;
                opts.keyhandler = $.fn.solrautocomplete.keyhandler;
                opts.selector = $.fn.solrautocomplete.selector;
                opts.trimmer = $.fn.solrautocomplete.trimmer;
                opts.fields = opts.fields.split(";");
                var $input = $(this);
                $input.bind(($.browser.opera ? "keypress" : "keyup") + ".solrautocomplete", function(event) {
                    opts.keyhandler(event, $input, opts);
                });
                $input.blur(function() {
                    if (opts.result != undefined && opts.result.is(":visible") && !opts.hover)
                        opts.result.hide();
                });
                $(document).click(function() {
                    if (opts.result != undefined && opts.result.is(":visible") && !opts.hover)
                        opts.result.hide();
                });
            }
        });
    };

    $.fn.solrautocomplete.keyhandler = function(event, $input, opts) {
        switch (event.keyCode) {
            case KEY.RETURN:
                event.preventDefault();
                if (opts.linkResult != undefined && opts.result != undefined)
                    document.location.href = opts.linkResult + encodeURI($input.val());
                break;
            case KEY.UP:
                event.preventDefault();
                if (opts.result != undefined && opts.result.is(":visible"))
                    opts.selector(1, opts, undefined);
                break;
            case KEY.DOWN:
                event.preventDefault();
                if (opts.result != undefined && opts.result.is(":visible"))
                    opts.selector(-1, opts, undefined);
                else
                    opts.doRequest($input, opts);
                break;
            case KEY.ESC:
                if (opts.result != undefined && opts.result.is(":visible"))
                    opts.result.hide();
                break;
            default:
                opts.doRequest($input, opts);
        }
    };

    $.fn.solrautocomplete.doRequest = function($input, opts) {
        var value = encodeURI(opts.trimmer(($input.val())));
        if (value.length >= opts.minChars) {
            var url = opts.url + "(symb:" + value + ")(content:" + value + ")(content:" + value + "*)";
            $.ajax({
                url: url,
                dataType: "json",
                success: function(json) {
                    // show result
                    opts.displayResult($input, value, json, opts);
                },
                error:function (xhr) {
                    switch (xhr.status) {
                        case 404:
                            alert("page not found, check parameter 'url'");
                            break;
                    }
                }
            });
        } else {
            // reset result
            opts.displayResult($input, value, null, opts);
        }
    };

    $.fn.solrautocomplete.displayResult = function($input, term, json, opts) {
        var $table;
        var id = "solrac_" + $input.attr("id");
        if (opts.result == undefined) {
            // first time create the container for autocomplete values
            var $div = $('<div/>').attr("id", "div_" + id).attr("class", CLASSES.DIV);
            $table = $('<table/>').attr("id", "tbl_" + id).attr("cellpadding", "0").attr("cellspacing", "0");
            $table.hover(function() {
                opts.hover = true;
            }, function() {
                opts.hover = false;
            });
            $table.appendTo($div);
            $input.after($div);
            opts.result = $div;
        } else {
            // clear old values before add new result
            $table = $("#tbl_" + id);
            $table.html("");
        }
        // parse json
        var $tr;
        if (json == null) {
            opts.result.hide();
        } else {
            opts.result.show();
            var numFound = json.response.numFound;
            if (numFound == 0) {
                $tr = $('<tr/>')
                        .attr("class", CLASSES.HITS)
                        .append($('<td/>')
                        .html(opts.noHitMessage))
                        .appendTo($table);
            } else {
                var docs = json.response.docs;
                var i1 = 0;
                jQuery.each(docs, function() {
                    i1++;
                    var doc = this;
                    var $tr = $('<tr/>').attr("class", i1 % 2 == 0 ? CLASSES.EVEN : CLASSES.ODD);
                    for (var i2 = 0; i2 < opts.fields.length; i2++) {
                        var fieldId = "doc." + opts.fields[i2];
                        $tr.append($('<td/>').html(opts.highlighter(eval(fieldId), term, opts)));
                    }
                    $tr.bind("mouseover", function() {
                        opts.selector(0, opts, this)
                    });
                    if (opts.linkDetail != undefined && doc.id != undefined) {
                        $tr.bind("click", function() {
                            document.location.href = opts.linkDetail + doc.id;
                        });
                    }
                    $tr.appendTo($table);
                });
                if (opts.showHits) {
                    $('<tr/>').attr("class", CLASSES.HITS)
                            .append($('<td/>')
                            .attr("colspan", "6")
                            .append($('<span/>').attr("class", CLASSES.TXT).html(opts.hitMessage))
                            .append($('<span/>').attr("class", CLASSES.NBR).html(numFound)))
                            .appendTo($table);
                }
            }
            opts.result.bgiframe();
        }
    };

    $.fn.solrautocomplete.highlighter = function(value, term, opts) {
        if (value == undefined)
            return '&nbsp;';
        if (opts.highlight)
            return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
        else
            return value;
    };

    $.fn.solrautocomplete.multitermhighlighter = function(value, term, opts) {
        if (value == undefined)
            return '&nbsp;';
        if (opts.highlight) {
            var terms = term.split("%20");
            for (var i = 0; i < terms.length; i++) {
                value = value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + terms[i].replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
            }
            return value;
        }
        else
            return value;
    };

    $.fn.solrautocomplete.selector = function(move, opts, event) {
        var showHits = opts.showHits;
        var $divResult = opts.result;
        if (opts.result != undefined && opts.result.is(":visible")) {
            var $lastActiveRow = $divResult.find("." + CLASSES.ACTIVE);
            var $activeRow;
            if (event == undefined) {
                // key selector
            } else {
                // mouse selector
                $activeRow = $(event);
            }
            if ($lastActiveRow != undefined)
                $lastActiveRow.removeClass(CLASSES.ACTIVE);
            if ($activeRow != undefined)
                $activeRow.addClass(CLASSES.ACTIVE);
        }
    };

    $.fn.solrautocomplete.trimmer = function(str) {
        str = str.replace(/^\s+/, '');
        for (var i = str.length - 1; i >= 0; i--) {
            if (/\S/.test(str.charAt(i))) {
                str = str.substring(0, i + 1);
                break;
            }
        }
        return str;
    };

    var KEY = {
        UP: 38,
        DOWN: 40,
        DEL: 46,
        TAB: 9,
        RETURN: 13,
        ESC: 27,
        COMMA: 188,
        PAGEUP: 33,
        PAGEDOWN: 34,
        BACKSPACE: 8
    };

    var CLASSES = {
        DIV: "solrac",
        EVEN: "even",
        ODD: "odd",
        HITS: "hits",
        TXT: "txt",
        NBR: "nbr",
        ACTIVE: "over"
    };

})(jQuery);

