// common eludi functions
// (c) 2010-2011 by Gerald Franz, all rights reserved

/// returns current date in ISO standard notation
isoDate = function (deltaDay) {
	var date = new Date();
	if(deltaDay) date.setTime(date.getTime()+deltaDay*86400*1000);
	var month = date.getMonth()+1;
	if(month<10) month = '0'+String(month);
	var day = date.getDate();
	if(day<10) day='0'+String(day);
	return date.getFullYear()+"-"+month+"-"+day;
}

/// String trim extension, removes leading and tailing whitespace
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }
/// String reverse extension
String.prototype.reverse=function(){return this.split("").reverse().join("");}
/// encodes reserved characters and umlauts to html entities
String.prototype.htmlStr = function(){
	var from = [ /&/g,/</g,/>/g,/"/g, /Ö/g, /ö/g, /Ä/g, /ä/g, /Ü/g, /ü/g, /ß/g];
	var to = ["&amp;", "&lt;", "&gt;", "&quot;", "&Ouml;", "&ouml;", "&Auml;", "&auml;", "&Uuml;", "&uuml;", "&szlig;" ];
	var string = this;
	for (var i=0; i<from.length; ++i) string = string.replace(from[i], to[i]);
	return string;
}
/// encodes html entities to unicode
String.prototype.html2unicode = function(){
	var from = [ /&apos;/g, /&quote;/g, /&Ouml;/g, /&ouml;/g, /&Auml;/g, /&auml;/g, /&Uuml;/g, /&uuml;/g, /&szlig;/g];
	var to = [ "'", '"', "\u00d6", "\u00f6", "\u00c4", "\u00e4", "\u00dc", "\u00fc", "\u00df" ];
	var string = this;
	for (var i=0; i<from.length; ++i) string = string.replace(from[i], to[i]);
	return string;
}
/// string formatting
String.prototype.format = function() {
	var s = this;
	for (var i = 0; i < arguments.length; ++i) {
		var regexp = new RegExp('\\{'+i+'\\}', 'gi');
		s = s.replace(regexp, arguments[i]);
	}
	return s;
}

/// clear array
Array.prototype.clear=function() {
      this.length = 0;
}
/// Array remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
	var rest = this.slice((to || from) + 1 || this.length);
	this.length = from < 0 ? this.length + from : from;
	return this.push.apply(this, rest);
}
/// swaps element i and j of array
Array.prototype.swap = function(i, j) {
	var tmp = this[i];
	this[i] = this[j]
	this[j] = tmp;
}

/// implementation of document.getElementsByClassName, if missing
if(!document.getElementsByClassName) document.getElementsByClassName = function(className) {
	var ret=[];
	var all_obj = document.all ? document.all : document.getElementsByTagName("*");
	for(var i=0; i<all_obj.length; ++i)
		if(all_obj[i].className.indexOf(className)!=-1)
			if((","+all_obj[i].className.split(" ").join(",")+",").indexOf(","+className+",")!=-1)
				ret.push(all_obj[i]);
	return ret;
}

