/*
@author: remy sharp / http://remysharp.com
@url: http://remysharp.com/2007/12/28/jquery-tag-suggestion/
@usage: setGlobalTags(['javascript', 'jquery', 'java', 'json']); // applied tags to be used for all implementations
$('input.tags').tagSuggest(options);
          
The selector is the element that the user enters their tag list
@params:
matchClass - class applied to the suggestions, defaults to 'tagMatches'
tagContainer - the type of element uses to contain the suggestions, defaults to 'span'
tagWrap - the type of element the suggestions a wrapped in, defaults to 'span'
sort - boolean to force the sorted order of suggestions, defaults to false
url - optional url to get suggestions if setGlobalTags isn't used.  Must return array of suggested tags
tags - optional array of tags specific to this instance of element matches
delay - optional sets the delay between keyup and the request - can help throttle ajax requests, defaults to zero delay
separator - optional separator string, defaults to ' ' (Brian J. Cardiff)
@license: Creative Commons License - ShareAlike http://creativecommons.org/licenses/by-sa/3.0/
@version: 1.4
@changes: fixed filtering to ajax hits
*/

(function($) {
    var globalTags = [];

    // creates a public function within our private code.
    // tags can either be an array of strings OR
    // array of objects containing a 'tag' attribute
    window.setGlobalTags = function(tags /* array */) {
        globalTags = getTags(tags);
    };

    function getTags(tags) {
        var tag, i, goodTags = [];
        for (i = 0; i < tags.length; i++) {
            tag = tags[i];
            if (typeof tags[i] == 'object') {
                tag = tags[i].tag;
            }
            goodTags.push(tag.toLowerCase());
        }

        return goodTags;
    }

    // Create a new chart in +domNode+ with the given
    // +options+.  domNode can be a unique selector or
    // a jQuery element.
    //
    function TagSuggester(domNode, options) {
        this._el = $(domNode);
        this._init(options || {});
        this.setSelection();
    }

    $.fn.tagSuggest = function(options) {
        return this.each(function() {
            var el = $(this);
            if (!el.data('TagSuggester'))
                el.data("TagSuggester", new TagSuggester(this, options));
        });
    };

    $.TagSuggester = function(el) {
        return $(el).eq(0).data('TagSuggester');
    };




    TagSuggester.prototype = {
        defaults: {
            'matchClass': 'tagMatches',
            'tagContainer': 'span',
            'tagWrap': 'span',
            'sort': true,
            'tags': null,
            'url': null,
            'delay': 0,
            'separator': ' ',
            'elContainer': null,
            'takeFirstOnEnter': true,
            'variableContainThisIstance': null,
            'getAdditionalParameter': null,
            'overridePressEnter': null
        },
        settings: {},
        // Initialize a new BarFly instance with the given
        // options.  Called from the constructor when a new
        // chart is created
        //
        _init: function(options) {
            this.settings = $.extend({}, this.defaults, options);
            if (this.settings.tags) {
                this.userTags = getTags(this.settings.tags);
            } else {
                this.userTags = globalTags;
            }
            this._timer = null;
            this.matches, this.fromTab, this.suggestionsShow = false;
            this.workingTags = [];
            this.currentTag = { "position": 0, tag: "" };
            this.tagMatches = document.createElement(this.settings.tagContainer);
            //qui Jquery posiziona tagMatches che contiene i minitags DOPO _el che è il campo textbox

            if (this.settings.elContainer != null) {
                this.settings.elContainer.show();
                this.settings.elContainer.append(this.tagMatches);

            } else {
                this._el.after(this.tagMatches);
            }
            //.keypress(handleKeys).keyup(handleKeys).blur(function() {
            var questo = this;

            this._el.keypress(function(ev) {
                fromTab = false;
                var type = ev.type;
                var resetSelection = false;

                switch (ev.keyCode) {
                    case 37: // ignore cases (arrow keys)
                    case 38:
                    case 39:
                    case 40:
                        {
                            questo.hideSuggestions();
                            return true;
                        }
                    case 224:
                    case 17:
                    case 16:
                    case 18:
                        {
                            return true;
                        }

                    case 8:
                        {
                            // delete - hide selections if we're empty
                            if (questo._el.val() == '') {
                                questo.hideSuggestions();
                                questo.setSelection();
                                return true;
                            } else {
                                type = 'keyup'; // allow drop through
                                resetSelection = true;
                                questo.showSuggestionsDelayed(questo);
                            }
                            break;
                        }

                    case 9: // return and tab
                    case 13:
                        {
                            //se il settings dice di non prendere il primo elemento alla pressione del tasto enter esco
                            if (ev.keyCode == 13 && typeof questo.settings.overridePressEnter == "function") {
                                questo.settings.overridePressEnter();
                            }
                            if (!questo.settings.takeFirstOnEnter) return false;
                            if (questo.suggestionsShow) {
                                // complete
                                questo.chooseTag(matches[0]);

                                fromTab = true;
                                return false;
                            } else {
                                return true;
                            }
                        }
                    case 27:
                        {
                            questo.hideSuggestions();
                            questo.setSelection();
                            return true;
                        }
                    case 32:
                        {
                            questo.setSelection();
                            return true;
                        }
                }

                if (type == 'keyup') {
                    switch (ev.charCode) {
                        case 9:
                        case 13:
                            {
                                return true;
                            }
                    }
                }
                if (questo.resetSelection) {
                    questo.setSelection();
                }
                questo.showSuggestionsDelayed(ev.charCode);
            });
            this._el.keyup(function(ev) {
                switch (ev.charCode) {
                    case 9:
                    case 13:
                        {
                            return true;
                        }
                }
                if (questo.resetSelection) {
                    questo.setSelection();
                }
                questo.showSuggestionsDelayed(ev.charCode);
            });

            //this._el.keypress(this.handleKeys).keyup(this.handleKeys).blur(function() {
            this._el.blur(function() {
                if (this.fromTab == true || this.suggestionsShow) { // tweak to support tab selection for Opera & IE
                    this.fromTab = false;
                    this._el.focus();
                }
            });


            // replace with jQuery version
            this.tagMatches = $(this.tagMatches).click(function(ev) {
                if (ev.target.nodeName == questo.settings.tagWrap.toUpperCase() && $(ev.target).is('._tag_suggestion')) {
                    questo.chooseTag(ev.target.innerHTML);
                }
            }).addClass(questo.settings.matchClass);
        },



        showSuggestionsDelayed: function(key) {
            if (this.settings.delay) {
                if (this._timer) clearTimeout(this._timer);
                this._timer = setTimeout(function() {
                    this.showSuggestions(key);
                }, this.settings.delay);
            } else {
                this.showSuggestions(key);
            }
        },

        showSuggestions: function(key) {
            if (this.settings.elContainer != null) this.settings.elContainer.show();
            this.workingTags = this._el.val().split(this.settings.separator);
            this.matches = [];
            var i, html = '', chosenTags = {}, tagSelected = false;

            // we're looking to complete the tag on currentTag.position (to start with)
            this.currentTag = { position: this.currentTags.length - 1, tag: '' };

            for (i = 0; i < this.currentTags.length && i < this.workingTags.length; i++) {
                if (!tagSelected &&
                        this.currentTags[i].toLowerCase() != this.workingTags[i].toLowerCase()) {
                    this.currentTag = { position: i, tag: this.workingTags[i].toLowerCase() };
                    this.tagSelected = true;
                }
                // lookup for filtering out chosen tags
                chosenTags[this.currentTags[i].toLowerCase()] = true;
            }

            if (this.currentTag.tag) {
                // collect potential tags
                if (this.settings.url) {
                    var questo = this;
                    var addParam = '';
                    var paramRequest = { 'tag': this.currentTag.tag };
                    if (typeof this.settings.getAdditionalParameter == "function") {
                        addParam = this.settings.getAdditionalParameter();
                        $.extend(paramRequest, addParam);
                    }

                    $.ajax({
                        'url': this.settings.url,
                        'dataType': 'json',
                        'data': paramRequest,
                        'async': false, // wait until this is ajax hit is complete before continue
                        'success': function(m) {
                            questo.matches = m;
                        }
                    });
                } else {
                    for (var i = 0; i < this.userTags.length; i++) {
                        if (this.userTags[i].indexOf(this.currentTag.tag) === 0) {
                            this.matches.push(userTags[i]);
                        }
                    }
                }

                this.matches = $.grep(this.matches, function(v, i) {
                    return !chosenTags[v.toLowerCase()];
                });

                if (this.settings.sort) {
                    this.matches = this.matches.sort();
                }

                for (i = 0; i < this.matches.length; i++) {
                    if (this.matches[i] == '') continue;
                    html += '<' + this.settings.tagWrap + ' class="_tag_suggestion">' + this.matches[i] + '</' + this.settings.tagWrap + '>';
                }

                this.tagMatches.html(html);
                this.suggestionsShow = !!(this.matches.length);
            } else {
                this.hideSuggestions();
            }
        },

        hideSuggestions: function() {
            if (this.settings.elContainer != null) this.settings.elContainer.hide();
            this.tagMatches.empty();
            this.matches = [];
            this.suggestionsShow = false;
        },

        setSelection: function() {
            var v = this._el.val();

            // tweak for hintted elements
            // http://remysharp.com/2007/01/25/jquery-tutorial-text-box-hints/
            if (v == this._el.attr('title') && this._el.is('.hint')) v = '';

            this.currentTags = v.split(this.settings.separator);
            this.hideSuggestions();
        },

        chooseTag: function(tag) {
            var i, index;
            for (i = 0; i < this.currentTags.length; i++) {
                if (this.currentTags[i].toLowerCase() != this.workingTags[i].toLowerCase()) {
                    index = i;
                    break;
                }
            }

            if (index == this.workingTags.length - 1) tag = tag + this.settings.separator;

            this.workingTags[i] = tag;

            this._el.val(this.workingTags.join(this.settings.separator));
            this._el.blur().focus();
            this.setSelection();
        }


    };
})(jQuery);
