﻿/*
	Joook Toolkit is a namespaced collection of functions that make JS coding
	just a bit more tolerable. The toolkit can be used statically but I
	recommend instantiating it as most of the methods are used pretty frequently
	and shortening the class name into something more convenient (e.g. "jtk")
	makes for a lot less code.
	
	This file also includes the Lazy Component class that can be used to
	dynamically import JS and CSS files. This is mainly meant to be used with
	bookmarklets to import required resources and as a lazy loader for big web
	applications that don't need to load everything at once.
*/

function JoookToolkit(){
	
	
	// Test if a variable is defined
	this.isDefined = function(testVar){
		if(typeof(testVar) != 'undefined'){
			return true;
		}
		else{
			return false;
		}
	}
	
	
	// Add an event handler to an object
	this.addEvent = function(obj, evType, fn){
		if(obj.addEventListener){ 
			obj.addEventListener(evType, fn, false); 
			return true; 
		}
		else if(obj.attachEvent){ 
			var r = obj.attachEvent("on"+evType, fn); 
			return r; 
		}
		else{ 
			return false; 
		}
	}
	
	
	/*
		Select elements using CSS-esque selectors. Multiple selectors can be
		passed and are separated by commas. This method ALWAYS returns an ARRAY.
		(Even if no elements were found.) Check array.length to see if your
		selection returned any results and remember to use index [0] with
		selections that return an array with only one member. (e.g. when using
		the id selector)
		
		Only the following SINGLE selectors are supported:
		- #id (selector mode 0)
		- .class (selector mode 1)
		- type (selector mode 2)
		- * (selector mode 3)
		
		Unsupported selectors:
		- all combination selectors:
			- type#id (typed id)
			- type.class (typed class)
			- type <type|#id|.class> (descendant selector)
			- > (child selector)
			- + (adjacent sibling selector)
		- pseudo selectors (elements and classes)
		- attribute selectors
	*/
	this.select = function(selector, parent){
		var parentEmt = document;
		var retval = new Array();
		
		if(this.isDefined(parent)){
			parentEmt = parent;
		}
		
		if(this.isDefined(selector) && selector != ''){
			var selectors = selector.split(",");
			for(var i = 0; i < selectors.length; i++){
				var currentSelector = selectors[i].replace(/\s/, '');
				var selectionMode = -1;
				
				if(currentSelector.indexOf("#") == 0){
					selectionMode = 0;
				}
				else if(currentSelector.indexOf(".") == 0){
					selectionMode = 1;
				}
				else if(currentSelector.indexOf("*") == -1){
					selectionMode = 2;
				}
				else{
					selectionMode = 3;
				}
				
				switch(selectionMode){
					case 0:
						var emtId = currentSelector.substr(1);
						retval.push(parentEmt.getElementById(emtId));
						break;
					
					case 1:
						var children = parentEmt.childNodes;
						var matchingNodes = new Array();
						for(var j = 0; j < children.length; j++){
							var classnames = children[j].className.split(" ");
							for(var k = 0; k < classnames.length; k++){
								if(classnames[k] == currentSelector.substr(1)){
									retval.push(children[j]);
									break;
								}
							}
						}
						break;
					
					case 2:
						var children = parentEmt.getElementsByTagName(currentSelector);
						for(var j = 0; j < children.length; j++){
							retval.push(children[j]);
						}
						break;
					
					case 3:
						var children = parentEmt.childNodes;
						for(var j = 0; j < children.length; j++){
							retval.push(children[j]);
						}
						break;
				}
			}
			
		}
		return retval;
	}
	
	
	// Get element dimensions, returns an object
	this.getDimensions = function(obj){
		return {width: obj.offsetWidth, height: obj.offsetHeight};
	}
	
	
	// Get element position in window, returns an object
	this.getPosition = function(obj){
		var curleft = curtop = 0;
		if(obj && obj.offsetParent){
			curleft = obj.offsetLeft;
			curtop = obj.offsetTop;
			while(obj = obj.offsetParent){
				curleft += obj.offsetLeft;
				curtop += obj.offsetTop;
			}
		}
		return {left: curleft, top: curtop};
	}
	
	
	// Set element opacity (percentage)
	this.setOpacity = function(obj, opa){
		var styleObj = obj.style;
		styleObj.opacity = (opa/100); // Opera
		styleObj.MozOpacity = (opa/100); // Mozilla+Firefox
		styleObj.KhtmlOpacity = (opa/100); // Konqueror
		styleObj.filter = "alpha(opacity=" + opa + ")"; // IE
	}
}




