    if(typeof VYRE === "undefined"){
        VYRE = {
            name:"VYRE",
            vyreVersion:"4310"
        };
    }

    VYRE.SuggestSource = function (settings) {
        this.ajaxSearch = null;
        this.attributeId = null;
        this.jsonSourceId = null;
        this.suggest = null;
        if( typeof settings != "undefined" ) {
            for( var property in this) {
                if(typeof settings[property] != "undefined") {
                    this[property] = settings[property];
                }
            }
        }
        var self = this;
        if(this.ajaxSearch.responseType =="JSON") {
            this.ajaxSearch.JSONHandler = function (json) {
                self.dataRecieved(json);
            };
        } else {
            this.ajaxSearch.callBackFunctions.add(function () {
                self.dataRecieved();
            });
        }
        
    };
    VYRE.SuggestSource.prototype = {
        find : function ( prefix) {
            prefix = prefix.trim();
            prefix.replace(/\s*/gi," ");
            var tokens = prefix.split(" ");
            var luceneString = "";
            for( var i=0; i<tokens.length; i++) {
                if(tokens[i] != "") {
                    if(i != 0) {
                        luceneString += " AND ";
                    }
                    luceneString +=tokens[i];
                }
            }
            luceneString +="*";
            
            luceneString = encodeURIComponent(luceneString);
            
            this.ajaxSearch.attributes.set( new VYRE.Attribute(this.attributeId, luceneString));
            this.ajaxSearch.search();
        },

        registerAutoSuggest : function( suggest ) {
            this.suggest = suggest;
        },
        dataRecieved : function (json) {
            if(json) {
                this.suggest.setSuggestions( JSONstring.toObject(json) );
            } else {
                this.suggest.setSuggestions(JSONstring.toObject(document.getElementById(this.jsonSourceId).value));
            }
        }


    };

   
    VYRE.AutoSuggest = function (settings) {
        var self = this;
        this.letterCount = 0;
        this.cachedSearches = [];
        this.cachedSuggestions = [];
        this.validate = false;
        this.lastSearchPrefix = "";
        this.valid = true;
        this.validate = false;
        this.suggestSource = null;
        this.includeCloseButton = false;
        this.inputFieldId = null;
        this.imagePreview = false;
        if( typeof settings != "undefined" ) {
            for( var property in this) {
                if(typeof settings[property] != "undefined") {
                    this[property] = settings[property];
                }
            }
        }
        this.suggestSource.registerAutoSuggest(this);
        this.inputField = document.getElementById(this.inputFieldId);
        this.suggestionsContainer = VYRE.AutoSuggest.createElement( {tag:"div",className:"suggestionsContainer"} );
        this.suggestionsLeft =  VYRE.AutoSuggest.createElement({tag:"div",className:"suggestionsLeft"});
        this.suggestionsContainer.appendChild(this.suggestionsLeft);
        if(this.imagePreview == true) {
            this.imageBox = VYRE.AutoSuggest.createElement({tag:"div",className:"imageBox"});
            this.previewImage = VYRE.AutoSuggest.createElement({tag:"img", className:"suggestImage"});
            this.suggestionsContainer.appendChild(this.imageBox);
            this.imageBox.style.display ="none";
            this.imageBox.appendChild(this.previewImage);
            this.imageSources = [];
        }
        this.positionBox();
        this.appendSuggestions();
        this.lastImageSrc = "";
        this.validationHandler = function () {};
        this.copyHandler = null;
        this.inputField.onkeydown = function (e) {
            self.keydown(e);
        };
        this.inputField.onblur = function () {
            self.blur();
        };
        this.inputField.onfocus = function () {
            self.positionBox(true);
            self.search();
        };
        if(this.imagePreview == true ) {
            this.suggestionsContainer.onmouseover = function (e) {
                self.mouseover(e);
            };
            this.suggestionsContainer.onmouseout= function (e) {
                self.mouseout(e);
            };
        }
        this.suggestionsContainer.onmousedown = function (e) {
            self.suggestionBoxHandler(e);
        };
        this.selectedIndex = -1;
        this.suggestionsBox;
        this.timeout;
    };


    VYRE.AutoSuggest.preventDefault = function( e ) {
        if ( e.preventDefault ) {
            e.preventDefault();
        } else if ( e.returnValue ) {
            e.returnValue = false;
        }
        return false;
    };
    
    VYRE.AutoSuggest.cancelBubble = function (e ) {
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();
    }
    VYRE.AutoSuggest.html_entity_decode = function(str) {
      var ta=document.createElement("textarea");
      ta.innerHTML=str.replace(/</g,"&lt;").replace(/>/g,"&gt;");
      return ta.value;
    };
    VYRE.AutoSuggest.createElement = function (properties) {
        var element = null;
        if(properties && properties.tag) {
            element = document.createElement(properties.tag);
            if(properties.src) {element.setAttribute("src", properties.src);}
            if(properties.className) {element.className = properties.className;}
            if(properties.innerText) {element.appendChild(document.createTextNode(properties.innerText));}
            if(properties.id) {element.setAttribute("id",properties.id);}
            if(properties.type) {element.setAttribute("type",properties.type);}
            if(properties.href) {element.setAttribute("href",properties.href);}
        }
        return element;
    };

    VYRE.AutoSuggest.prototype = {
        appendSuggestions : function (suggestions) {
            var self = this;
            VYRE.Utils.addLoadEvent(function () {
                document.body.appendChild(self.suggestionsContainer);
            });          
        },
        positionBox : function (loaded) {
            var self = this;
            if(!loaded) {
            VYRE.Utils.addLoadEvent(function () {
                self.suggestionsContainer.style.left = self.getLeft() + "px";
                self.suggestionsContainer.style.top = (self.getTop()+self.inputField.offsetHeight) + "px";   
            });
            } else {
                self.suggestionsContainer.style.left = self.getLeft() + "px";
                self.suggestionsContainer.style.top = (self.getTop()+self.inputField.offsetHeight) + "px";   
            }
        },
        keydown : function (e) {
            var e = (e)?e : window.event;
            VYRE.AutoSuggest.cancelBubble(e);
            var self = this;
            var code = ( e.which ) ? e.which : e.keyCode;

            if ( code == 13 ) {
                if ( e.type == "keydown" ) {
                    if(this.suggestionsBox != null ) {
if(this.suggestionsBox.className=="suggestBox close"){
self.inputField.form.submit();}
else{
                        this.copySelection(this.suggestionsBox.childNodes[this.selectedIndex]);
                        this.setVisible(false);
}
                    }else{
self.inputField.form.submit();
}
                }

                return VYRE.AutoSuggest.preventDefault( e );
            } else if ( code == 9 ) {
                if ( e.type == "keydown" ) {
                    this.copySelection(this.suggestionsBox.childNodes[this.selectedIndex]);
                    this.setVisible(false);
                }
            } else if ( code == 38 || code == 63232 ) {
                if ( e.type == "keydown" ) this.changeSelected(-1);
                    return VYRE.AutoSuggest.preventDefault( e );
            } else if ( code == 40 || code == 63233 ) {
                if ( e.type == "keydown" )this.changeSelected(1);
                    return VYRE.AutoSuggest.preventDefault( e );
            } else {
                this.search();
            }
            return true;
        },
        blur : function () {
            this.setVisible(false);
        },
        
        search : function () {
            var self = this;
            clearTimeout(this.timeout);
            this.timeout = setTimeout( function () {
                var prefix = self.inputField.value;
                prefix = prefix.replace(/[:*\\?]/gi,"");
                if(prefix.length > self.letterCount) {
                    var cachedSuggestion = self.cachedSearches[prefix];
                    if(typeof cachedSuggestion !="undefined") {
                            self.setSuggestions(cachedSuggestion, true);
                        } else {
                            self.suggestSource.find(prefix);
                            self.lastSearchPrefix = prefix;
                        }
 
                    } else {
                        self.setVisible(false);
                    }
             },0);      
        },
        setSuggestions : function (suggestions,isCached) {
            if(!isCached) {
                this.cachedSearches[this.lastSearchPrefix] = suggestions;
            }
            this.suggestionsBox = this.generateSuggestionsBox( suggestions );

            this.suggestionsLeft.innerHTML = "";
            if(this.suggestionsBox != null) {
                this.suggestionsLeft.appendChild(this.suggestionsBox);
                if(this.includeCloseButton == true) {
                    this.suggestionsBox.className = "suggestBox close";
                    var closeBar = VYRE.AutoSuggest.createElement({tag:"div", className : "closeBar", innerText:"Close"});
                    var self = this;
                    closeBar.onclick = function (e) {
                        self.setVisible(false);
                    }
                    this.suggestionsLeft.appendChild(closeBar);
                }
                this.setVisible(true);
            }
            this.validateInput();
        },
        generateSuggestionsBox : function (suggestions) {
            var container = VYRE.AutoSuggest.createElement({tag:"div", className:"suggestBox"});
            var suggestElements = "";
            var inputValue = this.inputField.value;
            inputValue = inputValue.replace(/[:*\\?]/gi,"").replace(/\s/gi,"\\s*")
            for(var i  = 0; i< suggestions.items.length; i++) {
                var innerText = suggestions.items[i].name;
                if(this.validate) {
                    this.cachedSuggestions[innerText] = innerText;
                }
                innerText = innerText.replace(new RegExp("("+inputValue+")","gi"), "<b>$1</b>");
                var selected = "";
                if(i == "0") {
                    selected = " selected";
                    this.selectedIndex = 0;
                }
                innerText = "<div class = 'suggestElement"+selected+"' id='"+suggestions.items[i].id+"'>"+innerText+"</div>";
                if(suggestions.items[i].thumbnail && this.imagePreview == true) {
                    this.imageSources[suggestions.items[i].id] = suggestions.items[i].thumbnail;
                }
                suggestElements+= innerText;
            }
            if(suggestElements != "") {
                container.innerHTML = suggestElements;
                this.setImage(suggestions.items[0]);
                return container;
            } else {
                this.setImage();
                return null;
            }
        },

        suggestionBoxHandler : function (e) {
            var e = (e)?e : window.event;
            var targ = e.target || e.srcElement;
            
            if(targ.className.indexOf("suggestElement") != -1 || targ.parentNode.className.indexOf("suggestElement") != -1) {
                var elem = (targ.className.indexOf("suggestElement") != -1) ? targ : targ.parentNode;
                this.copySelection(elem);
            }
            
            this.setVisible(false);
        },

        validateInput : function () {
            if(this.validate) {
                if(this.inputField.value=="") {
                    this.inputField.className = "";     
                    this.valid = true;
                } else  if(this.cachedSuggestions[this.inputField.value]  ) {
                    this.inputField.className = "valid";
                    this.valid = true;
                } else {
                    this.inputField.className = "invalid";
                    this.valid = false;
                }
                this.validationHandler();
            }
        },
        isValid : function () {
            return this.valid;          
        },
        setVisible : function (visible) {
            this.validateInput();
            this.suggestionsContainer.style.display = (visible) ? "block" : "none";
        },

        copySelection : function (element) {
            var str =  element.innerHTML.replace(/<b>|<\/b>/gi,"");
            this.inputField.value = VYRE.AutoSuggest.html_entity_decode(str);;
            this.validateInput();
            if(typeof this.inputField.onchange == "function") {
               this.inputField.onchange();
            }
            if(typeof this.copyHandler == "function") {
                this.copyHandler(element) ;
            }

        },

        changeSelected : function(direction) {
            var suggestElements = this.suggestionsBox.childNodes;
            if(suggestElements.length > 1 ) {
                suggestElements[this.selectedIndex].className = "suggestElement";
                if(direction == -1) {
                    this.selectedIndex = (this.selectedIndex > 0) ? this.selectedIndex -1 : suggestElements.length -1;
                } else if (direction == 1) {
                    this.selectedIndex = (this.selectedIndex == suggestElements.length -1) ? 0 : this.selectedIndex + 1;
                }
                suggestElements[this.selectedIndex].className = "suggestElement selected";
                if(typeof this.copyHandler != "function") {
                    this.copySelection(suggestElements[this.selectedIndex]);
                }
            }
            this.setImage(suggestElements[this.selectedIndex]);
        },
        
        mouseover : function (e) {
            if(this.mouseOutTimer ) {
                clearTimeout(this.mouseOutTimer);
            }
            var e = (e)?e : window.event;
            var targ = e.target || e.srcElement;
            if(targ.className.indexOf("suggestElement") != -1) {
                this.setImage(targ);
            }
            
        },
        mouseout : function (e) {
            var self = this;
            this.mouseOutTimer = setTimeout(function () {
                self.changeSelected(0);
            },100);
            
        },
        setImage : function (element) {
            if(this.imagePreview == true) {
                var src;
                if(typeof element != "undefined") {
                    src = this.imageSources[element.id];
                }
                if(src) {
                    this.imageBox.style.display="block";
                    this.previewImage.src = src;
                } else {
                    this.imageBox.style.display="none";
                    this.previewImage.src ="";
                }
            }
        },
        getLeft : function () {
            var elem;
            if(document.getElementById) {
                var elem = this.inputField
            } else if (document.all){
                var elem = document.all[this.inputField.id];
            }
            xPos = elem.offsetLeft;
            tempEl = elem.offsetParent;
            while (tempEl != null) {
                xPos += tempEl.offsetLeft;
                tempEl = tempEl.offsetParent;
            }
            return xPos;
                
        },
        getTop : function () {

            if(document.getElementById) {   
                var elem = this.inputField
            } else if (document.all) {
                var elem = document.all[this.inputField.id];
            }
            yPos = elem.offsetTop;
            tempEl = elem.offsetParent;
            while (tempEl != null) {
                yPos += tempEl.offsetTop;
                tempEl = tempEl.offsetParent;
            }
                return yPos;
        }
    };
    
    VYRE.AutoSuggestLinker = function (settings) {
        var self = this;
        this.autoSuggest = null;
        this.linkType="add";
        this.portletId = null;
        this.linkId = null;
        if( typeof settings != "undefined" ) {
            for( var property in this) {
                if(typeof settings[property] != "undefined") {
                    this[property] = settings[property];
                }
            }
        }
        this.autoSuggest.copyHandler = function (element) {
            self.linkItem(element.id); 
        };
        eval(VYRE.AutoSuggestLinker.templates.addItem.supplant({"portletId" : this.portletId}));
    };
   
    VYRE.AutoSuggestLinker.templates = function () {
        return {
            addItem : "this.addItemAction = addSelectedLink{portletId};",
            addItemTest :"this.addItemAction = function (linkId,itemId){alert(linkId+' {portletId} '+itemId);}"
        };
    }();
    
    VYRE.AutoSuggestLinker.prototype = {
        
        linkItem : function (itemId) {
           if(this.linkType=="replace") {
           	  document.getElementById("item_link_"+ this.linkId).value = "";
           }
           this.addItemAction(this.linkId, itemId);    
           this.autoSuggest.inputField.value ="";
        }
    };
