var STATION_CODE = 0;
var STATION_NAME = 1;
var STATION_ALIAS = 2;
var LIST_MAX_SIZE = 25;

var listItemTemplate = new Template('<li id="#{id}"><div>#{stationAndCodeAndAlias}</div></li>');
var stationTemplate = new Template('#{station}#{stationCode}#{alias}');
var formListenerAttached = false;
var canSubmitForm = true;

var cachedStations;
function loadStation(stations){
	cachedStations = stations;
}

function RegisterElementForAutoSuggest(inputElement, doNotOverrideSubmit) {
	RegisterElementForAutoSuggestWithList(inputElement, doNotOverrideSubmit, cachedStations);
}

function RegisterElementForAutoSuggestWithList(inputElement, doNotOverrideSubmit, listOfStations) {
   	var curPos;
	var htmlCreator = new StationListHtmlCreator();
	var resultsElement = initResultsElement();
	initAutoCompleteAttribute(inputElement);
	Event.observe(inputElement,'keydown', handleKeydown);
	doNotOverrideSubmit || attachFormListener(inputElement,resultsElement);
	
    delayedInput({
        elem: inputElement,
		results: resultsElement.down('ul'),
        chars: 1,
		time: 200,
        open: function(value){
		    if(!inputElement.isAutoCompleteOn()) {
				return
			}
            if ( value && value.strip() != '' && listOfStations) {
                curPos = null;
                this.results.innerHTML = htmlCreator.createListHtml(listOfStations, inputElement.value.strip());
                var li = this.results.select( 'li' );
                
                
                if ( li.length == 0 ) {
                    hide(resultsElement);
					return;
				}
				
				for ( var i = 0; i < li.length; i++ ) {
					var ele = li[i];
					ele.observe('mouseover', function(){
                        updatePos( this, resultsElement );
                    });
                    ele.observe('click', function(){
                        updateInputField( this, inputElement,resultsElement );
                        inputElement.focus();
						inputElement.turnOffAutoComplete();
						canSubmitForm = true;
                    });
				
					(li%2 == 1) && addClass( li[i], 'odd' );
				}  
				updatePos( li[0],resultsElement );
				show(resultsElement);
            }
        },
        
        close: function(){
            hide(resultsElement);
            resetPos();
        }
    }, listOfStations);
	
	function initResultsElement() {
		var results = new Element('div', {'class':'results' }).hide();
		var suggestDiv = new Element('div' , { 'class':'suggest' });
		results.insert(suggestDiv);
		results.insert(new Element('ul'));
		inputElement.insert({'after': results});
		makeWindowed(suggestDiv); // ie6 bug fix
		return results;
	}

	function initAutoCompleteAttribute(ele) {
		Object.extend(ele,{
			isAutoCompleteOn: function(){
					return this.getAttribute('autocomplete') == 'on';
				},
			turnOnAutoComplete: function(){
					this.hasAttribute('autocomplete') && this.setAttribute('autocomplete','on');
				},
			turnOffAutoComplete: function(){
					this.hasAttribute('autocomplete') && this.setAttribute('autocomplete','off');
				},
			turnOffAutoCompleteIfAttributeNotPresent: function(){
				this.hasAttribute('autocomplete') || this.setAttribute('autocomplete','off');
			}
		});
		inputElement.turnOffAutoCompleteIfAttributeNotPresent();
	}
	
    function handleKeydown(e){
        if ((e.keyCode == Event.KEY_UP  || e.keyCode == Event.KEY_DOWN || e.keyCode == Event.KEY_TAB) && !inputElement.isAutoCompleteOn())
            return true;
	    inputElement.turnOnAutoComplete();		
        if ( e.keyCode == Event.KEY_TAB || e.keyCode == Event.KEY_RETURN ) {
			var stopEvent = (e.keyCode == Event.KEY_TAB) && resultsElement.visible();
			canSubmitForm = !(e.keyCode == Event.KEY_RETURN && resultsElement.visible());
            updateInputField(curPos, inputElement, resultsElement);
	        inputElement.turnOffAutoComplete();		
            (stopEvent | !canSubmitForm) && e.stop();
            return false;
        }

        if ( e.keyCode == Event.KEY_ESC ) {
	        inputElement.turnOffAutoComplete();		
            e.stop();
            hide(resultsElement);
            resetPos();
			canSubmitForm = true;
            return false;
        }
		
        var li = $A(resultsElement.getElementsByTagName('li'));
        if ( e.keyCode == Event.KEY_UP )
            return updatePos( curPos.previousSibling || li.last(), resultsElement);
        if ( e.keyCode == Event.KEY_DOWN )
            return updatePos( curPos.nextSibling || li.first() , resultsElement);
    }
	
	function delayedInput(opt, listOfStations) {
		var old = opt.elem.value;
		var listInFocus = false;
		setInterval(function(){
			if (!listOfStations) {return;}
			var newValue = opt.elem.value;
			var len = newValue.length;
			if ( old != newValue ) {
			  if ( len < opt.chars ) {
				opt.close();
			  } else if ( len >= opt.chars && len > 0 ) {
				opt.open( newValue );
			  }
			  old = newValue;
			}
		}, opt.time );
	  
		opt.elem.observe ('keyup', function(){
			if ( this.value.length == 0 ) {
				opt.close();
			}
		});
		
		opt.results.observe ('mouseover', function(){
			listInFocus = true;
		});
		
		opt.results.observe ('mouseout', function(){
			listInFocus = false;
		});

		opt.elem.observe ('blur', function() {
			if (!listInFocus){ 
				opt.close();
			}
		});
	}
	
    function updatePos( elem, resultsParent) {
        curPos = elem;
        var ele = resultsParent.down('li.cur');
        removeClass( ele, 'cur' );
        addClass( curPos, 'cur' );
        return false;
    }

    function resetPos() {
        curPos = null;
    }

    function updateInputField( elem , inputElement, resultsParent ) {
        if(elem){
			inputElement.value = elem.id;
		}
        hide( resultsParent );
    }
	
	function addClass(elem,c) {
	  Element.addClassName(elem,c);
	}
	function removeClass(elem,c) {
	  Element.removeClassName(elem,c);  
	}
	function hide(elem) {
		elem.setStyle({display:'none'});
	}
	function show(elem) {
		elem.setStyle({display:'block'});
	}
	
	function attachFormListener(ele,result) {
		if (!formListenerAttached) {
			formListenerAttached = true;
			var oldAction = ele.form.onsubmit;
			ele.form.onsubmit= function() {
				if (!canSubmitForm) {
					canSubmitForm = true;
					return false;
				}
				oldAction && eval(oldAction);
			};
		}
	}
};

