function org_umasstransit_autocomplete()
{
    var TIMER_SPEED = 10 ; // 10 milliseconds
    var FORM_SUBMISSION_CANCEL_TIMEOUT = 500 ; // half-second before reset
    var KEY_UP = 38 ;
    var KEY_DOWN = 40 ;
    var KEY_TAB = 9 ;
    var KEY_ENTER = 13 ;
    var KEY_BACKSPACE = 8 ;
    var KEY_DELETE = 46 ;

    var opera = (window.opera ? true : false) ;
    var safari = (navigator.userAgent.toLowerCase().indexOf("safari") != -1) ;
    var mozilla = (navigator.userAgent.toLowerCase().indexOf("mozilla/5") != -1 && !opera && !safari) ;         

    var input = null ;
    var form = null ;
    var dropdown = null ;
    var list = null ;
    
    var data = new Array() ;
    var timerHandle = null ;
    var previousText = null ;
    var deleteFlag = false ;
    var cancelSubmit = false ;
    
    var selectedIndex = -1 ;
        

    /*  
     *  script entry point (document.onload)
     */
    function main()
    {
        window.onTimer = onTimer ;
        input = getInputField() ;
        //form = getParentForm() ;
		form = document.searchform;

        if(input)
        {
            input.setAttribute("autocomplete","off") ;
            inputData() ;
            installHandlers() ;
            createDropdown() ;
            document.body.appendChild(dropdown) ;
            positionDropdown() ;
        }        
    }


    /*
     *  find input field
     */
    function getInputField()
    {
        var input = document.getElementById("search") ;
        return input ;
    }


    /*
     *  find input field's parent <form>
     */
    function getParentForm()
    {
        var parent = input.parentNode ;
        while(parent)
        {
            if(parent.tagName.toLowerCase() == "form")
            {
                return parent ;
            }
            
            parent = parent.parentNode ;
        }

        return null ;
    }


    /*
     *  retrieve search-data from source
     */
    function inputData()
    {
        var data = document.getElementById("data") ;
        if(data)
        {
            for(var i=0;i<data.childNodes.length;i++)
            {
                addItem(data.childNodes[i].innerHTML) ;
            }
        }
    }


    /*
     *  install event handlers for input field
     */
    function installHandlers()
    {
        installEventHandler(input,"keydown",onKeyDown) ;
        installEventHandler(input,"keypress",onKeyPress) ;
        installEventHandler(window,"resize",positionDropdown) ;
        installEventHandler(input,"blur",onBlur) ;
        installEventHandler(window,"blur",onBlur) ;
        setTimeout("onTimer()",TIMER_SPEED) ;

        // form submission override
        if(form)
        {
            var oldHandler = form.onsubmit ;
            if(form.onsubmit)
            {
                form.onsubmit = function() 
                {
                    return (onSubmit() && oldHandler()) ;
                } ;
            }
            else
            {
                form.onsubmit = onSubmit ;
            }
        }
    }


    /*
     *  create dropdown element
     */
    function createDropdown()
    {
        // inner <UL>
        list = document.createElement("ul") ;
        list.id = "autocomplete-list" ;
        
        // container <DIV>
        dropdown = document.createElement("div") ;
        dropdown.id = "autocomplete-dropdown" ;
        dropdown.className = "autocomplete" ;
        dropdown.appendChild(list) ;
        setListVisibility(false) ;
    }


    /*
     *  clear selection list
     */
    function clearList()
    {
        selectedIndex = -1 ;
        while(list.childNodes.length > 0)
        {
            list.removeChild(list.childNodes[0]) ;
        }
    }


    /*
     *  add items to selection list
     */
    function populateList(items)
    {
        var listItem ;
    
        for(var i=0;i<items.length;i++)
        {
            listItem = document.createElement("li") ;
            listItem.itemIndex = i ;
            listItem.innerHTML = items[i] ;
            listItem.onmouseover = onMouseOver ;
            listItem.onmouseout = onMouseOut ;
            listItem.onmousedown = onMouseDown ;
            list.appendChild(listItem) ;
        }
    }


    /*
     *  set the visibility of dropdown list 
     */
    function setListVisibility(visibility)
    {
        dropdown.style.visibility = visibility ? "visible" : "hidden" ;
    }   


    /*
     *  highlight the next list item
     */
    function moveHighlightDown()
    {
        if(list.childNodes.length > 0)
        {
            selectedIndex = Math.min(list.childNodes.length-1,selectedIndex+1) ;
            updateHighlight() ;
        }
    }


    /*
     *  highlight the previous list item
     */
    function moveHighlightUp()
    {
        if(list.childNodes.length > 0)
        {
            selectedIndex = Math.max(0,selectedIndex-1) ;
            updateHighlight() ;
        }
    }


    /*
     *  update highlighted items
     */
    function updateHighlight()
    {
        for(var i=0;i<list.childNodes.length;i++)
        {
            list.childNodes[i].className = "" ;
        }

        if(selectedIndex >= 0)
        {
            list.childNodes[selectedIndex].className = "highlight" ;
        }
    }


    /*
     *  add an element to the searchable collection (sorted)
     */
    function addItem(item)
    {
        if(typeof item == "string" && item.length > 0)
        {
            var letter = item.substring(0,1).toLowerCase() ;
            if(typeof data[letter] == typeof undefined)
            {
                data[letter] = new Array() ;
            }
            
            data[letter][data[letter].length] = item ;
            data[letter].sort() ;
        }
    }


    /*
     *  search for autocomplete results
     */
    function autocomplete(text) 
    {
        if(typeof text != "string" || text.length <= 0)
        {
            return ;
        }

        var results = new Array() ;
        var letter = text.substring(0,1).toLowerCase() ;
        if(typeof data[letter] != typeof undefined)
        {
            for(var i=0;i<data[letter].length;i++)
            {
                if(data[letter][i].toLowerCase().indexOf(text.toLowerCase()) == 0)
                {
                    results[results.length] = data[letter][i] ;
                }
            }
        }

        return (results.length > 0 ? results : null) ;
    }


    /*
     *  fix the position of the dropdown 
     */
    function positionDropdown()
    {
        dropdown.style.left = left(input) + "px" ;
        dropdown.style.top = (top(input) + height(input) - 1) + "px" ;
        dropdown.style.width = width(input) + "px" ;
    }


    /*
     *  set the selection range of the input field
     */
    function setSelection(beginning,end) 
    {      
        if(input.setSelectionRange)
        {
            //input.focus() ;
            input.setSelectionRange(beginning,end) ;
        }
        else if(input.createTextRange)
        {
            var range = input.createTextRange() ;
            range.collapse(true) ;
            range.moveEnd("character",end) ;
            range.moveStart("character",beginning) ;
            range.select() ;
        }
    }


    /*
     *  select the currently highlighted list item
     */
    function selectHighlightedItem()
    {
        if(selectedIndex > -1 && list.childNodes.length >= (selectedIndex + 1))
        {
            input.value = list.childNodes[selectedIndex].innerHTML ;
            previousText = input.value ;
            setListVisibility(false) ;
            clearList() ;
            input.blur() ;
            input.focus() ;
            input.select() ;
        }
    }


    /*
     *  cancel a DOM event
     */
    function cancel(event)
    {
        if(event.preventDefault)
        {
            event.preventDefault() ;
        }

        if(event.stopPropagation)
        {
            event.stopPropagation() ;
        }
        
        event.returnValue = false ;
        return false ;
    }


    /*
     *  end the override of form submissions
     */
    window.cancelSubmissionTimeout = function()
    {
        cancelSubmit = false ;
    } ;


    /*
     *  onTimer event
     */
    function onTimer()
    {
        // was delete/backspace the last key pressed?
        if(deleteFlag)
        {
            deleteFlag = false ;
            previousText = input.value ;

            var results = autocomplete(input.value) ;
            clearList() ;
            if(results)
            {                
                populateList(results) ;
                setListVisibility(true) ;
            }
            else
            {
                setListVisibility(false) ;
            }
        }
        
        // check for updated (typed) text
        if(input.value != previousText && input.value.length > 0)
        {
            var saved = input.value ;
            var results = autocomplete(saved) ;
            clearList() ;
            if(results)
            {
                // set selection of text
                if(input.setSelectionRange || input.createTextRange)
                {
                    input.value = results[0] ;
                    setSelection(saved.length,results[0].length) ;
                }                

                // fill dropdown list
                populateList(results) ;
                setListVisibility(true) ;
            }
            else
            {
                setListVisibility(false) ;
            }
        }

        previousText = input.value ;
        timerHandle = setTimeout("onTimer();",TIMER_SPEED) ;        
    }


    /*
     *  onKeyDown event (input field)
     */
    function onKeyDown(event)
    {       
        // reposition dropdown (in case layout has been changed)
        positionDropdown() ;
    
        // check for <enter>
        if(event.keyCode == KEY_ENTER && selectedIndex != -1)
        {
            cancelSubmit = true ;
            setTimeout("cancelSubmissionTimeout();",FORM_SUBMISSION_CANCEL_TIMEOUT) ;
        }
    
        // cancellation has no effect in mozilla
        // mozilla cancels under "onKeyPress"
        if(event.keyCode == KEY_UP && list.childNodes.length > 0)
        {
            moveHighlightUp() ;
            return cancel(event) ;
        }
        else if(event.keyCode == KEY_DOWN && list.childNodes.length > 0)
        {
            moveHighlightDown() ;
            return cancel(event) ;
        }
        else if(event.keyCode == KEY_ENTER && selectedIndex != -1)
        {            
            selectHighlightedItem() ;
            return cancel(event) ;
        }
        else if(event.keyCode == KEY_TAB  && selectedIndex != -1 && !mozilla && !opera)
        {
            selectHighlightedItem() ;
            return cancel(event) ;
        }
        
        // check for <DEL> or <BKSPC>
        if(event.keyCode == KEY_DELETE || event.keyCode == KEY_BACKSPACE)
        {
            deleteFlag = true ;
        }
    }


    /*
     *  onKeyPress event (input field)
     */
    function onKeyPress(event)
    {             
        deleteFlag = false ;

        // mozilla-specific cancellations        
        switch(event.keyCode)
        {
            case KEY_UP:
            case KEY_DOWN:

                if(list.childNodes.length > 0)
                {
                    return cancel(event) ;
                }

                break ;
                    
            case KEY_TAB:
                
                if(selectedIndex != -1 && (mozilla || opera))
                {
                    selectHighlightedItem() ;
                    return cancel(event) ;
                }

                break ;

            case KEY_BACKSPACE:
            case KEY_DELETE:
                              
                deleteFlag = true ;
                break ;
        }        
    }


    /*
     *  onMouseOver event (list item)
     */
    function onMouseOver(event)
    {
        selectedIndex = this.itemIndex ;
        updateHighlight() ;
    }


    /*
     *  onMouseOut event (list item)
     */
    function onMouseOut(event)
    {
        if(selectedIndex == this.itemIndex)
        {
            selectedIndex = -1 ;
        }

        updateHighlight() ;
    }


    /*
     *  onMouseDown event (list item)
     */
    function onMouseDown(event)
    {
        selectHighlightedItem() ;
    }


    /*
     *  focus-lost event (window and input field)
     */
    function onBlur(event)
    {
        previousText = input.value ;
        clearList() ;
        setListVisibility(false) ;
    }


    /*
     *  form submission sentinel     
     */
    function onSubmit()
    {
        if(cancelSubmit)
        {
            cancelSubmit = false ;
            return false ;
        }
        else
        {
            return true ;
        }
    }
    

    /*
     *  get the width of an element
     */
    function width(element)
    {
        return element.offsetWidth ;
    }


    /*
     *  get the height of an element
     */
    function height(element)
    {
        return element.offsetHeight ;
    }


    /*
     *  get the X-coordinate of an element
     */
    function left(element)
    {
        var left = 0 ;
        while(element)
        {
            left += element.offsetLeft ;
            element = element.offsetParent ;
        }

        return left ;
    }


    /*
     *  get the Y-coordinate of an element
     */
    function top(element)
    {
        var top = 0 ;
        while(element)
        {
            top += element.offsetTop ;
            element = element.offsetParent ;
        }

        return top ;
    }


    /*  
     *  install an event handler
     */
    function installEventHandler(element,event,handler)
    {
        if(element.addEventListener)
            element.addEventListener(event,handler,false) ;
        else if(element.attachEvent)
            element.attachEvent("on"+event,handler) ;
    }

    
    // install window.onload handler
    //installEventHandler(window,"load",main) ;
	main();
}
//if(document.createElement && document.getElementsByTagName)
//    org_umasstransit_autocomplete();