/*
	Lazy loader for JS and CSS components. Can't really be bothered to write a
	documentation for this one. The code is pretty self-explanatory.
*/
function LazyComponent(){
	this.loaded = false;
	this.element = null;
	this.parentEmt = null;
	
	this.createCSSEmt = function(fileUrl){
		this.element = document.createElement("link");
		this.element.rel = "stylesheet";
		this.element.type = "text/css";
		this.element.href = fileUrl;
	}
	
	this.createJSEmt = function(fileUrl){
		this.element = document.createElement("script");
		this.element.type = "text/javascript";
		this.element.src = fileUrl;
	}
	
	this.load = function(targetEmt, fileUrl, optionsObj){
		this.parentEmt = targetEmt;
		
		var emtType = 1;
		
		if(isDefined(optionsObj)){
			if(isDefined(optionsObj.isCSS) && optionsObj.isCSS == true){
				emtType = 2;
			}
		}
		
		if(emtType == 2){
			this.createCSSEmt(fileUrl);
		}
		else{
			this.createJSEmt(fileUrl);
		}
		
		targetEmt.appendChild(this.element);
		
		this.loaded = true;
		
		if(isDefined(optionsObj)){
			if(isDefined(optionsObj.callBack)){
				optionsObj.callBack.call();
			}
		}
	}
	
	this.getElement = function(){
		return this.element;
	}
	
	this.remove = function(){
		if(this.element != null && this.loaded == true){
			this.loaded = false;
			return this.parentEmt.removeChild(this.element);
		}
		else{
			return false;
		}
	}
	
	this.replace = function(newUrl, optionsObj){
		if(this.element.nodeName == "link"){
			this.element.href = newUrl;
		}
		else{
			this.element.src = newUrl;
		}
		
		if(isDefined(optionsObj) && isDefined(optionsObj.callBack)){
			optionsObj.callBack.call();
		}
	}
}




/*
	New Joook functionality: JTKDelegate class
	Delegates are used to implicitly scope method calls to objects.
	This delegate class code is similar to that found in deathmonkeyz.com.
*/

function JTKDelegate(){}

JTKDelegate._defaultArgNum = 2;

JTKDelegate.create = function(obj, func){
	var argArr = new Array();
	for(var i = JTKDelegate._defaultArgNum; i < arguments.length; i++){
		argArr[i - JTKDelegate._defaultArgNum] = arguments[i];
	}
	
	return function(){
		func.apply(obj, argArr);
	}
}

var jtk = new JoookToolkit(); // This row may be omitted if JTK is instantiated elsewhere
var formRecipientError = "Muista valita viestille vastaanottava ravintola!";

function setFormSubmissionHandler(formField){
	var formEmt = null;
	var emtParents = new Array();
	var currentEmt = formField;
	
	while(currentEmt.parentNode.nodeName.toLowerCase() != 'body'){
		currentEmt = currentEmt.parentNode;
		emtParents.push(currentEmt);
	}
	
	for(var i = 0; i < emtParents.length; i++){
		if(emtParents[i].nodeName.toLowerCase() == 'form'){
			formEmt = emtParents[i];
			break;
		}
	}
	
	jtk.addEvent(formEmt, "submit", function(){
		return convertRecipient();
	});
}


function updateFormRecipient(selectEmt){
	var selectedOption = selectEmt.options[selectEmt.selectedIndex];
	var delimiterIdx = selectedOption.value.indexOf(";");
	var addr = selectedOption.value.substring(0, delimiterIdx);
	var key = selectedOption.value.substring((delimiterIdx + 1));
	jtk.select("#field_toaddr")[0].value = addr;
	jtk.select("#field_toaddr_key")[0].value = key;
}

function convertRecipient(){
	if(jtk.select("#field_toaddr")[0].value.indexOf("$") > 0){
		jtk.select("#field_toaddr")[0].value = jtk.select("#field_toaddr")[0].value.replace("$", "@");
		return true;
	}
	else{
		alert(formRecipientError);
		return false;
	}
}


var mapservice;
var locale = null;


var restaurantFolders = new Array();
restaurantFolders.push("");
restaurantFolders.push("forssa/");
restaurantFolders.push("helsinki_hameentie/");
restaurantFolders.push("helsinki_vilhonkatu/");
restaurantFolders.push("helsinki_pasila/");
restaurantFolders.push("hyvinkaa/");
restaurantFolders.push("imatra_cumulus/");
restaurantFolders.push("joensuu/");
restaurantFolders.push("jarvenpaa/");
restaurantFolders.push("kotka/");
restaurantFolders.push("kuusamo/");
restaurantFolders.push("kuusankoski/");
restaurantFolders.push("lahti/");
restaurantFolders.push("ideapark/");
restaurantFolders.push("lohja/");
restaurantFolders.push("pieksamaki/");
restaurantFolders.push("pori/");
restaurantFolders.push("riihimaki/");
restaurantFolders.push("rovaniemi/");
restaurantFolders.push("turku_skanssi/");

