/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */

function liveDropdown ()
{
    this.results;    // var to hold results from live request
    this.maxResults; // max num of results to appear in dropdown
    
    this.numResults     = 0; // total number of results returned
    this.selectedResult = 0; // which result is currently selected
    this.firstResult    = 0; // which result is first to be displayed in our dropdown
    
    this.searchItemID   = 'livedropdownSearch';       // ID of item where search string is displayed
    this.searchResultID = 'livedropdownSearchResult'; // ID of item where value of selected item will be stored
    this.resultsDivID   = 'livedropdownResults';      // ID of div where results will be displayed
    this.resultsCellID  = 'livedropdownSearchItem';   // ID of table cell
    this.resultSelecvted= 'livedropdownSelected';    // ID of item where we put the selected value
    
    this.liveRequestObjectsId;
    this.elementsToHide = new Array();
    this.changeEvents = new Array();

    /**
    * Get results back as array and display them
    */
    this.handleResults = function (res)
    {
    	this.results    = res;
        this.numResults = this.results.length;

        this.selectedResult = 0;
        this.firstResult    = 0;

        this.displayResults();
    }
    
    /**
    * Display results
    */
    this.displayResults = function ()
    {
        var resultsDiv = document.getElementById(this.resultsDivID);
		
        var result;
        var resultCell;
        var resultID;
		
        var lastResult = this.maxResults - 1;
		
        // do nothing if no results
        if (this.numResults == 0) { return; }
		
        // hide then unhide div to refresh viewport
        changeClass(resultsDiv, 'liveDropdownHidden');
        changeClass(resultsDiv, 'liveDropdownShow');
        
        this.applyVisibilityToElements('hidden');
		
        for (var i = 0; i < this.maxResults; i++)
        {
            resultID   = i+this.firstResult;
            resultCell = document.getElementById(this.resultsCellID+i);
			
            // hide cell if no result to display
            if (!this.results[resultID]) 
            {
                changeClass(resultCell, 'hidden');
                continue;
				
				// do we need to show more option
            } 
            else if (i == lastResult && this.numResults > this.maxResults && resultID != (this.numResults-1) )
            {
                resultCell.innerHTML = '...';
                changeClass(resultCell, 'normal');
                continue;
				
            // do we need to show less option
            }
            else if (i == 0 && this.firstResult > 0) 
            {
                resultCell.innerHTML = '...';
                changeClass(resultCell, 'normal');
                continue;
				
            // display result
            }
            else
            {
                result = this.results[resultID];
                display_text = result.value;
                if (result.info != null) display_text+= result.info;
                resultCell.innerHTML = display_text;
            }
			
            // set css class for result cell
            if (i == this.selectedResult) 
            {
                changeClass(resultCell, 'selected');
            } 
            else 
            {
                changeClass(resultCell, 'normal');
            }
        }
    }
    
    /**
    * Results navigation and selection
    */
    this.resultsNav = function (evt)
    {
        var key = (evt.which || evt.charCode || evt.keyCode);
        var scrollThreshold = Math.floor(this.maxResults / 2);
        var resultsLeft;

        // scroll down
        if (key == 40)
        {
            resultsLeft = (this.numResults - this.firstResult) - this.maxResults;
    
            // no more results to display so can ignore scroll threshold
            if (resultsLeft == 0 && this.selectedResult < (this.maxResults-1))
            {
                this.selectedResult++;
            // move highlight if have results left and below scroll threshold
            } 
            else if (resultsLeft > 0 && this.selectedResult < scrollThreshold)
            {
                this.selectedResult++;
            // less than max num results returned and not on last item
            } 
            else if (this.numResults <= this.maxResults && this.selectedResult != this.numResults - 1) 
            {
                this.selectedResult++;
    
            // otherwise move results
            } 
            else if (resultsLeft > 0) 
            {
                this.firstResult++;
            }
        // scroll up
        } 
        else if (key == 38) 
        {
            // above threshold on last set of results
            if (this.selectedResult > scrollThreshold) 
            {
                this.selectedResult--;
    
            // first set of results and selected isn't first item
            } 
            else if (this.firstResult == 0 && this.selectedResult != 0)
            {
                this.selectedResult--;
    
            // otherwise move results
            } 
            else if (this.firstResult > 0) 
            {
                this.firstResult--;
            }
    
         // home
        }
        else if (key == 36) 
        {
            this.firstResult = 0;
            this.selectedResult=0;

        // end
        }
        else if (key == 35) 
        {
            this.firstResult = (this.numResults > this.maxResults) ? (this.numResults - this.maxResults): 0;
            this.selectedResult=(this.maxResults - 1);
        // select
        }
        else if (key == 13)
        {
            obj = document.getElementById(this.searchItemID);
            obj.value = this.results[this.firstResult + this.selectedResult].value;
            
            obj = document.getElementById(this.searchResultID);
            obj.value = this.results[this.firstResult + this.selectedResult].id;
            
            obj = document.getElementById(this.resultSelected);
            obj.value = this.results[this.firstResult + this.selectedResult].value;
            
            changeClass(document.getElementById(this.resultsDivID), 'liveDropdownHidden');
            // abort any subsequent request
            liveRequestObjects[this.liveRequestObjectsId].abortRequest();
            
            this.applyChangeEvents();
            this.hideResults();
			
            return;
            
        // escape
        }
        else if (key == 27)
        {
            this.hideResults();
            // abort any subsequent request
            liveRequestObjects[this.liveRequestObjectsId].abortRequest();
            return;
        }

        this.displayResults();
    }
    
    this.handleMouse = function (selected, action)
    {
        this.selectedResult = selected;

        if (action == 'click')
        {
            obj = document.getElementById(this.searchItemID);
            obj.value = this.results[this.firstResult + this.selectedResult].value;
			
            obj = document.getElementById(this.searchResultID);
            obj.value = this.results[this.firstResult + this.selectedResult].id;
			
            obj = document.getElementById(this.resultSelected);
            obj.value = this.results[this.firstResult + this.selectedResult].value;
			
            changeClass(document.getElementById(this.resultsDivID), 'liveDropdownHidden');
            
            // abort any subsequent request
            liveRequestObjects[this.liveRequestObjectsId].abortRequest();
            
            this.applyChangeEvents();
            this.hideResults();
			
            return;
        }
        else
        {
            this.displayResults();
        }
    }
    
    /**
     * Hide results
     */
    this.hideResults = function ()
    {
        this.applyVisibilityToElements('visible');
        window.setTimeout("changeClass(document.getElementById('"+this.resultsDivID+"'), 'liveDropdownHidden');",100);
    }
    
    /**
    * Hides objects (usually <selects>s) when menu is displayed
    */
    this.AddElementToHide = function (obj)
    {
        this.elementsToHide[this.elementsToHide.length] = obj;
    }
    
    this.applyVisibilityToElements = function (vis)
    {
        for(var i=0; i < this.elementsToHide.length; i++)
        {
            eval('document.getElementById("'+this.elementsToHide[i]+'").style.visibility = vis;');
        }
    }
    
    /**
    * Upon selection, will eval these strings
    */
    this.AddChangeEvent = function (str)
    {
        this.changeEvents[this.changeEvents.length] = str;
    }
    
    this.applyChangeEvents = function ()
    {
        for(var i=0; i < this.changeEvents.length; i++)
        {
            eval(this.changeEvents[i]);
        }
    }
}
