/* Coded by: emposha <admin@emposha.com> */
/* Copyright: Emposha.com <http://www.emposha.com> - Distributed under MIT - Keep this message! */

/**
 * json_url         - url to fetch json object
 * cache            - use cache
 * height           - maximum number of element shown before scroll will apear
 * newel            - show typed text like a element
 * firstselected    - automaticly select first element from dropdown
 * filter_case      - case sensitive filter
 * filter_selected  - filter selected items from list
 * complete_text    - text for complete page
 * maxshownitems    - maximum numbers that will be shown at dropdown list (less better performance)
 * onselect         - fire event on item select
 * onremove         - fire event on item remove
 * maxitimes        - maximum items that can be added
 * delay            - delay between ajax request (bigger delay, lower server time request)
 * addontab         - add first visible element on tab or enter hit
 * attachto         - after this element fcbkcomplete insert own elements
 */
jQuery(function($) {
    $.fn.fcbkcomplete = function(opt) {
        return this.each(function() {
            function init() {
                createFCBK();
                preSet();
                addInput(0);
            }

            function createFCBK() {
                element.hide();
                element.attr("multiple", "multiple");
                /*if (element.attr("name").indexOf("[]") == -1) {
                    element.attr("name", element.attr("name") + "[]");
                }*/

                holder = $(document.createElement("ul"));
                holder.attr("class", "holder");
                
                if (options.attachto) {
                  if (typeof(options.attachto) == "object") {
                    options.attachto.append(holder);
                  }
                  else {
                    $(options.attachto).append(holder);
                  }
                  
                }
                else {
                  element.after(holder);
                }

                complete = $(document.createElement("div"));
                complete.addClass("facebook-auto");
                complete.append('<div class="default">' + options.complete_text + "</div>");
                complete.hover(function() {options.complete_hover = 0;}, function() {options.complete_hover = 1;});
                
                feed = $(document.createElement("ul"));
                feed.attr("id", elemid + "_feed");

                complete.prepend(feed);
                holder.after(complete);
                feed.css("width", complete.width());
            }

            function preSet() {
                element.children("option").each(function(i, option) {
                    option = $(option);                    
                    if (option.hasClass("selected")) {
                        addItem(option.text(), option.val(), true, option.hasClass("locked"));
                        option.attr("selected", "selected");
                    }
                    cache.push({
                        key: option.text(),
                        value: option.val()
                    });
                    search_string += "" + (cache.length - 1) + ":" + option.text() + ";";
                });
            }

            //public method to add new item
            $(this).bind("addItem",
            function(event, data) {
                addItem(data.title, data.value, 0, 0, 0);
            });

            //public method to remove item
            $(this).bind("removeItem",
            function(event, data) {
                var item = holder.children('li[rel=' + data.value + ']');
                if (item.length) {
                    removeItem(item);
                }
            });
            
            //public method to remove item
            $(this).bind("destroy",
            function(event, data) {
                holder.remove();
                complete.remove();
                element.show();
            });

            function addItem(title, value, preadded, locked, focusme) {
                if (!maxItems()) {
                    return false;
                }
                var li = document.createElement("li");
                var txt = document.createTextNode(title);
                var aclose = document.createElement("a");
                var liclass = "bit-box" + (locked ? " locked": "");
                $(li).attr({
                    "class": liclass,
                    "rel": value
                });
                $(li).prepend(txt);
                $(aclose).attr({
                    "class": "closebutton",
                    "href": "#"
                });

                li.appendChild(aclose);
                holder.append(li);

                $(aclose).click(function() {
                    removeItem($(this).parent("li"));
                    return false;
                });

                if (!preadded) {
                    $("#" + elemid + "_annoninput").remove();
                    var _item;
                    addInput(focusme);
                    if (element.children("option[value=" + value + "]").length) {
                        _item = element.children("option[value=" + value + "]");
                        _item.get(0).setAttribute("selected", "selected");
                        _item.attr("selected", "selected");
                        if (!_item.hasClass("selected")) {
                            _item.addClass("selected");
                        }
                    }
                    else{
                        var _item = $(document.createElement("option"));
                        _item.attr("value", value).get(0).setAttribute("selected", "selected");
                        _item.attr("value", value).attr("selected", "selected");
                        _item.attr("value", value).addClass("selected");
                        _item.text(title);
                        element.append(_item);
                    }
                    if (options.onselect) {
                        funCall(options.onselect, _item)
                    }
                    element.change();
                }
                holder.children("li.bit-box.deleted").removeClass("deleted");
                feed.hide();
            }

            function removeItem(item) {

                if (!item.hasClass('locked')) {                    
                    item.fadeOut("fast");
                    if (options.onremove) {
                        var _item = element.children("option[value=" + item.attr("rel") + "]");
                        funCall(options.onremove, _item)
                    }
                    element.children('option[value="' + item.attr("rel") + '"]').removeAttr("selected").removeClass("selected");
                    item.remove();
                    element.change();
                    deleting = 0;
                }
            }

            function addInput(focusme) {
                var li = $(document.createElement("li"));
                var input = $(document.createElement("input"));
                var getBoxTimeout = 0;

                li.attr({
                    "class": "bit-input",
                    "id": elemid + "_annoninput"
                });
                input.attr({
                    "type": "text",
                    "class": "maininput",
                    "size": "1"
                });
                holder.append(li.append(input));

                input.focus(function() {
                    complete.fadeIn("fast");
                });

                input.blur(function() {
                    if (options.complete_hover) {
                      complete.fadeOut("fast");
                    }
                    else {
                      input.focus();
                    }
                });              

                holder.click(function() {
                    input.focus();
                    if (feed.length && input.val().length) {
                        feed.show();
                    }
                    else{
                        feed.hide();
                        complete.children(".default").show();
                    }
                });

                input.keypress(function(event) {
                    if (event.keyCode == 13) {
                        return false;
                    }
                    //auto expand input             
                    input.attr("size", input.val().length + 1);
                });

                input.keydown(function(event) {
                    //prevent to enter some bad chars when input is empty
                    if (event.keyCode == 191) {
                        event.preventDefault();
                        return false;
                    }
                });

                input.keyup(function(event) {
                    var etext = xssPrevent(input.val());

                    if (event.keyCode == 8 && etext.length == 0) {
                        feed.hide();
                        if (!holder.children("li.bit-box:last").hasClass('locked')) {
                            if (holder.children("li.bit-box.deleted").length == 0) {
                                holder.children("li.bit-box:last").addClass("deleted");
                                return false;
                            }
                            else{
                                if (deleting) {
                                    return;
                                }
                                deleting = 1;
                                holder.children("li.bit-box.deleted").fadeOut("fast",
                                function() {
                                    removeItem($(this));
                                    return false;
                                });
                            }
                        }
                    }

                    if (event.keyCode != 40 && event.keyCode != 38 && event.keyCode!=37 && event.keyCode!=39 && etext.length != 0) {
                        counter = 0;

                        if (options.json_url) {
                            if (options.cache && json_cache) {
                                addMembers(etext);
                                bindEvents();
                            }
                            else{
                                getBoxTimeout++;
                                var getBoxTimeoutValue = getBoxTimeout;
                                setTimeout(function() {
                                    if (getBoxTimeoutValue != getBoxTimeout) return;
                                    $.getJSON(options.json_url, {tag: etext},
                                    function(data) {
                                        addMembers(etext, data);
                                        json_cache = true;
                                        bindEvents();
                                    });
                                },
                                options.delay);
                            }
                        }
                        else{
                            addMembers(etext);
                            bindEvents();
                        }
                        complete.children(".default").hide();
                        feed.show();
                    }
                });
                if (focusme) {
                    setTimeout(function() {
                        input.focus();
                        complete.children(".default").show();
                    },
                    1);
                }
            }

            function addMembers(etext, data) {
                feed.html('');

                if (!options.cache && data != null) {
                    cache = new Array();
                    search_string = "";
                }

                addTextItem(etext);

                if (data != null && data.length) {
                    $.each(data,
                    function(i, val) {
                        cache.push({
                            key: val.key,
                            value: val.value
                        });
                        search_string += "" + (cache.length - 1) + ":" + val.key + ";";
                    });
                }

                var maximum = options.maxshownitems < cache.length ? options.maxshownitems: cache.length;
                var filter = "i";
                if (options.filter_case) {
                    filter = "";
                }

                var myregexp,
                match;
                try{
                    myregexp = eval('/(?:^|;)\\s*(\\d+)\\s*:[^;]*?' + etext + '[^;]*/g' + filter);
                    match = myregexp.exec(search_string);
                }
                catch(ex) {
                    };

                var content = '';
                while (match != null && maximum > 0) {
                    var id = match[1];
                    var object = cache[id];
                    if (options.filter_selected && element.children("option[value=" + object.value + "]").hasClass("selected")) {
                        //nothing here...
                        }
                    else{
                        content += '<li rel="' + object.value + '">' + itemIllumination(object.key, etext) + '</li>';
                        counter++;
                        maximum--;
                    }
                    match = myregexp.exec(search_string);
                }
                feed.append(content);

                if (options.firstselected) {
                    focuson = feed.children("li:visible:first");
                    focuson.addClass("auto-focus");
                }

                if (counter > options.height) {
                    feed.css({
                        "height": (options.height * 24) + "px",
                        "overflow": "auto"
                    });
                }
                else{
                    feed.css("height", "auto");
                }
            }

            function itemIllumination(text, etext) {
                if (options.filter_case) {
                    try{
                        eval("var text = text.replace(/(.*)(" + etext + ")(.*)/gi,'$1<em>$2</em>$3');");
                    }
                    catch(ex) {
                        };
                }
                else{
                    try{
                        eval("var text = text.replace(/(.*)(" + etext.toLowerCase() + ")(.*)/gi,'$1<em>$2</em>$3');");
                    }
                    catch(ex) {
                        };
                }
                return text;
            }

            function bindFeedEvent() {
                feed.children("li").mouseover(function() {
                    feed.children("li").removeClass("auto-focus");
                    $(this).addClass("auto-focus");
                    focuson = $(this);
                });

                feed.children("li").mouseout(function() {
                    $(this).removeClass("auto-focus");
                    focuson = null;
                });
            }

            function removeFeedEvent() {
                feed.children("li").unbind("mouseover");
                feed.children("li").unbind("mouseout");
                feed.mousemove(function() {
                    bindFeedEvent();
                    feed.unbind("mousemove");
                });
            }

            function bindEvents() {
                var maininput = $("#" + elemid + "_annoninput").children(".maininput");
                bindFeedEvent();
                feed.children("li").unbind("mousedown");
                feed.children("li").mousedown(function() {
                    var option = $(this);
                    addItem(option.text(), option.attr("rel"), 0, 0, 1);
                    feed.hide();
                    complete.hide();
                });

                maininput.unbind("keydown");
                maininput.keydown(function(event) {
                    if (event.keyCode == 191) {
                        event.preventDefault();
                        return false;
                    }

                    if (event.keyCode != 8) {
                        holder.children("li.bit-box.deleted").removeClass("deleted");
                    }

                    if ((event.keyCode == 13 || event.keyCode == 9) && checkFocusOn()) {
                        var option = focuson;
                        addItem(option.text(), option.attr("rel"), 0, 0, 1);
                        complete.hide();
                        event.preventDefault();
                        focuson = null;
                        return false;
                    }

                    if ((event.keyCode == 13 || event.keyCode == 9) && !checkFocusOn()) {
                        if (options.newel) {
                            var value = xssPrevent($(this).val());
                            addItem(value, value, 0, 0, 1);
                            complete.hide();
                            event.preventDefault();
                            focuson = null;
                            return false;
                        }
                        
                        if (options.addontab) {
                          focuson = feed.children("li:visible:first");
                          var option = focuson;
                          addItem(option.text(), option.attr("rel"), 0, 0, 1);
                          complete.hide();
                          event.preventDefault();
                          focuson = null;
                          return false;
                        }                        
                    }

                    if (event.keyCode == 40) {
                        removeFeedEvent();
                        if (focuson == null || focuson.length == 0) {
                            focuson = feed.children("li:visible:first");
                            feed.get(0).scrollTop = 0;
                        }
                        else{
                            focuson.removeClass("auto-focus");
                            focuson = focuson.nextAll("li:visible:first");
                            var prev = parseInt(focuson.prevAll("li:visible").length, 10);
                            var next = parseInt(focuson.nextAll("li:visible").length, 10);
                            if ((prev > Math.round(options.height / 2) || next <= Math.round(options.height / 2)) && typeof(focuson.get(0)) != "undefined") {
                                feed.get(0).scrollTop = parseInt(focuson.get(0).scrollHeight, 10) * (prev - Math.round(options.height / 2));
                            }
                        }
                        feed.children("li").removeClass("auto-focus");
                        focuson.addClass("auto-focus");
                    }
                    if (event.keyCode == 38) {
                        removeFeedEvent();
                        if (focuson == null || focuson.length == 0) {
                            focuson = feed.children("li:visible:last");
                            feed.get(0).scrollTop = parseInt(focuson.get(0).scrollHeight, 10) * (parseInt(feed.children("li:visible").length, 10) - Math.round(options.height / 2));
                        }
                        else{
                            focuson.removeClass("auto-focus");
                            focuson = focuson.prevAll("li:visible:first");
                            var prev = parseInt(focuson.prevAll("li:visible").length, 10);
                            var next = parseInt(focuson.nextAll("li:visible").length, 10);
                            if ((next > Math.round(options.height / 2) || prev <= Math.round(options.height / 2)) && typeof(focuson.get(0)) != "undefined") {
                                feed.get(0).scrollTop = parseInt(focuson.get(0).scrollHeight, 10) * (prev - Math.round(options.height / 2));
                            }
                        }
                        feed.children("li").removeClass("auto-focus");
                        focuson.addClass("auto-focus");
                    }
                });
            }

            function maxItems() {
                if (options.maxitems != 0) {
                    if (holder.children("li.bit-box").length < options.maxitems) {
                        return true;
                    }
                    else{
                        return false;
                    }
                }
            }

            function addTextItem(value) {
                if (options.newel && maxItems()) {
                    feed.children("li[fckb=1]").remove();
                    if (value.length == 0) {
                        return;
                    }
                    var li = $(document.createElement("li"));
                    li.attr({
                        "rel": value,
                        "fckb": "1"
                    }).html(value);
                    feed.prepend(li);
                    counter++;
                }
                else{
                    return;
                }
            }

            function funCall(func, item) {
                var _object = "";
                for (i = 0; i < item.get(0).attributes.length; i++) {
                    if (item.get(0).attributes[i].nodeValue != null) {
                        _object += "\"_" + item.get(0).attributes[i].nodeName + "\": \"" + item.get(0).attributes[i].nodeValue + "\",";
                    }
                }
                _object = "{" + _object + " notinuse: 0}";
                func.call(func, _object);
            }

            function checkFocusOn() {
                if (focuson == null) {
                    return false;
                }
                if (focuson.length == 0) {
                    return false;
                }
                return true;
            }

            function xssPrevent(string) {
                string = string.replace(/[\"\'][\s]*javascript:(.*)[\"\']/g, "\"\"");
                string = string.replace(/script(.*)/g, "");
                string = string.replace(/eval\((.*)\)/g, "");
                string = string.replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '');
                return string;
            }

            var options = $.extend({
                json_url: null,
                cache: false,
                height: "10",
                newel: false,
                addontab: false,
                firstselected: false,
                filter_case: false,
                filter_selected: false,
                complete_text: "Start to type...",
                maxshownitems: 30,
                maxitems: 10,
                onselect: null,
                onremove: null,
                attachto: null,
                delay: 350
            },
            opt);

            //system variables
            var holder = null;
            var feed = null;
            var complete = null;
            var counter = 0;
            var cache = new Array();
            var json_cache = false;
            var search_string = "";
            var focuson = null;
            var deleting = 0;
            var complete_hover = 1;

            var element = $(this);
            var elemid = element.attr("id");
            init();

            return this;
        });
    };
});