var StationListHtmlCreator = function() {

	var escapeRegex = createEscapeRegex();

	this.createListHtml = function (list, searchCriteria) {
		list = list.clone();
		var filteredListArr = createFileteredList(list, searchCriteria);
		var listHtml='';
		
		filteredListArr.each(function(listObj){
			listObj.each(function(listEle) {
				listHtml += listEle;
			});
		});
		return listHtml;
	};
	
	function createFileteredList(list, searchCriteria) {
		var escSearchCriteria = escape(searchCriteria);
		var regexArr = [{regex:new RegExp('^('+escSearchCriteria+')$', 'i'),part:STATION_CODE},
						{regex:new RegExp('^('+escSearchCriteria+')', 'i'),part:STATION_NAME},
						{regex:new RegExp('^('+escSearchCriteria+')', 'i'),part:STATION_ALIAS},
						{regex:new RegExp('^('+escSearchCriteria+')', 'i'),part:STATION_CODE},
						{regex:new RegExp(' ('+escSearchCriteria+')', 'i'),part:STATION_NAME},
						{regex:new RegExp(' ('+escSearchCriteria+')', 'i'),part:STATION_ALIAS}];
		var filteredListArr = [];
		var count = 0;
		
		regexArr.each(function(regexPartPair){
			var filteredList = filterList(list, regexPartPair, count);
			filteredListArr[filteredListArr.length] = filteredList;
			count+=filteredList.length;
		});  
		return filteredListArr;
	}
	
	function filterList(list, regexPartPair, count) { 
		var filteredList = [];
		for (var i=0;count<LIST_MAX_SIZE && i<list.length;i++) {
			var stationCodePair = list[i];
			if (regexPartPair.regex.test(stationCodePair[regexPartPair.part])) {
				var stationAndCodeStr = highlightStation(stationCodePair, regexPartPair);
				filteredList[filteredList.length] = listItemTemplate.evaluate({id:stationCodePair[STATION_NAME], 
																			   stationAndCodeAndAlias:stationAndCodeStr});
				list[i] = ['',''];
				count++;
			}
		}
		return filteredList;
	}

	function highlightStation(station, regexPartPair) {
		var codeStr = regexPartPair.part == STATION_CODE ? highlight(station[STATION_CODE], regexPartPair.regex) : station[STATION_CODE];
		var stationStr = regexPartPair.part == STATION_NAME ? highlight(station[STATION_NAME], regexPartPair.regex) : station[STATION_NAME];
		var alias = regexPartPair.part == STATION_ALIAS ? highlight(station[STATION_ALIAS], regexPartPair.regex) : station[STATION_ALIAS];
		
		return stationTemplate.evaluate({station:stationStr, 
													stationCode: displayForStationCode(station[STATION_CODE], codeStr), 
													alias: displayForAlias(alias)});
	}

	function highlight(stationStr, regex) {
		var matches = stationStr.match(regex);
		return matches?stationStr.replace(matches[0],'<span class="highlight_station">'+matches[0]+'</span>'):stationStr;
	}

	function displayForStationCode(stationCode, stationCodeStr) {
		return stationCode == '' ?'':' ('+stationCodeStr+')';
	}

	function displayForAlias(alias) {
		return alias && ' (' + alias + ')';
	}
	
	function createEscapeRegex(text) {
		var specialChars = [
		  '/', '.', '*', '+', '?', '|',
		  '(', ')', '[', ']', '{', '}', '\\'
		];
		return new RegExp('(\\' + specialChars.join('|\\') + ')', 'g');
	}

	function escape(text) {
		return text.replace(escapeRegex , '\\$1');
	}
};

function suffix_id_for_tag(tag,idSuffix) {
    regexp = new RegExp(".*" + idSuffix + "$");
    return $$(tag).find(
        function(elem) {
            return elem.id.match(regexp);
        }
    );
}

//for ie select overlap bug
function makeWindowed(p_div)
{
    var is_ie6 = document.all && (navigator.userAgent.toLowerCase().indexOf("msie 6.") != -1);
    if (is_ie6)
    {
       var html =
          "<iframe style=\"position: absolute; display: none; display: block; " +
          "z-index: -1; width: 30em; height:50em; top: 0; left: 0;" +
          "filter: mask(); background-color: #ffffff; \" src=\"javascript:false\"></iframe>";
       if (p_div) p_div.innerHTML += html;
       // force refresh of div
       var olddisplay = p_div.style.display;
       p_div.style.display = 'none';
       p_div.style.display = olddisplay;
    };
}
