//suggest-field
//Requires SDLib.js

//IE, FF, and GC working up through 19-Nov

/**
 * Parameters that MUST be defined:
 *  textInputBox -> &lt;dom-input-element&gt; - the dom element (not the id, the actual element) of the input box being used
 *  dropDown -> &lt;dom-table-element&gt; - the table dom element (not the id, the actual element) to be used for the drop down
 *  varName -> &lt;string&gt; - the name of the variable reference to this object from the scope of the window
 *
 * Optional configuration parameters:
 *  closeButton -> &lt;boolean&gt; - have a 'close' button link like google suggest or not
 *  closeLinkText -> &lt;string&gt; - for I18N - what should the text of the 'close' link be?
 *  useMouseOut -> &lt;boolean&gt; - creates a behavior difference. Should it act on a mouse out event (google does NOT)
 *
 * Data population array:
 *  data -> &lt;String[]&gt; - not defined on set up (though it could be), but should be dynamically populated via ajax
 *
 * @param jsonObj - used to set various parameters upon object construction
 */
var SuggestBox = Class.create();
SuggestBox.prototype =
{
    initialize : function(jsonObj)
    {
        //must be overwritten
        this.textInputBox = null; //the dom element
        this.dropDown = null; //the dom element

        //functions for fecthing data, submitting form etc
        this.dataFetch = this.defaultDataFetch;
        this.submit = this.onSubmit;

        //options
        this.closeButton = true; //have a close button or not?
        this.closeLinkText = 'close'; //for internationalization purposes
        this.useMouseOut = false; //behavior difference when mouse out's of drop down
        this.resultCountColumn = false; //creates a second table column for the number of results

        //data source
        //this.data = Array("hello", "world", "really long word here dude!", "how", "are", "you!");
        //this.data = Array("hello", "world", "how", "are", "you!");

        // should rename these to more generic names - like 0: and 1: - maybe, or maybe not?
//        this.data = Array(  {suggestion: "hello", count: "5 results"},
//                            {suggestion: "world", count: "100000 results"},
//                            {suggestion: "how", count:"842 results"},
//                            {suggestion: "are", count:"57 results"},
//                            {suggestion: "you!", count:"9270 results"});
        //this.data = Array();

        //internal use
        this.closeTimeout = null;
        this.closeTimeoutTime = 300;
        this.currentlyClosed = false;
        this.origText = "";
        this.selectedRowIndex = null;

        for(var i in jsonObj)
        {
            if(typeof(this[i]) != "undefined")
            {
                this[i] = jsonObj[i];
            }
        }

        if(this.textInputBox == null || this.dropDown == null)
        {
            alert("Script Error!");
        }
        Event.observe(this.textInputBox, "keyup", this.handleTextInputEvent.bindAsEventListener(this));
        Event.observe(this.textInputBox, "keydown", this.handleTextInputEvent.bindAsEventListener(this));
        Event.observe(this.textInputBox, "blur", this.handleTextInputEvent.bindAsEventListener(this));
        Event.observe(this.textInputBox, "focus", this.handleTextInputEvent.bindAsEventListener(this));
    },

    onSubmit : function()
    {
        alert("overwrite this to submit your form!");
    },

    defaultDataFetch : function(callback)
    {
        alert("overwrite this to fetch your data!");
        this.data = Array(  {suggestion: "hello", count: "5 results"},
                        {suggestion: "world", count: "100000 results"},
                        {suggestion: "how", count:"842 results"},
                        {suggestion: "are", count:"57 results"},
                        {suggestion: "you!", count:"9270 results"});
        callback();
    },

    handleTextInputEvent : function(e)
    {
        var el = this.textInputBox;
        switch(e.type)
        {
            case "keydown":
                switch(e.keyCode)
                {
                    case 9: //tab
                    case 13: //enter
                    case 27: //esc
                        Event.stop(e);
                        return false;
                    default:
                        break;
                }
                break;
            case "keyup":
                switch(e.keyCode)
                {
                    case 9: //tab
                        this.origText = this.textInputBox.value;
                        this.hideDropdown();
                        if(document.getElementById('searchButton')!=null)
                        {
                            document.getElementById('searchButton').focus();
                        }
                        Event.stop(e);
                        break;
                    case 13: //enter
                        this.origText = this.textInputBox.value;
                        this.hideDropdown();
                        this.submit();
                        break;
                    case 27: //esc
                        this.textInputBox.value = this.origText;
                        this.hideDropdown();
                        break;
                    case 37: //left
                        break;
                    case 38: //up
                        //none selected, no text - do nothing!
                        //none selected, text
                        //one (not last) is selected
                        //last one is selected
                        if(this.selectedRowIndex == null && this.textInputBox.value != "")
                        {
                            //only wrap up if the drop down is already showing, else do nothing
                            if(!this.dropDown.className.toLowerCase().match('hidden'))
                            {
                                this.origText = this.textInputBox.value;
                                this.selectLastRow();
                            }
                        }
                        else if(this.selectedRowIndex != null)
                        {
                            this.selectPreviousRow();
                        }
                        break;
                    case 39: //right
                        break;
                    case 40: //down
                        if(this.selectedRowIndex == null && this.textInputBox.value != "")
                        {
                            if(this.dropDown.className.toLowerCase().match('hidden') && this.data.length > 0)
                            {
                                this.createDropDown();
                            }
                            this.origText = this.textInputBox.value;
                            this.selectFirstRow();
                        }
                        else if(this.selectedRowIndex != null)
                        {
                            this.selectNextRow();
                        }
                        break;
                    default:
                        this.dataFetch(this.handleKeyUpDefault.bind(this));
                        break;
                }
                break;
            case 'blur':
                this.textInputBox.className = 'suggestFieldBlur';
                this.closeTimeout = window.setTimeout(this.hideDropdown.bind(this), this.closeTimeoutTime);
                break;
            case 'focus':
                this.textInputBox.className = 'suggestFieldFocus';
                break;
            default:
                alert("el: " + el + ", - " + e.type + " event not supported");
                break;
        }
    },

    handleKeyUpDefault : function()
    {
        this.origText = this.textInputBox.value;
        if(this.textInputBox.value != ""
                && !this.currentlyClosed
                && this.data.length > 0)
        {
            this.createDropDown();
        }
        else if(this.textInputBox.value == "" )
        {
            this.hideDropdown();
            this.currentlyClosed = false;
        }
        else if(this.data.length == 0)
        {
            this.hideDropdown();
        }
    },

    handleDropDownEvent : function(e)
    {
        var el = Event.element(e);
        var rowind = el.getAttribute('rowind') * 1; //required to convert the string attribut into a number
        var selectedRow;
        switch(e.type)
        {
             case "click":
                window.clearTimeout(this.closeTimeout);
                this.selectedRowIndex = rowind;
                selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
                this.textInputBox.value = SDLib.getInnerText(selectedRow.childNodes[0]); //requires SDLib
                this.origText = this.textInputBox.value;
                this.hideDropdown();
                this.submit();
                break;
            case "mouseover":
                if(this.selectedRowIndex != null)
                {
                    selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
                    selectedRow.className = 'ddRowNotSelected';
                }
                this.selectedRowIndex = rowind;
                selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
                selectedRow.className =  'ddRowSelected';
                break;
            case "mouseout":
                //only used if useMouseOut is set to true
                if(this.selectedRowIndex != null)
                {
                    selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
                    selectedRow.className = 'ddRowNotSelected';
                    this.selectedRowIndex = null;
                }
                break;
            default:
                alert("el: " + el + ", - " + e.type + " event not supported");
                break;
        }
    },

    handleCloseEvent : function()
    {
        window.clearTimeout(this.closeTimeout);
        if(this.closeButton)
        {
            // this.currentlyClosed = true; // causing dropdown to not reappear.
            this.textInputBox.value = this.origText;
            this.hideDropdown();
            var len = this.textInputBox.value.length;
            if(this.textInputBox.createTextRange) //for ie
            {
                var range = this.textInputBox.createTextRange();
                range.move("character", len);
                range.select();
            }
            else if(this.textInputBox.selectionStart) //for gecko browsers
            {
                this.textInputBox.focus();
                this.textInputBox.setSelectionRange(len, len);
            }
        }
    },

    selectPreviousRow : function() //this should be treated as private
    {
        var selectedRow;
        if((this.selectedRowIndex - 1) >= 0)
        {
            //unselect this and...
            selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
            selectedRow.className =  'ddRowNotSelected';
            // select previous on ui
            this.selectedRowIndex--;
            selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
            this.textInputBox.value = SDLib.getInnerText(selectedRow.childNodes[0]); //requires SDLib
            selectedRow.className =  'ddRowSelected';
        }
        else if((this.selectedRowIndex - 1) < 0)
        {
            this.textInputBox.value = this.origText;
            selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
            selectedRow.className = 'ddRowNotSelected';
            this.selectedRowIndex = null;
        }
    },

    selectLastRow : function() //this should be treated as private
    {
        this.selectedRowIndex = this.dropDown.childNodes.length - 1;
        if(this.closeButton)
        {
            this.selectedRowIndex--;
        }
        var selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
        selectedRow.className = 'ddRowSelected';
        this.textInputBox.value = SDLib.getInnerText(selectedRow.childNodes[0]); //requires SDLib
    },

    selectNextRow : function() //this should be treated as private
    {
        var selectedRow;
        var lengthToCheck = this.dropDown.childNodes.length;
        if(this.closeButton)
        {
            lengthToCheck--;
        }
        if((this.selectedRowIndex + 1) < lengthToCheck)
        {
            //unselect previous and...
            selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
            selectedRow.className = 'ddRowNotSelected';
            // select next on ui
            this.selectedRowIndex++;
            selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
            this.textInputBox.value = SDLib.getInnerText(selectedRow.childNodes[0]); //requires SDLib
            selectedRow.className = 'ddRowSelected';
        }
        else if((this.selectedRowIndex + 1) >= lengthToCheck)
        {
            this.textInputBox.value = this.origText;
            selectedRow = this.dropDown.childNodes[this.selectedRowIndex];
            selectedRow.className = 'ddRowNotSelected';
            this.selectedRowIndex = null;
        }
    },

    selectFirstRow : function() //this should be treated as private
    {
        this.selectedRowIndex = 0;
        var selectedRow = this.dropDown.childNodes[0];
        selectedRow.className =  'ddRowSelected';
        this.textInputBox.value = SDLib.getInnerText(selectedRow.childNodes[0]); //requires SDLib
    },

    hideDropdown : function() //this should be treated as private
    {
        this.selectedRowIndex = null;
				if (ieVersion != -1 ) {
					$('searchBox').style.height = "auto";
				}
				
				if (ieVersion == 6) {
					$('optionPicker').style.display = 'block';
				}
				
				this.dropDown.className =  'dropDownHidden';
    },

    createDropDown : function() //this should be treated as private
    {
			
			  //delete any children if existing
        var children = this.dropDown.getElementsByTagName("div");
        for(var childIndex =0; childIndex < children.length; i++)
        {
            this.dropDown.removeChild(children[childIndex]);
        }

        var row;
        var cell;
        for(var i2 = 0; i2 < this.data.length; i2++)
        {
            row = document.createElement('div');
            row.className =  'ddRowNotSelected';
            cell = document.createElement('div');
            cell.className =  'ddCell';
            cell.setAttribute('rowind', i2);
            if(this.resultCountColumn)
            {
                cell.appendChild(document.createTextNode(this.data[i2].suggestion));
                row.appendChild(cell);
                cell = document.createElement('div');
                cell.className = 'ddCellCount';
                cell.setAttribute('rowind', i2);
                cell.appendChild(document.createTextNode(this.data[i2].count));
            }
            else
            {
                cell.appendChild(document.createTextNode(this.data[i2]));
            }
            row.appendChild(cell);
            Event.observe(row, "mouseover", this.handleDropDownEvent.bindAsEventListener(this));
            if(this.useMouseOut)
            {
                Event.observe(row, "mouseout", this.handleDropDownEvent.bindAsEventListener(this));
            }
            Event.observe(row, "click", this.handleDropDownEvent.bindAsEventListener(this));
            row.setAttribute('rowind', i2);
            this.dropDown.appendChild(row);
        }
        if(this.closeButton)
        {
            row = document.createElement('div');
            row.className = 'ddRowClose';
            cell = document.createElement('div');
            cell.className = 'ddCellClose';
            var closeSpan = document.createElement('span');
            Event.observe(closeSpan, "click", this.handleCloseEvent.bindAsEventListener(this));
            closeSpan.className = 'ddCloseSpan';
            closeSpan.appendChild(document.createTextNode(this.closeLinkText));
            cell.appendChild(closeSpan);
            row.appendChild(cell);
            var parent = $('q');
            while(parent.className.indexOf('column')==-1)
            {
                parent = parent.parentNode;
            }
            this.dropDown.appendChild(row);
        }
				this.dropDown.className = 'dropDown';
				this.dropDown.style.width = $('q').offsetWidth-2+"px";
				
				if (ieVersion == -1) {
					this.dropDown.style.left = $('q').offsetLeft+"px";
					this.dropDown.style.margin= "0px 0px 0px 0px !important";
                }
				
				if (ieVersion == 8) {
					$('searchBox').style.height = this.dropDown.offsetHeight+"px";
					this.dropDown.style.left = $('q').offsetLeft+14+"px";
				}
				
				if (ieVersion == 7) {
					this.dropDown.style.left = $('q').offsetLeft+14+"px";
					$('searchBox').style.height = this.dropDown.offsetHeight+$('q').offsetHeight+"px";
                }
				
				if (ieVersion == 6) {
					$('searchBox').style.height = this.dropDown.offsetHeight+$('q').offsetHeight+"px";
					this.dropDown.style.top = $('q').offsetHeight+21+"px";
					this.dropDown.style.left = $('q').offsetLeft+10+"px";
                    $('optionPicker').style.display = 'none'; // ie6 cannot display form elements on top of divs.
				}
    }
}


