/*!
 * jQuery TagWidget plugin v0.9.6
 * http://www.imexis.net
 *
 * Copyright (c) 2009 Imexis
 * Licensed under GNU General Public Licence v3.
 * http://www.gnu.org/licenses/gpl-3.0.txt
 *
 * Date: 2009-04-30 15:00:00 (Thu, 30 Apr 2009)
 * Revision: 096
 */
(function($){
    $.fn.addNewTabIndex = function(){
        var highestTabIndex = -1;
        return this.each(function(){
            $("*[tabindex]").each(function(){
                curTabIndex = parseInt($(this).attr("tabindex"));
                highestTabIndex = (highestTabIndex > curTabIndex) ? highestTabIndex : curTabIndex;
            })
            highestTabIndex = highestTabIndex + 1;
            $(this).attr({
                'tabindex': highestTabIndex
            });
        });
    };
    
    $.fn.addNewZIndex = function(){
        var highestZIndex = 1000;
        return this.each(function(){
            $("*[z-index]").each(function(){
                curZIndex = parseInt($(this).css("z-index"));
                highestZIndex = (highestZIndex > curZIndex) ? highestZIndex : curZIndex;
            })
            highestZIndex = highestZIndex + 1;
            $(this).css({
                'z-index': highestZIndex
            });
        });
    };
    
    $.fn.tagWidget = function(tags, actions, options){
        var KEY = {
            UP: 38,
            DOWN: 40,
            PAGEUP: 33,
            PAGEDOWN: 34
        };
        var TYPE = {
            TAG: "tag",
            ACTION: "action"
        };
        var tags = tags;
        var actions = actions;
        var options = options;
        var tabIndex = 0;
        var scrollHeight = 182;
        
        return this.each(function(){
            var insideTagSearch = false;
            var $tagWidget = $(this);
            var $tagButton = null;
            var $tagPopup = null;
            var $searchInput = null;
            var $tagList = null;
            var $tagElements = null;
            var insideTagPopup = false;
            var insideTagButton = false;
            var hoveringEnabled = false;
            
            $tagWidget.defaults = {
                tagWidgetClass: "tw",
                tagButtonClass: "tb",
                tagPopupClass: "tp",
                tagSearchClass: "tp-search",
                searchInputClass: "searchInput",
                tagListClass: "tp-list",
                tagClass: "tp-tag",
                actionListClass: "tp-actions",
                actionClass: "tp-action",
                checkedClass: "ui-state-active",
                checkedIconClass: "ui-icon-check",
                uncheckedIconClass: "ui-icon-minus",
                overClass: "ui-state-hover",
                selectedClass: "ui-state-active",
                minChars: 1,
                delay: 400,
                matchCase: false,
                matchSubset: true,
                matchContains: false,
                cacheLength: 10,
                max: 100,
                mustMatch: false,
                extraParams: {},
                selectFirst: true,
                formatItem: function(row){
                    return row[0];
                },
                formatMatch: null,
                autoFill: false,
                width: 175,
                multiple: false,
                multipleSeparator: ", ",
                highlight: function(value, term){
                    return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
                },
                scroll: true,
                scrollHeight: 180,
                numberElementVisible: 10,
                multiSelect: false,
                buttonLabel: "Tag"
            };
            /* generateElementId */
            $tagWidget.generateElementId = function(type, id){
                return 'tw-' + $tagWidget.attr('id') + '-' + type + '-' + id;
            };
            /* getTextbox */
            $tagWidget.getTextbox = function(){
                return $(".searchInput", $tagWidget);
            };
            /* 	getAllTags */
            $tagWidget.getAllTags = function(){
                return $("li." + options.tagClass, $tagWidget);
            }
            /* 	getAllVisibleTags */
            $tagWidget.getAllVisibleTags = function(){
                return $("li." + options.tagClass + ":visible", $tagWidget);
            }
            /* 	getAllVisibleActions */
            $tagWidget.getAllVisibleActions = function(){
                return $("li." + options.actionClass + ":visible", $tagWidget);
            }
            /* 	getAllCheckedTags */
            $tagWidget.getAllCheckedTags = function(){
                return $("li." + options.checkedClass, $tagWidget);
            }
            /* 	getAllOverElements */
            $tagWidget.getAllOverElements = function(){
                return $("li." + options.overClass, $tagWidget);
            }
            /* 	getAllOverTagElements */
            $tagWidget.getAllOverTagElements = function(){
                return $("li." + options.tagClass + "." + options.overClass, $tagWidget);
            }
            /* 	getAllOverActionElements */
            $tagWidget.getAllOverActionElements = function(){
                return $("li." + options.actionClass + "." + options.overClass, $tagWidget);
            }
            
            /* 	addTagElement */
            $tagWidget.addTagElement = function(id, text, isChecked){
                tagElement = $("<li/>").attr({
                    'id': $tagWidget.generateElementId(TYPE.TAG, id),
                    'tagType': TYPE.TAG
                }).addClass(options.tagClass).addClass('ui-state-default');
                tagElement.click(function(){
                    $tagWidget.toggleElement($(this));
                }).hover(function(){
                    if (hoveringEnabled) {
                        $tagWidget.addOverToElement($(this));
                    }
                }, function(){
                    $tagWidget.removeOverToElement($(this));
                });
                tagElement.text(text);
                if (options.multiSelect) {
                    tagElement.prepend($("<span/>").addClass('ui-icon'));
                } else {
					tagElement.css({'padding':'1px 5px'});
				}
                if (isChecked) {
                    $tagWidget.checkTagElement(tagElement);
                }
                else {
                    $tagWidget.uncheckTagElement(tagElement);
                }
                $tagElements.append(tagElement);
            }
            /* 	removeTagElement */
            $tagWidget.removeTagElement = function(tagId){
                tagElementId = '#' + $tagWidget.generateElementId(TYPE.TAG, tagId);
                $tagElements.remove($(tagElementId, $tagWidget));
            };
            /* addOverToElement */
            $tagWidget.addOverToElement = function(el){
                $("li." + options.overClass, $tagWidget).removeClass(options.overClass);
                el.addClass(options.overClass);
            }
            /* removeOverToElement */
            $tagWidget.removeOverToElement = function(el){
                el.removeClass(options.overClass);
            }
            /* elementHasOver */
            $tagWidget.elementHasOver = function(el){
                return el.hasClass(options.overClass);
            }
            /* disableHovering */
            $tagWidget.disableHovering = function(){
                hoveringEnabled = false;
            }
            /* enableHovering */
            $tagWidget.enableHovering = function(){
                hoveringEnabled = true;
            }
            /* toggleElement */
            $tagWidget.toggleElement = function(el){
                if (el.attr('tagType') == TYPE.TAG) {
                    if (options.multiSelect) {
                        if ($tagWidget.tagElementIsChecked(el)) {
                            $tagWidget.uncheckTagElement(el);
                        }
                        else {
                            $tagWidget.checkTagElement(el);
                        }
                    }
                    else {
                        $("li." + options.checkedClass, $tagWidget).each(function(){
                            $tagWidget.uncheckTagElement($(this));
                        });
                        $tagWidget.checkTagElement(el);
                    }
                    jQuery.each(actions, function(id, action){
                        if (action.defaultAction) {
                            action.callback($tagWidget);
                        }
                    });
                    $searchInput.focus();
                }
                else {
                    if (el.attr('tagType') == TYPE.ACTION) {
                        el.click();
                    }
                }
            }
            /* tagElementIsChecked */
            $tagWidget.tagElementIsChecked = function(el){
                if (el.hasClass(options.checkedClass)) {
                    return true;
                }
                else {
                    return false;
                }
            }
            
            /* checkTagElement */
            $tagWidget.checkTagElement = function(el){
                if (!$tagWidget.tagElementIsChecked(el)) {
                    if (options.multiSelect) {
                        el.addClass(options.checkedClass);
                        $('span', el).addClass(options.checkedIconClass).removeClass(options.uncheckedIconClass);
                    }
                    else {
                        el.addClass(options.checkedClass);
                    }
                }
            }
            
            /* uncheckTagElement */
            $tagWidget.uncheckTagElement = function(el){
                if (options.multiSelect) {
                    el.removeClass(options.checkedClass);
                    $('span', el).removeClass(options.checkedIconClass).addClass(options.uncheckedIconClass);
                }
                else {
                    el.removeClass(options.checkedClass);
                }
            }
            
            /* closePopup */
            $tagWidget.closePopup = function(){
                if (!insideTagPopup) {
                    $tagButton.removeClass(options.selectedClass);
                    $tagPopup.hide();
                }
            };
            /* openPopup */
            $tagWidget.openPopup = function(){
                newHeight = 10;
                $tagButton.addClass(options.selectedClass);
                $tagPopup.css('left', $tagButton.offset().left);
                $tagPopup.css('top', $tagButton.offset().top + $tagButton.outerHeight());
                $tagPopup.addNewZIndex();
                $tagPopup.show();
                if ($tagWidget.getAllTags().size() > 0) {
                    defaultElementHeight = $tagWidget.getAllTags().eq(0).outerHeight();
                    newHeight = defaultElementHeight * options.numberElementVisible;
                }
                if (newHeight == 0) {
                    newHeight = options.scrollHeight;
                }
                $tagList.css({
                    'max-height': newHeight,
                    'min-height': newHeight
                });
                scrollHeight = newHeight;
                $searchInput.focus();
            };
            
            /* 	addAction */
            $tagWidget.addAction = function(action){
                actionElement = $("<li/>").addClass(options.actionClass).addClass('ui-state-default').attr({
                    'id': $tagWidget.generateElementId(TYPE.ACTION, action.id),
                    'tagType': TYPE.ACTION
                });
                actionElement.hover(function(){
                    $tagWidget.addOverToElement($(this));
                }, function(){
                    $tagWidget.removeOverToElement($(this));
                }).click(function(){
                    action.callback($tagWidget);
                    $searchInput.focus();
                });
                actionElement.append($("<span/>").addClass('ui-icon').addClass('ui-icon-check'));
                actionElement.text(action.label);
                $actionElements.append(actionElement);
            };
            /* 	removeAction */
            $tagWidget.removeAction = function(actionId){
                actionElementId = '#' + $tagWidget.generateElementId('action', actionId);
                $actionElements.remove($(actionElementId, $tagWidget));
            };
            /* 	showAction */
            $tagWidget.showAction = function(actionId){
                actionElementId = '#' + $tagWidget.generateElementId('action', actionId);
                $(actionElementId).show();
            };
            /* 	hideAction */
            $tagWidget.hideAction = function(actionId){
                actionElementId = '#' + $tagWidget.generateElementId('action', actionId);
                $(actionElementId).hide();
            };
            /* 	adaptScroll */
            $tagWidget.adaptScroll = function(){
                overElement = $tagWidget.getAllOverElements();
                if (overElement.attr('tagType') == TYPE.TAG) {
                    var tagIdArr = [];
                    scrollDistance = 0;
                    $tagWidget.getAllVisibleTags().each(function(){
                        tagIdArr.push($(this).attr('id'));
                    });
                    topPositionElement = (jQuery.inArray(overElement.attr('id'), tagIdArr)) * overElement.outerHeight();
                    topPositionScrollTagList = $tagList.scrollTop();
                    bottomPositionElement = (jQuery.inArray(overElement.attr('id'), tagIdArr) + 1) * overElement.outerHeight();
                    bottomPositionScrollTagList = $tagList.scrollTop() + $tagList.innerHeight();
                    if (topPositionScrollTagList > topPositionElement) {
                        $tagWidget.disableHovering();
                        scrollDistance = topPositionElement;
                        $tagList.scrollTop(scrollDistance);
                    }
                    else 
                        if (bottomPositionElement > bottomPositionScrollTagList) {
                            $tagWidget.disableHovering();
                            scrollDistance = bottomPositionElement - $tagList.innerHeight();
                            $tagList.scrollTop(scrollDistance);
                        }
                }
            };
            
            /*
             * TagWidget
             */
            options = $.extend({}, $tagWidget.defaults, options);
            $(this).addClass(options.tagWidgetClass).addClass('ui-widget');
            
            /*
             * tagButton
             */
            $tagButton = $("<a/>");
            $tagButton.addClass(options.tagButtonClass).addClass('ui-state-default').addClass('ui-corner-all');
            $tagButton.text(options.buttonLabel);
            $tagButton.append($("<span/>").addClass('ui-icon').addClass('ui-icon-triangle-1-s'));
            $tagButton.click(function(){
                if ($tagButton.hasClass(options.selectedClass)) {
                    $tagWidget.closePopup();
                }
                else {
                    $tagWidget.openPopup();
                }
            }).hover(function(){
                $tagButton.addClass('ui-state-hover');
                insideTagButton = true;
            }, function(){
                $tagButton.removeClass('ui-state-hover');
                insideTagButton = false;
            });
            $tagWidget.append($tagButton);
            
            /*
             * tagPopup
             */
            $tagPopup = $("<div/>");
            $tagPopup.addClass(options.tagPopupClass).addClass('ui-widget-content').addClass('ui-corner-all').addNewTabIndex();
            $tagPopup.focus(function(){
            }).blur(function(){
                $tagWidget.closePopup();
            }).hover(function(){
                insideTagPopup = true;
            }, function(){
                insideTagPopup = false;
            }).mousemove(function(){
                $tagWidget.enableHovering();
            });
            $tagPopup.css({
                'display': 'none',
                'left': $(this).offset().left + "px"
            });
            $tagWidget.append($tagPopup);
            
            /* 
             * tagSearch
             */
            searchTag = $("<div/>");
            searchTag.addClass(options.tagSearchClass);
            $tagPopup.append(searchTag);
            
            $searchInput = $("<input/>").addClass(options.searchInputClass).addClass('ui-state-default').addClass('ui-state-active').attr({
                type: "text",
                autocomplete: "off"
            });
			//$searchInput.append($("<span/>").addClass('ui-icon').addClass('ui-icon-search'));
            $searchInput.focus(function(){
            }).blur(function(){
                if (!insideTagButton) 
                    $tagWidget.closePopup();
            });
            searchTag.append($searchInput);
            
            /*
             * tagList
             */
            $tagList = $("<div/>");
            $tagList.addClass(options.tagListClass);
            $tagPopup.append($tagList);
            
            $tagElements = $("<ul/>");
            $tagList.append($tagElements);
            
            for (var i = 0; i < tags.length; i++) {
                tag = tags[i];
                $tagWidget.addTagElement(tag.id, tag.label, tag.selected);
            }
            
            /* 
             * TagActions
             */
            $actionElements = $("<ul/>");
            $tagPopup.append($("<div/>").addClass(options.actionListClass).append($actionElements));
            jQuery.each(actions, function(id, action){
                $tagWidget.addAction(action);
            });
            
            /*
             * Special treatment
             */
            /* Filter */
            new $.Filter($tagWidget, $searchInput, $tagList, options);
            
        });
        
        
        
    };
    
    $.Filter = function($tagWidget, input, $tagList, options){
    
        var KEY = {
            UP: 38,
            DOWN: 40,
            DEL: 46,
            TAB: 9,
            RETURN: 13,
            ESC: 27,
            COMMA: 188,
            PAGEUP: 33,
            PAGEDOWN: 34,
            BACKSPACE: 8,
            SPACE: 32
        };
        var TYPE = {
            TAG: "tag",
            ACTION: "action"
        };
        var timeout;
        var stopTimeout;
        var $tagWidget = $tagWidget;
        var $tagList = $tagList;
        var lastKeyCode;
        
        $input = $(input);
        /* setTimeout */
        $input.setTimeout = function(to){
            timeout = to;
        }
        /* getTimeout */
        $input.getTimeout = function(){
            return timeout;
        }
        
        /* changeSelection */
        $input.changeSelection = function($tagWidget, $tagList, options, lastKeyCode){
            // track last key pressed
            switch (lastKeyCode) {
                case KEY.UP:
                case KEY.PAGEUP:
                    // remove all Over class from hidden elements
                    $(":hidden", $tagWidget.getAllOverElements()).each(function(){
                        $tagWidget.removeOverToElement($(this));
                    });
                    if ($tagWidget.getAllOverElements().size() > 0) {
                        // select current element
                        overElement = $tagWidget.getAllOverElements();
                        if (overElement.attr('tagType') == TYPE.TAG) {
                            // a visible Tag has class Over
                            var tagIdArr = [];
                            $tagWidget.getAllVisibleTags().each(function(){
                                tagIdArr.push($(this).attr('id'));
                            });
                            firstTagId = $tagWidget.getAllVisibleTags().filter(':first').attr('id');
                            curTagId = $tagWidget.getAllOverTagElements().filter(':first').attr('id');
                            currentElementIndex = jQuery.inArray(overElement.attr('id'), tagIdArr);
                            nbVisibleElements = $tagWidget.getAllVisibleTags().size();
                            firstElementIndex = 0;
                            if (currentElementIndex == firstElementIndex) {
                                // if first visible Tag then Tag last Action
                                $tagWidget.getAllOverElements().each(function(){
                                    $tagWidget.removeOverToElement($(this));
                                });
                                $tagWidget.addOverToElement($tagWidget.getAllVisibleActions().filter(':last'));
                            }
                            else {
                                switch (lastKeyCode) {
                                    case KEY.UP:
                                        // otherwise Tag the previous Tag
                                        $tagWidget.addOverToElement($tagWidget.getAllOverTagElements().removeClass(options.overClass).prevAll(':visible:first'));
                                        $tagWidget.adaptScroll();
                                        break;
                                    case KEY.PAGEUP:
                                        // otherwise Tag the previous Scroll Tag
                                        elementHeight = overElement.outerHeight();
                                        topPositionScrollTagList = $tagList.scrollTop();
                                        topElementIndex = (topPositionScrollTagList - (topPositionScrollTagList % elementHeight)) / elementHeight;
                                        if ((elementHeight / 2) < (topPositionScrollTagList % elementHeight)) {
                                            topElementIndex = topElementIndex + 1;
                                        }
                                        nbElemInsideTagList = (($tagList.innerHeight() - ($tagList.innerHeight() % elementHeight)) / elementHeight) - 1;
                                        bottomElementIndex = nbElemInsideTagList + topElementIndex;
                                        if (currentElementIndex == topElementIndex) {
                                            // if current element is last visible element then scroll
                                            if (currentElementIndex <= nbElemInsideTagList) {
                                                // if jump is too far: limit to the first element
                                                nextElementIndex = firstElementIndex;
                                            }
                                            else {
                                                // else jump of nb elements inside the tagList
                                                nextElementIndex = topElementIndex - nbElemInsideTagList;
                                            }
                                        }
                                        else {
                                            // else jump to the topElementIndex
                                            nextElementIndex = topElementIndex;
                                        }
                                        $tagWidget.addOverToElement($tagWidget.getAllVisibleTags().eq(nextElementIndex));
                                        $tagWidget.adaptScroll();
                                        break;
                                }
                            }
                        }
                        else {
                            if ($tagWidget.getAllOverElements().attr('tagType') == TYPE.ACTION) {
                                // a visible Action has class Over
                                firstActionId = $tagWidget.getAllVisibleActions().filter(':first').attr('id');
                                curActionId = $tagWidget.getAllOverActionElements().filter(':first').attr('id');
                                regExp = new RegExp(curActionId, "i");
                                if (regExp.test(firstActionId)) {
                                    // if first visible Action then Tag last tag
                                    $tagWidget.getAllOverElements().each(function(){
                                        $tagWidget.removeOverToElement($(this));
                                    });
                                    $tagWidget.addOverToElement($tagWidget.getAllVisibleTags().filter(':last'));
                                    $tagWidget.adaptScroll();
                                }
                                else {
                                    switch (lastKeyCode) {
                                        case KEY.UP:
                                            // otherwise Tag the previous Action
                                            $tagWidget.addOverToElement($tagWidget.getAllOverActionElements().removeClass(options.overClass).prevAll(':visible:first'));
                                            break;
                                        case KEY.PAGEUP:
                                            // otherwise Tag the first Action
                                            $tagWidget.addOverToElement($tagWidget.getAllOverActionElements().removeClass(options.overClass).prevAll(':visible:last'));
                                            break;
                                    }
                                }
                            }
                        }
                    }
                    else {
                        // No element has the Over class
                        if ($tagWidget.getAllVisibleTags().size() > 0) {
                            // Tag the last Tag
                            $tagWidget.addOverToElement($tagWidget.getAllVisibleTags().filter(':last'));
                            $tagWidget.adaptScroll();
                        }
                        else 
                            if ($tagWidget.getAllVisibleActions().size() > 0) {
                                // Tag the last Action
                                $tagWidget.addOverToElement($tagWidget.getAllVisibleActions().filter(':last'));
                            }
                    }
                    break;
                    
                case KEY.DOWN:
                case KEY.PAGEDOWN:
                    // remove all Over class from hidden elements
                    $(":hidden", $tagWidget.getAllOverElements()).each(function(){
                        $tagWidget.removeOverToElement($(this));
                    });
                    if ($tagWidget.getAllOverElements().size() > 0) {
                        // select current element
                        overElement = $tagWidget.getAllOverElements();
                        
                        if (overElement.attr('tagType') == TYPE.TAG) {
                            // a visible Tag has class Over
                            var tagIdArr = [];
                            $tagWidget.getAllVisibleTags().each(function(){
                                tagIdArr.push($(this).attr('id'));
                            });
                            lastTagId = $tagWidget.getAllVisibleTags().filter(':last').attr('id');
                            curTagId = $tagWidget.getAllOverTagElements().filter(':first').attr('id');
                            currentElementIndex = jQuery.inArray(overElement.attr('id'), tagIdArr);
                            nbVisibleElements = $tagWidget.getAllVisibleTags().size();
                            lastElementIndex = nbVisibleElements - 1;
                            if (currentElementIndex == lastElementIndex) {
                                // if last visible Tag then Tag first Action
                                $tagWidget.getAllOverElements().each(function(){
                                    $tagWidget.removeOverToElement($(this));
                                });
                                $tagWidget.addOverToElement($tagWidget.getAllVisibleActions().filter(':first'));
                            }
                            else {
                                switch (lastKeyCode) {
                                    case KEY.DOWN:
                                        // otherwise Tag the next Tag
                                        $tagWidget.addOverToElement($tagWidget.getAllOverTagElements().removeClass(options.overClass).nextAll(':visible:first'));
                                        $tagWidget.adaptScroll();
                                        break;
                                    case KEY.PAGEDOWN:
                                        // otherwise Tag the next Scroll Tag
                                        elementHeight = overElement.outerHeight();
                                        topPositionScrollTagList = $tagList.scrollTop();
                                        topElementIndex = (topPositionScrollTagList - (topPositionScrollTagList % elementHeight)) / elementHeight;
                                        if ((elementHeight / 2) < (topPositionScrollTagList % elementHeight)) {
                                            topElementIndex = topElementIndex + 1;
                                        }
                                        nbElemInsideTagList = (($tagList.innerHeight() - ($tagList.innerHeight() % elementHeight)) / elementHeight) - 1;
                                        if (topElementIndex + nbElemInsideTagList <= lastElementIndex) {
                                            bottomElementIndex = topElementIndex + nbElemInsideTagList;
                                        }
                                        else {
                                            bottomElementIndex = lastElementIndex;
                                        }
                                        if (currentElementIndex == bottomElementIndex) {
                                            // if current element is last visible element then scroll
                                            if (currentElementIndex + nbElemInsideTagList >= nbVisibleElements) {
                                                // if jump is too far: limit to the last element
                                                nextElementIndex = nbVisibleElements - 1;
                                            }
                                            else {
                                                // else jump of nb elements inside the tagList
                                                nextElementIndex = bottomElementIndex + nbElemInsideTagList;
                                            }
                                        }
                                        else {
                                            // else jump to the bottomElementIndex
                                            nextElementIndex = bottomElementIndex;
                                        }
                                        $tagWidget.addOverToElement($tagWidget.getAllVisibleTags().eq(nextElementIndex));
                                        $tagWidget.adaptScroll();
                                        break;
                                }
                            }
                        }
                        else {
                            if ($tagWidget.getAllOverElements().attr('tagType') == TYPE.ACTION) {
                                // a visible Action has class Over
                                lastActionId = $tagWidget.getAllVisibleActions().filter(':last').attr('id');
                                curActionId = $tagWidget.getAllOverActionElements().filter(':first').attr('id');
                                regExp = new RegExp(curActionId, "i");
                                if (regExp.test(lastActionId)) {
                                    // if last visible Action then Tag first tag
                                    $tagWidget.getAllOverElements().each(function(){
                                        $tagWidget.removeOverToElement($(this));
                                    });
                                    $tagWidget.addOverToElement($tagWidget.getAllVisibleTags().filter(':first'));
                                    $tagWidget.adaptScroll();
                                }
                                else {
                                    switch (lastKeyCode) {
                                        case KEY.DOWN:
                                            // otherwise Tag the next Action
                                            $tagWidget.addOverToElement($tagWidget.getAllOverActionElements().removeClass(options.overClass).nextAll(':visible:first'));
                                            break;
                                        case KEY.PAGEDOWN:
                                            // otherwise Tag the last Action
                                            $tagWidget.addOverToElement($tagWidget.getAllOverActionElements().removeClass(options.overClass).nextAll(':visible:last'));
                                            break;
                                    }
                                }
                            }
                        }
                    }
                    else {
                        // No element has the Over class
                        if ($tagWidget.getAllVisibleTags().size() > 0) {
                            // Tag the first Tag
                            $tagWidget.addOverToElement($tagWidget.getAllVisibleTags().filter(':first'));
                            $tagWidget.adaptScroll();
                        }
                        else {
                            // Tag the first Action
                            if ($tagWidget.getAllVisibleActions().size() > 0) {
                                $tagWidget.addOverToElement($tagWidget.getAllVisibleActions().filter(':first'));
                            }
                        }
                    }
                    break;
            }
            clearTimeout($input.getTimeout());
            $input.setTimeout(setTimeout(function(){
                $input.changeSelection($tagWidget, $tagList, options, lastKeyCode)
            }, options.delay));
        };
        
        $input.bind("keyup", function(event){
            switch (event.keyCode) {
                case KEY.UP:
                case KEY.DOWN:
                case KEY.PAGEUP:
                case KEY.PAGEDOWN:
                case KEY.TAB:
                case KEY.RETURN:
                case KEY.SPACE:
                    clearTimeout($input.getTimeout());
                    break;
                default:
                    searchEl = $(this);
                    var pattern = searchEl.val().replace(/^\s+|\s+$/g, '');
                    var regExp = new RegExp(pattern, "i");
                    var lis = $tagWidget.getAllTags().each(function(){
                        if (regExp.test($(this).text())) {
                            $(this).show();
                        }
                        else {
                            if ($tagWidget.elementHasOver($(this))) {
                                $tagWidget.removeOverToElement($(this));
                            }
                            $(this).hide();
                        }
                    });
                    break;
            }
        });
        $input.keydown(function(event){
            // track last key pressed
            switch (event.keyCode) {
            
                case KEY.UP:
                case KEY.PAGEUP:
                case KEY.DOWN:
                case KEY.PAGEDOWN:
                    lastKeyCode = event.keyCode;
                    event.preventDefault();
                    $input.changeSelection($tagWidget, $tagList, options, lastKeyCode);
                    break;
                    
                case KEY.TAB:
                case KEY.RETURN:
                    if ($tagWidget.getAllOverElements().size() > 0) {
                        $tagWidget.toggleElement($tagWidget.getAllOverElements());
                    }
                    break;
                case KEY.ESC:
                    $tagWidget.closePopup();
                    break;
                    
                default:
                    break;
            }
        })
        
    };
    
})(jQuery);