/// namespace for shared functionality
eludi = {
	/// generates a random sequence of length n, 0..n-1
	randomSequence: function(n) {
		var seq = [ ];
		for(var i=0; i<n; ++i) seq.push(i);
		for(var i=n-1; i>0; --i) seq.swap(i, Math.floor(Math.random()*(i+1)));
		return seq;
	},
//--- DOM utilities ---
	/// permutes child nodes sequence
	permutateChildren: function(parentId) {
		var parent = document.getElementById(parentId);
		var n = parent.children.length;
		for(var i=n-1; i>0; --i) {
			var j = Math.floor(Math.random()*(i+1));
			if(i==j) continue;
			var child1 = parent.removeChild(parent.children[i]);
			var child2 = parent.removeChild(parent.children[j]);
			parent.appendChild(child2);
			parent.insertBefore(child1, parent.children[j]);
		}
	},
	/// switches a single child on, and all other children of its parent off
	switchToChild: function(childId) {
		var refChild = document.getElementById(childId);
		if(!refChild) return false;
		var parent= refChild.parentNode;
		for(var i = 0; i < parent.childNodes.length; ++i) {
			var child = parent.childNodes[i];
			if(child.nodeType!=1) continue;
			child.style.display = (child===refChild) ? "block" : "none";
		}
		return true;
	},
	/// switches the passed element of a toggle button group on, all others off
	toggleButton: function(el){
		var parent = el.parentNode;
		for(var i = 0; i < parent.childNodes.length; ++i) {
			var child = parent.childNodes[i];
			if(child.nodeType!=1) continue;
			if(child===el)
				child.className = "on";
			else if(child.className ==="on") 
				child.className = "off";
		}
	},	
	/// localization of HTML document, not exactly the semantically correct place, but suitable
	localizeDocument: function(dict) {
		var elements = document.getElementsByClassName('l10n');
		for(var i=0; i<elements.length; ++i) {
			var key = elements[i].innerHTML;
			if(key in dict) elements[i].innerHTML = dict[key];
		}
	},
	click2touch: function(element) {
		if(session.platform!='iOS'&&session.platform!='Android')
			return;
		var elems = element ? [ element ] : document.getElementsByTagName('*');
		for(var i=0; i<elems.length; ++i) {
			var elem = elems[i];
			if(elem.onclick && !elem.ontouchstart) {
				elem.callback = elem.onclick;
				elem.ontouchstart=function(e) { e.preventDefault(); return this.callback(e); }
				elem.onclick=null;
			}
		}
	},
	windowMetrics: function() {
		return { innerWidth:window.innerWidth, innerHeight:window.innerHeight, 
		outerWidth:window.outerWidth, outerHeight:window.outerHeight,
		screenWidth:screen.width, screenHeight:screen.height, 
		availWidth:screen.availWidth, availHeight:screen.availHeight,
		orientation:(window.orientation||0) };
	},

//--- communication helpers ---
	/// returns URL parameters as map
	paramsRequest: function() {
		var map = (typeof params === 'undefined') ? {} : params;
		if(window.location.protocol!='file:' && sessionStorage && sessionStorage['eludi_paramsRequest']) {
			var sessionStorageParams = JSON.parse(sessionStorage['eludi_paramsRequest']);
			for(var key in sessionStorageParams)
				map[key] = sessionStorageParams[key];
			delete sessionStorage['eludi_paramsRequest'];
		}
		if(window.location.href.indexOf('?')>=0)
			window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { map[key] = decodeURIComponent(value); });
		return map;
	},
	/// dynamically loads a javascript file from a url
	loadjs: function (url, callback) {
		var node=document.createElement('script');
		node.setAttribute("type","text/javascript");
		node.setAttribute("src", url);
		if(callback) {
			if (node.addEventListener)
				node.addEventListener("load", callback, false);
			else node.onreadystatechange = function() {
				if (this.readyState == "complete") callback(this);
			}		
		}
		document.getElementsByTagName("head")[0].appendChild(node);
	},
	/// executes an asynchronous XMLHttpRequest or JSONP AJAX request
	httpRequest: function(url, params, callback, method) {
		if(!method) method = "POST";
		var paramStr = '';
		for(var key in params) {
			if(paramStr.length) paramStr += '&';
			paramStr += key+'='+encodeURIComponent(params[key]);
		}
		
		if(method=='JSONP') {
			var u = url;
			var nocache = Math.random().toString().substr(2);
			if(callback) {
				nocache = '_cb'+nocache;
				window[nocache] = function(resp) {
					callback(resp, (!resp ? 204 : resp.status ? resp.status : 200));
					delete window[nocache];
				}
				u+='?callback=' + nocache;
			}
			else  u+= '?nocache='+nocache;
			if(paramStr.length) 
				u+='&'+paramStr;
			var script = document.createElement('script');
			script.setAttribute('src', u);
			script.setAttribute('type', 'text/javascript');
			var cleanup = function() { script.parentNode.removeChild(script); };
			if(script.addEventListener)
				script.addEventListener("load", cleanup, false);
			else script.onload = cleanup;
			document.getElementsByTagName('head')[0].appendChild(script);
			return;
		}
		var xhr = null;
		try {
			xhr = new XMLHttpRequest();
		}
		catch(e) {
			try {
				xhr  = new ActiveXObject("Microsoft.XMLHTTP");
			} 
			catch(e) {
				try {          
					xhr  = new ActiveXObject("Msxml2.XMLHTTP");
				} 
				catch(e) {
					return;
				}
			}
		}
		try {
			var u = url;
			if((method!='POST') && paramStr.length) 
				u+='?'+paramStr;
			xhr.open( method, u, true );
			if((method=='POST') && paramStr.length)
				xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			if(callback) xhr.onreadystatechange = function () {
				if ( xhr.readyState == 4)
					callback( xhr.responseText, xhr.status );
			};
			if((method=='POST') && paramStr.length)
				xhr.send(paramStr);
			else xhr.send(null);
		}
		catch(error) { }
	},
	postToUrl: function(url, params, callback) {
		var form = document.createElement("form");
		form.setAttribute("method", 'POST');
		form.setAttribute("action", url);
		
		var target = "hidden_iframe";
		form.setAttribute("target", target);
		var iframe = document.getElementById(target);
		if(!iframe) {
			iframe = document.createElement("iframe");
			iframe.setAttribute("name", target);
			iframe.setAttribute("id", target);
			iframe.style.display="none";
			document.body.appendChild(iframe);
		}
		if(callback) iframe.onload = function() { callback(); }
		for(var key in params) {
			var hiddenField = document.createElement("input");
			hiddenField.setAttribute("type", "hidden");
			hiddenField.setAttribute("name", key);
			hiddenField.setAttribute("value", params[key]);
			form.appendChild(hiddenField);
		}
		document.body.appendChild(form);
		form.submit();
		document.body.removeChild(form);
	},
	/// opens another (eludi) url and passes parameters preferably via sessionStorage
	openUrl: function(url, params, replace) {
		if(params) {
			if(window.location.protocol!='file:' && sessionStorage)
				sessionStorage['eludi_paramsRequest']=JSON.stringify(params);
			else {
				var paramStr = '';
				for(var key in params) {
					if(paramStr.length) paramStr += '&';
					paramStr += key+'='+encodeURIComponent(params[key]);
				}
				url += '?' + paramStr;
			}
		}
		if(replace)
			window.location.replace(url);
		else window.location.href=url;
	},
	
	/// executes a structured query on a Google spreadsheet
	spreadsheetQuery: function(spreadsheetKey, worksheetKey, callback, params) {
		var filter = '';
		for(var key in params)
			filter+= '&'+key+'='+((key=='sq')?encodeURIComponent(params[key]):params[key]);
		var scriptId = spreadsheetKey+worksheetKey;
		var script = document.getElementById(scriptId);
		if (script) script.parentNode.removeChild(script);
		script = document.createElement('script');
		script.setAttribute('src', 'http://spreadsheets.google.com/feeds/list'
			+ '/' + spreadsheetKey + '/' + worksheetKey + '/public/values' 
			+ '?alt=json-in-script&callback='+callback + filter );
		script.setAttribute('id', scriptId);
		script.setAttribute('type', 'text/javascript');
		document.getElementsByTagName('body')[0].appendChild(script);
	},
	/// extracts data from a Google spreadsheet feed response
	spreadsheetExtractData: function(json) {
		var data = [ ];
		if( json.feed.entry) for (var i = 0; i < json.feed.entry.length; ++i) {    
			var entry = json.feed.entry[i];
			var line= { };
			for (var prop in entry) if(prop.substr(0,4)=="gsx$")
				line[prop.substr(4)]=entry[prop].$t;
			data.push(line);
		}
		return data;
	},
	/// appends a single data record to a Google Spreadsheet via the form interface
	spreadsheetAppend: function(formKey, data) {
		var params= { formkey:formKey };
		for(var i=0; i<data.length; ++i)
			params["entry."+i+".single"] = data[i];		
		this.postToUrl("https://spreadsheets.google.com/formResponse", params);
	},