function updateReservation(){
	jtk.select('#fmRecipient')[0].value = jtk.select('#reservations_restaurantSelect')[0].options[jtk.select('#reservations_restaurantSelect')[0].selectedIndex].value;
	if(jtk.select('#reservations_restaurantSelect')[0].selectedIndex >= 0 && jtk.select('#reservations_restaurantSelect')[0].selectedIndex < restaurantFolders.length){
		jtk.select('#resrevations_restaurantLink')[0].href = "/martina!/ravintolat/" + restaurantFolders[jtk.select('#reservations_restaurantSelect')[0].selectedIndex];
	}
}

function adminGeocode(){
	var address = document.getElementById("street_address").getElementsByTagName("div")[0].innerHTML + ", " + document.getElementById("post_office").getElementsByTagName("div")[0].innerHTML;
	var geocoder = new GClientGeocoder();
	
	alert(address);
	
	geocoder.getLocations(address, fillGeocodeSlot);
}

function fillGeocodeSlot(response){
	if (!response || response.Status.code != 200){
		alert("Can't geocode!");
	}
	else{
		place = response.Placemark[0];
		document.getElementById("geocode").getElementsByTagName("div")[0].innerHTML = "lat : " + place.Point.coordinates[1] + ", lng : " + place.Point.coordinates[0];
	}
}




function initMap(useDI){
	if(document.getElementById('geocode').innerHTML != ''){		
		var hotelCoords = eval("({" + document.getElementById('geocode').innerHTML + "})");
		var hotelPoint = new GLatLng(hotelCoords.lat, hotelCoords.lng);
		
		mapservice = new MapService('mapView');
		if(locale == null){
			locale = "fi_FI";
		}
		mapservice.setLocale(locale);
		mapservice.init();
		mapservice.showControls();
		
		if(useDI == true){
			var address = document.getElementById("street_address").innerHTML + ", " + document.getElementById("post_office").innerHTML;
			mapservice.getDirections(document.getElementById("diFrom").value, address, "directions");
		}
		else{
			mapservice.gotoPos(hotelPoint, true);
		}
	}
}


function mapView(geoCode, emtId, showDIQuery){
	var position = findPos(document.getElementById("street_address"));
	document.getElementById(emtId).style.left = (position[0] - 180) + "px";
	document.getElementById(emtId).style.top = (position[1] - 300) + "px";
	document.getElementById(emtId).style.display = "block";
	
	if(showDIQuery == true){
		document.getElementById(emtId).getElementsByTagName("form")[0].style.display = "block";
	}
	
	initMap(false);
}

function updateDI(){
	if(document.getElementById("diFrom").value != ''){
		document.getElementById("diTo").value = document.getElementById("street_address").innerHTML + ", " + document.getElementById("post_office").innerHTML;
		document.getElementById("diHotel").value = document.getElementById("content_head").innerHTML;
		return true;
	}
	else{
		return false;	
	}
}

function closeMap(emtId){
	document.getElementById(emtId).style.display = "none";
}

function printMap(emtId){
	var address = document.getElementById("street_address").innerHTML + ", " + document.getElementById("post_office").innerHTML;
	var newWin = window.open("/stc/martina/jsp/maps.jsp?from=" + urlEncode(document.getElementById("diFrom").value) + "&to=" + urlEncode(address) + "&hotel=" + urlEncode(document.getElementById("content_head").innerHTML) + "&locale=" + mapservice.locale);
}







// URL encode strings
function urlEncode(clearString) {
  var output = '';
  var x = 0;
  clearString = clearString.toString();
  var regex = /(^[a-zA-Z0-9_.]*)/;
  while (x < clearString.length) {
    var match = regex.exec(clearString.substr(x));
    if (match != null && match.length > 1 && match[1] != '') {
    	output += match[1];
      x += match[1].length;
    } else {
      if (clearString[x] == ' ')
        output += '+';
      else {
        var charCode = clearString.charCodeAt(x);
        var hexVal = charCode.toString(16);
        output += '%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase();
      }
      x++;
    }
  }
  return output;
}

// Find element position
function findPos(obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft
		curtop = obj.offsetTop
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
	}
	return [curleft,curtop];
}








