/*
 * Station Finder V0.5
 * Creates a list of stations
 * e.g:
 * <input type="text" class="stationfinder" />
 * <ul class="stationList">
 *		<li crs="{crs}" class="oddRow">{stationname}</li>
 *		<li crs="{crs}" class="selected">{stationname}</li>
 * 		<li crs="{crs}" class="oddRow">{stationname}</li>
 * 		<li crs="{crs}">{stationname}</li>
 * </ul>
 *
 * TODO: DO the bolding of typed in text
 */
$.fn.extend({
	stationfinder : function(options) {
		var defaults = {
			dataFile	: "/assets/json/stations.json",
			codeName	: "crs",
			showCode	: true,
			listCount	: 10,
			useMatch	: true
		}
		var opts = $.extend(defaults, options);

		return this.each(function() {
			return $.StationFinder(this, opts);
		});
	}
});

$.StationFinder = function(input, options) {
	var elem = $(input);
	elem.attr("autocomplete", "off");
	
	// Set the list
	var listHolder = $('<div class="ui-stationfinder"></div>');
	var list = $('<ul class="ui-stationlist"></ul>');
	list.attr("id", elem.attr("id")+"List");
	listHolder.append(list);
	list.hide();
	
	elem.after(listHolder);
	
	var key = {
		up: 38,
		down: 40,
		esc: 27,
		enter: 13,
		back: 8
	}
	
	// Set the actions
	elem.keyup(keyUpActions);
	elem.keydown(keyDownActions);
	elem.focus(function() {
		if (elem.val() != "") {
			setList();
		}
	});
	elem.blur(function() {
		killList = setTimeout(function() {
			removeList();
			clearTimeout(killList);
			killList = null;
		}, 500);
	});
	
	function keyDownActions(e) {
		var pressed = e.keyCode;
		
		switch(pressed) {
			case key.enter:
				if (list.children().length > 0) {
					e.preventDefault();
				}
				break;
		}
	}
	
	function keyUpActions(e) {
		
		var pressed = e.keyCode;
		
		switch(pressed) {
			case key.up:
				changeSelected("prev");
				break;
		
			case key.down:
				changeSelected("next");
				break;
			
			case key.esc:
				removeList();
				break;
			
			case key.enter:
				setSelectedAsStation();
				return false;
				break;
			
			default:
				setList();
				break;
		}
	}
	
	function setList() {
		// Get the XML
		var firstLetter = elem.val() ? elem.val().substr(0, 1).toLowerCase() : null;
		if (firstLetter && firstLetter.match(/[a-z-A-Z]/)) {
			$.ajax({
				url: options.dataFile,
				dataType: "json",
				success: setStations,
				cache: false,
				method: "GET",
				data: {text: elem.val(), amount: options.listCount}
			});
		} else {
			removeList();
		}
	}
	
	function setStations(data) {
		clearList();
		list.show();
		setStationList(data);
	}
	
	function setStationList(data) {
		$(data.items).each(function() {
			var isMatch = !options.useMatch ? true : matchStation(this.name, this[options.codeName]);
			var limit = options.listCount;
			
			if (isMatch) {
				var li = document.createElement("li");
			
				stationText = document.createElement("span");
				stationText.className = "stationName";
				stationText.appendChild(document.createTextNode(properCase(this.name)));
				
				crsText = document.createElement("span");
				crsText.className = "crsCode";
				if (!options.showCode) {
					crsText.style.display = "none";
				}
				crsText.appendChild(document.createTextNode("("+ this[options.codeName] +")"));
				
				li.appendChild(stationText);
				li.appendChild(crsText);
				
				// $(li).attr("crs", this.crs.toUpperCase());
				
				// Set the actions of the li
				$(li).hover(function() { selected(this, "on"); }, function() { selected(this, "off"); });
				$(li).click(function() { setSelectedAsStation(); });
				
				if ($(li).children(".stationName").text() != elem.val()) {
					if (list.children().length % 2 != 0) { $(li).addClass("oddRow"); }
					list.append(li);
				}
				if (list.children().length > limit-1) { return false; }
			}

		});
		// IE
		if ($.browser.msie && parseInt($.browser.version,10) < 7) {
			list.bgiframe();
		}
	}
	
	function matchStation(str, crs) {
		var isMatch = false;
		var val = elem.val();
		var testVal = val.toLowerCase();
		
		// Word match
			// The station must have a word starting with the first letter typed
			var firstLetter = testVal.substring(0, 1);
			var restOfWord = testVal.substring(1, val.length);
			var reg = "^"+ firstLetter + restOfWord +"| "+ firstLetter + restOfWord;
			
			reg = new RegExp(reg, "i");
			var wordMatch = reg.exec(str);
		
		// CRS Match
		reg = new RegExp("^"+ val, "i");
		var crsMatch = reg.exec(crs);
		
		return isMatch = wordMatch || crsMatch ? [wordMatch, crsMatch] : false;
	}
	
	function setSelectedAsStation() {
		var st = list.children(".selected").children(".stationName").text();
		var crs = list.children(".selected").children(".crsCode").text().replace("(", "").replace(")", "");
		if (st != "") {
			elem.val(st);
		}
		var hidden = $("input[name='"+ elem.attr("name") +"_crs']");

		if (hidden.length > 0) {
			hidden.val(crs);
		}
		removeList();
	}
	
	function selected(li, state) {
		var listItem = $(li);
		listItem.siblings().removeClass("selected");
		if(state == "on") { listItem.addClass("selected"); }
		else { listItem.removeClass("selected"); }
	}
	
	function clearList() {
		list.children().remove();
	}
	
	function removeList() {
		clearList();
		list.hide();
	}
	
	function changeSelected(direction) {
		if (!direction) { return false; }
		var current = list.children(".selected");
		list.children(".selected").removeClass("selected");
		
		if (direction == "next") {
			if (current.length == 0) {
				list.children(":first-child").addClass("selected");
			} else if(current.next().length != 0) {
				current.next().addClass("selected");
			} else {
				list.children(":last-child").addClass("selected");
			}
		}
		else if(direction == "prev") { 
			if (current.length == 0) {
				list.children(":last-child").addClass("selected");
			} else if(current.prev().length != 0) {
				current.prev().addClass("selected");
			} else {
				list.children(":first-child").addClass("selected");
			}
		}
		$(".selected").focus();
	}
}

// Start: String Functions
function properCase(str) {
	str = str.toLowerCase();	
	return (str +"").replace(/^(.)|\s(.)/g, function ($1) { return $1.toUpperCase(); } );
}
// End: String Functions