//--- shared specific functionality ---
	popupToggle: function (popupName) {
		var menu=document.getElementById(popupName);
		var show = (menu.style.display=='none');
		menu.style.display= show ? 'block':'none';
		var button = document.getElementById('button_'+popupName);
		if(button) button.className = show ? 'emenuButtonSelected' : 'emenuButton';
	},
	sessionRequest: function(callback, timeout, params) {
		if(callback)
			eludi.sessionReceive.callback = callback;
		if(!params && window.location.protocol!='file:' && sessionStorage && sessionStorage.session)
			eludi.sessionReceive(JSON.parse(sessionStorage.session));
		else {
			if(timeout)
				eludi.sessionRequest.timeout = window.setTimeout(eludi.sessionReceive, timeout);
			eludi.httpRequest('http://eludi.net/services/session.php', params, eludi.sessionReceive, 'JSONP');
		}
	},
	sessionReceive: function(json) { 
		if(typeof session==='undefined')
			session = { };
		var timeout = true;
		if(json) {
			clearTimeout(eludi.sessionRequest.timeout);
			for(var key in json)
				session[key]=json[key]; 
			timeout = false;
			if(localStorage)
				localStorage.lang = session.lang;
		}
		else if(localStorage && localStorage.lang)
			session.lang = localStorage.lang;
		
		// detect platform:
		var browserId = navigator.userAgent;
		if(browserId.indexOf('Android') != -1)
			session.platform = 'Android';
		else if(browserId.indexOf("iPhone") != -1 || browserId.indexOf("iPod") != -1 || browserId.indexOf("iPad") != -1)
			session.platform = 'iOS';
		else if(browserId.indexOf('Presto')!=-1)
			session.platform = 'Opera';
		else if(browserId.indexOf('AppleWebKit')!=-1)
			session.platform = 'webkit';
		else if(browserId.indexOf('Trident')!=-1)
			session.platform = 'MSIE';
		else if(browserId.indexOf('Gecko') != -1)
			session.platform = 'Gecko';
		
		if(window.location.protocol!='file:' && sessionStorage &&!session.temporary)
			sessionStorage.session=JSON.stringify(session);			
		delete eludi.sessionRequest.timeout;
		if(typeof l10n!='undefined') {
			if(session.lang && (session.lang!='en'))
				eludi.loadjs('l10n.'+session.lang+'.js');
			else eludi.localizeDocument(l10n);
		}
		if(eludi.sessionReceive.callback)
			eludi.sessionReceive.callback(timeout);
	},
	scores: {
		submit: function(app, version, score, name, sid, ip, mode, scenario, league) { // league not yet supported
			if(window.location.protocol!='file:' && sessionStorage)
				sessionStorage.name = name;			
			var date = new Date();
			var month = date.getMonth()+1;
			if(month<10) month = '0'+String(month);
			var day = date.getDate();
			if(day<10) day='0'+String(day);
			var dateInt = Number(String(date.getFullYear())+month+day);			
			var params = [ app, version, score, name.substr(0,32), '', sid, ip, mode ? mode : '', '', scenario ? scenario : '', dateInt ];
			eludi.spreadsheetAppend("dGVHYVJLclk2SHV1ZTljZC11aWFiclE6MA", params);
		},
		request: function(callback, app, period, mode, scenario, limit) {
			var query = 'app='+app;
			if(mode)
				query += ' and mode='+mode;
			if(scenario)
				query += ' and scenario='+scenario;			
			if(period) {
				if (period=='thisMonth') { 
					var date = new Date();
					var month = date.getMonth()+1;
					period = { year:date.getFullYear(), month:month };
				}
				if(period.month && period.year) {
					var month = String(period.month);
					if(month.length<2)
						month = '0'+month;
					period = [ Number(String(period.year)+month+'01'), Number(String(period.year)+month+'31') ];
				}				
				query += ' and date>='+period[0] + ' and date<='+period[1];
			}
			if(!limit)
				limit = 10;
			eludi.spreadsheetQuery('teGaRKrY6Huue9cd-uiabrQ', 'od6', callback, {sq:query, orderby:'column:score', reverse:true, 'max-results':limit});
		},
		display: function(json) {
			var nEntriesMax=10;
			var tbody = document.getElementById('tableHighscores').lastChild;
			while(tbody.childNodes.length>1)
				tbody.removeChild(tbody.lastChild);

			if(json.feed.entry) for (var i = 0; (i < json.feed.entry.length) && (i<nEntriesMax); ++i) {    
				var entry = json.feed.entry[i];
				var data = { };
				for (var prop in entry) if(prop.substr(0,4)=="gsx$")
					data[prop.substr(4)]=entry[prop].$t;
				var tr = document.createElement('tr');
				tr.appendChild(document.createElement('td'));
				tr.childNodes[tr.childNodes.length-1].innerHTML=(i+1);
				tr.appendChild(document.createElement('td'));
				tr.childNodes[tr.childNodes.length-1].innerHTML=data.score;
				tr.appendChild(document.createElement('td'));
				tr.childNodes[tr.childNodes.length-1].innerHTML=data.name.htmlStr();
				tr.appendChild(document.createElement('td'));
				var date = data.zeitstempel;
				if(date.length) {
					date = date.split(" ")[0];
					var parts = date.split(".");
					date = parts[2]+'-'+parts[1]+'-'+parts[0];
				}
				tr.childNodes[tr.childNodes.length-1].innerHTML=date;
				tbody.appendChild(tr);
			}
			if(eludi.scores.display.callback)
				eludi.scores.display.callback();
		},
		updateMin: function(json) {
			if(this.updateMin.timeout)
				clearTimeout(this.updateMin.timeout);
			if(!json)
				this.min = false;
			else {
				var nEntriesMax=10;
				this.min = (!json.feed.entry || json.feed.entry.length<nEntriesMax) ? 
					0 : Number(json.feed.entry[json.feed.entry.length-1]["gsx$score"].$t);
			}
			if(this.updateMin.callback)
				this.updateMin.callback(this.min);
		},
		requestMin: function(game, period, mode, scenario, callback, timeout) {
			this.request('eludi.scores.updateMin', game, period, mode, scenario, 10);
			this.updateMin.callback = callback;
			this.updateMin.timeout = timeout ? setTimeout(function() { eludi.scores.updateMin(false); }, timeout) : null;
		},
		requestDisplay: function(game, period, mode, scenario, title) {
			var timespan = null;
			var screen_scores_title;
			if (period=='thisMonth') { 
				var date = new Date();
				var month = date.getMonth()+1;
				period = { year:date.getFullYear(), month:month };
			}
			if(period && period.month && period.year) {
				var month = String(period.month);
				if(month.length<2)
					month = '0'+month;
				timespan = [ Number(String(period.year)+month+'01'), Number(String(period.year)+month+'31') ];
				screen_scores_title = l10n.highscores+' '+l10n.months[period.month-1]+' '+period.year;
			}
			else screen_scores_title = l10n.allTimeBest;
			if(mode && l10n[mode])
				screen_scores_title += ' '+l10n[mode];
			if(title)
				screen_scores_title += ', "'+title+'"';
			eludi.scores.request('eludi.scores.display', game, timespan, mode, scenario);
			eludi.scores.display.callback = function() {
				if(document.getElementById('screen_scores_title'))
					document.getElementById('screen_scores_title').innerHTML = screen_scores_title;
				eludi.switchToChild('screen_scores');
				eludi.switchToChild('controls_scores');
			}
		},
		min:0
	}
}