function showLayer(layerId, clickSrc, optObj){
	var tweakCoords = {x: 0, y: 0};
	if(optObj && typeof(optObj) != 'undefined'){
		tweakCoords = {x: optObj.relX, y: optObj.relY};
	}

	var srcPos = jtk.getPosition(clickSrc);
	var layerPos = {x: srcPos.left + tweakCoords.x, y: srcPos.top + tweakCoords.y};
	var layer = new Layer(layerId, clickSrc);
	layer.setOrigin(layerPos.x, layerPos.y);
	
	if(optObj && typeof(optObj.onShow) == 'function'){
		layer.onBeforeShow = optObj.onShow;
	}
	if(optObj && typeof(optObj.onHide) == 'function'){
		layer.onHide = optObj.onHide;
	}
	
	layer.show();
}


function hideSelects(wrapperId){
	var selectEmts = jtk.select("select", jtk.select("#" + wrapperId)[0]);
	for(var i = 0; i < selectEmts.length; i++){
		selectEmts[i].style.display = "none";
	}
}

function showSelects(wrapperId){
	var selectEmts = jtk.select("select", jtk.select("#" + wrapperId)[0]);
	for(var i = 0; i < selectEmts.length; i++){
		selectEmts[i].style.display = "inline";
	}
}

var jtk = new JoookToolkit();

function Layer(emtId, clickSrc){
	this.emt = null;
	this.visible = false;
	this.clickSrc = clickSrc;
	this.canceling = false;
	this.onBeforeShow = null;
	this.onShow = null;
	this.onBeforeHide = null;
	this.onHide = null;
	
	this.setOrigin = function(x, y){
		if(this.emt){
			this.emt.style.left = x + "px";
			this.emt.style.top = y + "px";
		}
	}
	
	this.show = function(){
		if(this.emt){
			if(this.onBeforeShow != null && typeof(this.onBeforeShow) == 'function'){
				this.onBeforeShow.call();
			}
			this.canceling = true;
			this.emt.style.display = "block";
			this.visible = true;
			if(this.onShow != null && typeof(this.onShow) == 'function'){
				this.onShow.call();
			}
		}
	}
	
	this.hide = function(){
		if(this.onBeforeHide != null && typeof(this.onBeforeHide) == 'function'){
			this.onBeforeHide.call();
		}
		if(!this.canceling){
			this.emt.style.display = "none";
			this.visible = false;
		}
		this.canceling = false;
		if(this.onHide != null && typeof(this.onHide) == 'function'){
			this.onHide.call();
		}
	}
	
	
	this.attachHandlers = function(){
		var that = this; // Store current object reference for later delegate binding
		
		jtk.addEvent(document.body, "click", function(){
			JTKDelegate.create(that, that.hide());
		});
		
		jtk.addEvent(this.emt, "click", function(){
			JTKDelegate.create(that, that.show());
		});
		
		jtk.addEvent(this.clickSrc, "click", function(){
			JTKDelegate.create(that, that.show());
		});
	}
	
	this.init = function(emtId){
		this.emt = jtk.select("#" + emtId)[0];
		if(this.emt){
			this.emt.style.position = "absolute";
			this.attachHandlers();
		}
	}
	
	this.init(emtId);
}

/*
	Form element classes for form validator
	All form elements have their own validation methods
*/

function FETextfield(emt){
	this.inputEmt = emt;
	this.valueRequired = null;
	this.emtValue = null;
	
	this.validationType = null;
	this.validTypes = new Array('Email', 'Number', 'Other');
	
	this.validLabelSrcs = new Array('FromNextSibling', 'FromPrevSibling');
	this.emtLabelSrc = null;
	this.emtLabel = "";
	
	this.validate = function(){
		if(this.inputEmt.title == null || this.inputEmt.title == ""){
			for(var i = 0; i < this.validLabelSrcs.length; i++){
				if(this.emtLabel == "" && this.inputEmt.className.indexOf('fvLabel' + this.validLabelSrcs[i]) > -1){
					this.emtLabelSrc = i;
				}
			}
			
			if(this.emtLabelSrc != null){
				switch(this.emtLabelSrc){
					case 0:
						this.emtLabel = this.inputEmt.nextSibling.innerHTML;
						break;
					
					case 1:
						this.emtLabel = this.inputEmt.previousSibling.innerHTML;
						break;
				}
			}
			else{
				this.emtLabel = this.inputEmt.name;
			}
		}
		else{
			this.emtLabel = this.inputEmt.getAttribute("title");
		}
		
		
		
		
		if(this.inputEmt.className.indexOf('fvRequired') > -1){
			this.valueRequired = true;
		}
		else{
			this.valueRequired = false;
		}
		
		if(this.valueRequired == true){
			this.emtValue = this.inputEmt.value;			
			var foundType = null;
			
			for(var i = 0; i < this.validTypes.length; i++){
				if(this.validationType == null && this.inputEmt.className.indexOf('fvType' + this.validTypes[i]) > -1){
					this.validationType = this.validTypes[i];
					foundType = i;
				}
			}
			
			if(this.validationType == null){
				this.validationType = this.validTypes[this.validTypes.length - 1];
			}
			
			var validationRegExp = null;
			
			switch(foundType){
				case 0:
					validationRegExp = new RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?");
					break;
				
				case 1:
					validationRegExp = new RegExp("[0-9]+");
					break;
				
				default:
					validationRegExp = new RegExp(".+");
					break;
			}
			
			return validationRegExp.test(this.emtValue);
		}
		else{
			return true;
		}
	}
	
	
	this.getValidationType = function(){
		return this.validationType;
	}
	
	this.getValidTypes = function(){
		return this.validTypes;
	}
	
	this.getLabel = function(){
		return this.emtLabel;
	}
}






function FECheckbox(emt){
	this.inputEmt = emt;
	this.valueRequired = null;
	this.emtValue = null;
	
	this.validLabelSrcs = new Array('FromNextSibling', 'FromPrevSibling');
	this.emtLabelSrc = null;
	this.emtLabel = "";
	
	this.validate = function(){
		if(this.inputEmt.title == null || this.inputEmt.title == ""){
			for(var i = 0; i < this.validLabelSrcs.length; i++){
				if(this.emtLabel == "" && this.inputEmt.className.indexOf('fvLabel' + this.validLabelSrcs[i]) > -1){
					this.emtLabelSrc = i;
				}
			}
			
			if(this.emtLabelSrc != null){
				switch(this.emtLabelSrc){
					case 0:
						this.emtLabel = this.inputEmt.nextSibling.innerHTML;
						break;
					
					case 1:
						this.emtLabel = this.inputEmt.previousSibling.innerHTML;
						break;
				}
			}
			else{
				this.emtLabel = this.inputEmt.name;
			}
		}
		else{
			this.emtLabel = this.inputEmt.getAttribute("title");
		}
		
		if(this.inputEmt.className.indexOf('fvRequired') > -1){
			this.valueRequired = true;
		}
		else{
			this.valueRequired = false;
		}
		
		if(this.valueRequired == true){
			this.emtValue = this.inputEmt.checked;			
			return this.emtValue;
		}
		else{
			return true;
		}
	}
	
	this.getLabel = function(){
		return this.emtLabel;
	}
}

/*
	Multi-purpose form validator
	Requires external element classes
*/

function FormValidator(formEmt){
	this.formEmt = formEmt;
	this.formInputs = null;
	this.formSelects = null;
	this.formTextareas = null;
	
	this.errorString = "Please fill out the following fields:";
	this.requiredPrefix = "- ";
	this.requiredSeparator = "\n";
	this.errorCount = 0;
	
	this.validate = function(){
		
		if(this.formEmt.tagName == "FORM"){
			var errorStr = "";
			
			this.formInputs = this.formEmt.getElementsByTagName("INPUT");
			/*
			this.formSelects = this.formEmt.getElementsByTagName("SELECT");
			this.formTextareas = this.formEmt.getElementsByTagName("TEXTAREA");
			*/
			
			
			for(var i = 0; i < this.formInputs.length; i++){
				if(this.formInputs[i].type == "text"){
					var textInput = new FETextfield(this.formInputs[i]);
					var validationResult = textInput.validate();
					
					if(validationResult == false){
						this.errorCount++;
						this.errorString += this.requiredSeparator + this.requiredPrefix + textInput.getLabel();
					}
				}
				
				if(this.formInputs[i].type == "checkbox"){
					var checkbox = new FECheckbox(this.formInputs[i]);
					var validationResult = checkbox.validate();
					
					if(validationResult == false){
						this.errorCount++;
						this.errorString += this.requiredSeparator + this.requiredPrefix + checkbox.getLabel();
					}
				}
			}
			
			if(this.errorCount > 0){
				alert(this.errorString);
				return false;
			}
			else{
				return true;
			}
		}
		else{
			return false;
		}
	}
}

	function validateForm(formEmt){
		var formValidator = new FormValidator(formEmt);
		formValidator.errorString = "Täytäthän vielä seuraavat kentät:\n";
		formValidator.requiredPrefix = "• ";
		formValidator.requiredSeparator = "\n";
		return formValidator.validate();
	}


