/* E PLURIBUS UNUM - API remota per javascript
*
*  Definiamo un namespace, foxgroup, che contiene tutte le funzioni comuni usate nelle pagine.
*  Ad esempio, foxgroup.gestionale contiene le funzioni che vengono usate nel gestionale:
*  foxgroup.gestionale.immobili contiene le funzioni che possono essere usate per manipolare gli immobili,
*  foxgroup.gestionale.clienti le funzioni per i clienti etc.
*
*  foxgroup.prossimacasa (non implementato) per prossima casa
*  foxgroup.renet        (non implementato) per renet
*
*  Per ultimo, foxgroup.utils contiene utilities che possono essere utili ovunque. Ad esempio,
*  foxgroup.utils.t     per tradurre stringhe
*  foxgroup.utils.error per mostrare messaggi di errore
*
*  Tutte le app interne sono incoraggiate ad usare questo spazio di nomi, DOPO aver controllato che il nome non
*  sia gia' in uso.
*  Probabilmente foxgroup.mappa andrebbe aggiunto qui. TODO!
*
*/

// controlliamo se il namespace esiste, e se non c'e' lo creiamo
var foxgroup = foxgroup || {};


/* ############################# SEZIONE GENERALE ################################### */

/* API Utils
*
*  Varie funzioni che possono essere utili per agire in modo -unificato- nelle varie pagine del gestionale.
*  Ad esempio, foxgroup.utils.placeholder(qualche-input-testuale, testo-da-mostrare) imposta un placeholder html5
*  sui browser che lo supportano, e ne emula uno in javascript nei browser che non lo supportano ancora.
*/
foxgroup.utils = foxgroup.utils || {};
(function(utils) {

	utils.stub             = stub;             // ()
	utils.addEvent         = addEvent;         // (obj:dom-element, str:event-type, fn:callback)
	utils.removeEvent      = removeEvent;      // (obj:dom-element, str:event-type, fn:callback)
	utils.inputPlaceholder = inputPlaceholder; // (obj:dom-element, str:placeholder-text)
	utils.support          = support;          // (str:tag, str:dom-property)
	utils.error            = error;            // (str:text-to-display, fn:callback)
	utils.t                = translate;        // (str:text-to-translate [, str:lang [, obj:context]])
	utils.xhr              = xhr;              // (str:url, str:method, obj:params [, fn:onsuccess [, fn:onfailure [, bool:cache]]])
	utils.runOnce          = runOnce;          // (fn:toberun [, bool:checkbody])

	function stub() {}

	function addEvent(el, type, fn) {
		if (el.addEventListener) return el.addEventListener(type, fn, false);
		else                     return el.attachEvent('on' + type, fn);
	}

	function removeEvent(el, type, fn) {
		if (el.addEventListener) return el.removeEventListener(type, fn);
		else                     return el.detachEvent('on' + type, fn);
	}

	function support(el, feature) {
		if (feature in document.createElement(el)) return true;
		else                                       return false;
	}

	function inputPlaceholder(el, text) {
		function removePlaceholder() {
			el.style.cssText = '';
			if (el.value === text) el.value = '';
		}
		function addPlaceholder() {
			if (el.value === '') {
				el.value = text;
				el.style.color = 'grey';
			}
		}

		if (utils.support('input', 'placeholder')) {
			el.placeholder = text;
		} else {
			utils.addEvent(el, 'focus', removePlaceholder);
			utils.addEvent(el, 'blur', addPlaceholder);
			if (el.form) utils.addEvent(el.form, 'submit', removePlaceholder);
			addPlaceholder();
		}
	}

	function error(text, cb) {
		alert(text); // TODO rimpiazzare l'alert con qualcosa di piu' elegante e magari loggare gli errori?
		if (typeof cb == 'function') cb(text);
	}

	function translate(text, ctx) {
		if (ctx == null) ctx = translate.defaultContext;
		return ctx[text] != null ? ctx[text] : text;
	}
	// TODO settare il contesto in qualche modo: file di localizzazione esterno? Si potrebbe renderlo modificabile
	//      dall'esterno in qualche modo migliore di foxgroup.utils.t.defaultContext
	translate.defaultContext = {};

	function xhr(url, method, parameters, onSuccess, onFailure, cache) {
		// non e' necessario passare i callbacks
		onSuccess = onSuccess || utils.stub;
		onFailure = onFailure || utils.stub;

		// Supporto alla cache
		xhr.cache = xhr.cache || {};
		cache     = !!cache   || false;
		queryHash = makeQueryHash();

		if (cache && xhr.cache.hasOwnProperty(queryHash)) {
			onSuccess.call(this, {responseText: xhr.cache[queryHash]});
			return;
		}

		// TODO Studiare fisica, costruire una macchina del tempo, andare nel passato ed uccidere il padre del
		//      creatore di Prototype prima che procrei la sua stirpe satanica di programmatori infami.
		//      In alternativa, rimpiazzare Prototype da qui.
		new Ajax.Request(url, {
			method: method,
			parameters: parameters,
			onSuccess: function(data) {
				if (cache) {
					xhr.cache[queryHash] = data.responseText;  // TODO Cachare l'oggetto?
				}
				onSuccess.call(this, data);
			},
			onFailure: onFailure
		});

		function makeQueryHash() {
			return method + '_' + url + '_' + foxgroup.utils.qs.render(parameters, '');
		}
	}

	// Esegue la funzione passatale come primo argomento solo una volta.
	// Il secondo parametro e' opzionale e specifica se fare il controllo anche sul corpo della funzione,
	// in alternativa viene fatto solo il controllo per identita'
	function runOnce(fn, checkbody) {
		checkbody = !!checkbody || false;

		if (runOnce.fns    === undefined) runOnce.fns    = [];
		if (runOnce.bodies === undefined) runOnce.bodies = [];

		var fnbody = fn.toString();

		if (runOnce.fns.indexOf(fn) != -1 || (checkbody && runOnce.bodies.indexOf(fnbody) != -1)) {
			return null;
		}

		runOnce.fns.push(fn);
		runOnce.bodies.push(fnbody);
		return fn.apply(this);
	}


	/* API per la manipolazione delle querystring
	*
	*  Serve a manipolare la querystring DUH!
	*
	*/

	utils.qs = utils.qs || {};
	(function(qs) {
		qs.get    = get;       // (str:param [, str:ctx])
		qs.set    = set;       // (obj:param [, bool:multi [, str:ctx]])
		qs.getAll = getAll;    // ([str:ctx])
		qs.render = render;    // (obj:qsObj [, str:ctx])


		// Ritorna una lista con tutti i valori che il parametro assume nella querystring
		// ctx e' l'url su cui lavora, se non viene passato si assume sia l'url della pagina
		function get(param, ctx) {
			return getAll(ctx)[param] || [];
		}

		// Ritorna l'url completa di querystring
		// obj e' un oggetto del tipo {parametro : valore} o del tipo {parametro : [val1, val2, val3...]}
		// multi e' un settaggio per stabilire se si vuole un singolo valore per le qs o si accettano valori multipli
		// per il parametro passato
		// ctx e' la solita url opzionale su cui lavorare
		function set(obj, multi, ctx) {
			multi = multi || false;
			var qsObj = qs.getAll(ctx);
			var p;
			for (p in obj) if (obj.hasOwnProperty(p)) {
				if (obj[p] == null) {
					delete qsObj[p];
					continue;
				}
				if (! (obj[p] instanceof Array)) obj[p] = [obj[p]];

				if (multi) {
					if (qsObj[p] === undefined) qsObj[p] = [];
					qsObj[p].push.apply(qsObj[p], obj[p]);
				}
				else
					qsObj[p] = obj[p];
			}
			return render(qsObj, ctx);
		}

		function getAll(ctx) {
			ctx = ctx || window.location.href;
			var r = /(?:\?|&)([^=]+)=([^&]*)/g;
			var t;
			var param;
			var value;
			var ret = {};
			while (t = r.exec(ctx)) {
				param = decodeURIComponent(t[1]);
				value = decodeURIComponent(t[2]);
				if (ret.hasOwnProperty(param) === false) ret[param] = [];
				ret[param].push(value);
			}
			return ret;
		}

		function render(qsObj, ctx) {
			ctx = ctx || window.location.href;
			var prop;
			var i;
			var qs = []; // TODO url completa o solo querystring???
			
			for (prop in qsObj) if (qsObj.hasOwnProperty(prop)) {
				if (typeof qsObj[prop] == "string")
					qs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(qsObj[prop]));
				else {
					for (i = 0; i < qsObj[prop].length; ++i) {
						qs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(qsObj[prop][i]));
					}
				}
			}
			if (qs.length > 0) return ctx.split('?')[0] + '?' + qs.join('&');
			else               return ctx.split('?')[0];
		}

	})(utils.qs);


	/* API per riconoscere i browsers
	*
	* Man mano che si va avanti si aggiunge roba, penso.
	* Non esporta procedure, ma valori booleani
	*/

	utils.browser = utils.browser || {};
	(function(browser) {

		var isAndroid  = /android/i  .test(navigator.appVersion);
		var isIphone   = /iphone/i   .test(navigator.appVersion);
		var isIpad     = /ipad/i     .test(navigator.appVersion);
		var isPlaybook = /playbook/i .test(navigator.appVersion);
		var isTouchPad = /hp-tablet/i.test(navigator.appVersion);
		var isMobile   = isAndroid || isIphone || isIpad || isPlaybook || isTouchPad;

		var vendor = /msie/i.test(navigator.userAgent) ? 'ie' :
			/webkit/i.test(navigator.appVersion) ? 'webkit' : 
			/firefox/i.test(navigator.userAgent) ? 'firefox' : 
			'opera' in window ? 'opera' : 'boh';

		browser.isAndroid  = isAndroid;
		browser.isIphone   = isIphone;
		browser.isIpad     = isIpad;
		browser.isPlaybook = isPlaybook;
		browser.isTouchPad = isTouchPad;
		browser.isMobile   = isMobile;
		browser.vendor     = vendor;

	})(utils.browser);


	/* Supporto per JSON crosslib
	*
	* Usiamo diverse librerie, a volte una, a volte un'altra. Questo le prova tutte!
	*/
	utils.JSON = utils.JSON || {};
	(function(exports) {

		exports.stringify = stringify;       // (obj|array|str|bool|null|num:data [, fn:replacer [, str:ws]])
		exports.parse     = parse;           // (str:str [, fn:reviver])

		// data     e' qualunque cosa serializzabile in JSON
		// replacer e' una funzione censoria invocata come replacer(key, value) -> new value
		// ws       e' white space per prettyprinting
		// Ritorna  JSON, o spara un errore
		function stringify(data, replacer, ws) {
			if (typeof JSON == "object") return JSON.stringify(data, replacer, ws);
			else if (data && typeof data.toJSON == "function") return data.toJSON();
			else throw new Error("No JSON support available");
		}

		// str e' JSON valido
		// reviver e' una funzione simile a replacer sopra
		// Ritorna un valore JS valido, o spara un errore
		function parse(str, reviver) {
			if (typeof JSON == "object") return JSON.parse(str, reviver);
			else if (jQuery && typeof jQuery.parseJSON == "function") return jQuery.parseJSON(str);
			else if (typeof str.evalJSON == "function") return str.evalJSON(true);
			else throw new Error("No JSON support available");
		}

	})(utils.JSON);


	/* Handlers utili
	*
	* Vari handlers comodi da riciclare
	*/
	utils.handlers = utils.handlers || {};
	(function(exports) {

		exports.addFavorite = addFavorite;

		function addFavorite(e) {
			var title = document.title;
			var url   = window.location.href;

			if (window.sidebar && window.sidebar.addPanel) { // Mozilla
				window.sidebar.addPanel(title, url, '');
			}
			// Non funziona se e' incluso in uno script esterno e non sulla pagina
			//else if (window.external && window.external.addFavorite) { // IE
			//	window.external.addFavorite(url, title);
			//}
			else if (window.opera && window.print) { // Opera
				this.setAttribute('rel', 'sidebar');
				return false;
			}
			else { // Chrome, ad esempio
				utils.error(utils.t('Purtroppo il vostro browser non supporta questa funzionalità.\n\nChiudere questa finestra di dialogo e premere la combinazione di tasti "Ctrl + D" per aggiungere il segnalibro'));
			}
			return false;
		}

	})(utils.handlers);


})(foxgroup.utils);


/* つづく */

//
// minified es5-shim version 1.2.10 https://github.com/kriskowal/es5-shim
//

(function(n){"function"==typeof define?define(n):n()})(function(){function n(a){try{return Object.defineProperty(a,"sentinel",{}),"sentinel"in a}catch(d){}}if(!Function.prototype.bind)Function.prototype.bind=function(a){var d=this;if("function"!=typeof d)throw new TypeError;var b=p.call(arguments,1),c=function(){if(this instanceof c){var e=function(){};e.prototype=d.prototype;var e=new e,g=d.apply(e,b.concat(p.call(arguments)));return null!==g&&Object(g)===g?g:e}return d.apply(a,b.concat(p.call(arguments)))};
return c};var l=Function.prototype.call,f=Object.prototype,p=Array.prototype.slice,m=l.bind(f.toString),h=l.bind(f.hasOwnProperty),t,u,q,r,o;if(o=h(f,"__defineGetter__"))t=l.bind(f.__defineGetter__),u=l.bind(f.__defineSetter__),q=l.bind(f.__lookupGetter__),r=l.bind(f.__lookupSetter__);if(!Array.isArray)Array.isArray=function(a){return"[object Array]"==m(a)};if(!Array.prototype.forEach)Array.prototype.forEach=function(a,d){var b=i(this),c=0,e=b.length>>>0;if("[object Function]"!=m(a))throw new TypeError;
for(;c<e;)c in b&&a.call(d,b[c],c,b),c++};if(!Array.prototype.map)Array.prototype.map=function(a,d){var b=i(this),c=b.length>>>0,e=Array(c);if("[object Function]"!=m(a))throw new TypeError;for(var g=0;g<c;g++)g in b&&(e[g]=a.call(d,b[g],g,b));return e};if(!Array.prototype.filter)Array.prototype.filter=function(a,d){var b=i(this),c=b.length>>>0,e=[];if("[object Function]"!=m(a))throw new TypeError;for(var g=0;g<c;g++)g in b&&a.call(d,b[g],g,b)&&e.push(b[g]);return e};if(!Array.prototype.every)Array.prototype.every=
function(a,d){var b=i(this),c=b.length>>>0;if("[object Function]"!=m(a))throw new TypeError;for(var e=0;e<c;e++)if(e in b&&!a.call(d,b[e],e,b))return!1;return!0};if(!Array.prototype.some)Array.prototype.some=function(a,d){var b=i(this),c=b.length>>>0;if("[object Function]"!=m(a))throw new TypeError;for(var e=0;e<c;e++)if(e in b&&a.call(d,b[e],e,b))return!0;return!1};if(!Array.prototype.reduce)Array.prototype.reduce=function(a){var d=i(this),b=d.length>>>0;if("[object Function]"!=m(a))throw new TypeError;
if(!b&&1==arguments.length)throw new TypeError;var c=0,e;if(2<=arguments.length)e=arguments[1];else{do{if(c in d){e=d[c++];break}if(++c>=b)throw new TypeError;}while(1)}for(;c<b;c++)c in d&&(e=a.call(void 0,e,d[c],c,d));return e};if(!Array.prototype.reduceRight)Array.prototype.reduceRight=function(a){var d=i(this),b=d.length>>>0;if("[object Function]"!=m(a))throw new TypeError;if(!b&&1==arguments.length)throw new TypeError;var c,b=b-1;if(2<=arguments.length)c=arguments[1];else{do{if(b in d){c=d[b--];
break}if(0>--b)throw new TypeError;}while(1)}do b in this&&(c=a.call(void 0,c,d[b],b,d));while(b--);return c};if(!Array.prototype.indexOf)Array.prototype.indexOf=function(a){var d=i(this),b=d.length>>>0;if(!b)return-1;var c=0;1<arguments.length&&(c=v(arguments[1]));for(c=0<=c?c:Math.max(0,b+c);c<b;c++)if(c in d&&d[c]===a)return c;return-1};if(!Array.prototype.lastIndexOf)Array.prototype.lastIndexOf=function(a){var d=i(this),b=d.length>>>0;if(!b)return-1;var c=b-1;1<arguments.length&&(c=Math.min(c,
v(arguments[1])));for(c=0<=c?c:b-Math.abs(c);0<=c;c--)if(c in d&&a===d[c])return c;return-1};if(!Object.getPrototypeOf)Object.getPrototypeOf=function(a){return a.__proto__||(a.constructor?a.constructor.prototype:f)};if(!Object.getOwnPropertyDescriptor)Object.getOwnPropertyDescriptor=function(a,d){if("object"!=typeof a&&"function"!=typeof a||null===a)throw new TypeError("Object.getOwnPropertyDescriptor called on a non-object: "+a);if(h(a,d)){var b,c,e;b={enumerable:!0,configurable:!0};if(o){var g=
a.__proto__;a.__proto__=f;c=q(a,d);e=r(a,d);a.__proto__=g;if(c||e){if(c)b.get=c;if(e)b.set=e;return b}}b.value=a[d];return b}};if(!Object.getOwnPropertyNames)Object.getOwnPropertyNames=function(a){return Object.keys(a)};if(!Object.create)Object.create=function(a,d){var b;if(null===a)b={__proto__:null};else{if("object"!=typeof a)throw new TypeError("typeof prototype["+typeof a+"] != 'object'");b=function(){};b.prototype=a;b=new b;b.__proto__=a}void 0!==d&&Object.defineProperties(b,d);return b};if(Object.defineProperty){var l=
n({}),y="undefined"==typeof document||n(document.createElement("div"));if(!l||!y)var s=Object.defineProperty}if(!Object.defineProperty||s)Object.defineProperty=function(a,d,b){if("object"!=typeof a&&"function"!=typeof a||null===a)throw new TypeError("Object.defineProperty called on non-object: "+a);if("object"!=typeof b&&"function"!=typeof b||null===b)throw new TypeError("Property description must be an object: "+b);if(s)try{return s.call(Object,a,d,b)}catch(c){}if(h(b,"value"))if(o&&(q(a,d)||r(a,
d))){var e=a.__proto__;a.__proto__=f;delete a[d];a[d]=b.value;a.__proto__=e}else a[d]=b.value;else{if(!o)throw new TypeError("getters & setters can not be defined on this javascript engine");h(b,"get")&&t(a,d,b.get);h(b,"set")&&u(a,d,b.set)}return a};if(!Object.defineProperties)Object.defineProperties=function(a,d){for(var b in d)h(d,b)&&Object.defineProperty(a,b,d[b]);return a};if(!Object.seal)Object.seal=function(a){return a};if(!Object.freeze)Object.freeze=function(a){return a};try{Object.freeze(function(){})}catch(D){Object.freeze=
function(a){return function(d){return"function"==typeof d?d:a(d)}}(Object.freeze)}if(!Object.preventExtensions)Object.preventExtensions=function(a){return a};if(!Object.isSealed)Object.isSealed=function(){return!1};if(!Object.isFrozen)Object.isFrozen=function(){return!1};if(!Object.isExtensible)Object.isExtensible=function(a){if(Object(a)===a)throw new TypeError;for(var d="";h(a,d);)d+="?";a[d]=!0;var b=h(a,d);delete a[d];return b};if(!Object.keys){var w=!0,x="toString,toLocaleString,valueOf,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,constructor".split(","),
z=x.length,j;for(j in{toString:null})w=!1;Object.keys=function(a){if("object"!=typeof a&&"function"!=typeof a||null===a)throw new TypeError("Object.keys called on a non-object");var d=[],b;for(b in a)h(a,b)&&d.push(b);if(w)for(b=0;b<z;b++){var c=x[b];h(a,c)&&d.push(c)}return d}}if(!Date.prototype.toISOString||-1===(new Date(-621987552E5)).toISOString().indexOf("-000001"))Date.prototype.toISOString=function(){var a,d,b,c;if(!isFinite(this))throw new RangeError;a=[this.getUTCMonth()+1,this.getUTCDate(),
this.getUTCHours(),this.getUTCMinutes(),this.getUTCSeconds()];c=this.getUTCFullYear();c=(0>c?"-":9999<c?"+":"")+("00000"+Math.abs(c)).slice(0<=c&&9999>=c?-4:-6);for(d=a.length;d--;)b=a[d],10>b&&(a[d]="0"+b);return c+"-"+a.slice(0,2).join("-")+"T"+a.slice(2).join(":")+"."+("000"+this.getUTCMilliseconds()).slice(-3)+"Z"};if(!Date.now)Date.now=function(){return(new Date).getTime()};if(!Date.prototype.toJSON)Date.prototype.toJSON=function(){if("function"!=typeof this.toISOString)throw new TypeError;return this.toISOString()};
if(!Date.parse||864E13!==Date.parse("+275760-09-13T00:00:00.000Z"))Date=function(a){var d=function g(b,d,c,f,h,i,j){var k=arguments.length;return this instanceof a?(k=1==k&&""+b===b?new a(g.parse(b)):7<=k?new a(b,d,c,f,h,i,j):6<=k?new a(b,d,c,f,h,i):5<=k?new a(b,d,c,f,h):4<=k?new a(b,d,c,f):3<=k?new a(b,d,c):2<=k?new a(b,d):1<=k?new a(b):new a,k.constructor=g,k):a.apply(this,arguments)},b=RegExp("^(\\d{4}|[+-]\\d{6})(?:-(\\d{2})(?:-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{3}))?)?(?:Z|(?:([-+])(\\d{2}):(\\d{2})))?)?)?)?$"),
c;for(c in a)d[c]=a[c];d.now=a.now;d.UTC=a.UTC;d.prototype=a.prototype;d.prototype.constructor=d;d.parse=function(d){var c=b.exec(d);if(c){c.shift();for(var f=1;7>f;f++)c[f]=+(c[f]||(3>f?1:0)),1==f&&c[f]--;var h=+c.pop(),i=+c.pop(),j=c.pop(),f=0;if(j){if(23<i||59<h)return NaN;f=6E4*(60*i+h)*("+"==j?-1:1)}h=+c[0];return 0<=h&&99>=h?(c[0]=h+400,a.UTC.apply(this,c)+f-126227808E5):a.UTC.apply(this,c)+f}return a.parse.apply(this,arguments)};return d}(Date);j="\t\n\u000b\u000c\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";
if(!String.prototype.trim||j.trim()){j="["+j+"]";var A=RegExp("^"+j+j+"*"),B=RegExp(j+j+"*$");String.prototype.trim=function(){return(""+this).replace(A,"").replace(B,"")}}var v=function(a){a=+a;a!==a?a=0:0!==a&&a!==1/0&&a!==-(1/0)&&(a=(0<a||-1)*Math.floor(Math.abs(a)));return a},C="a"!="a"[0],i=function(a){if(null==a)throw new TypeError;return C&&"string"==typeof a&&a?a.split(""):Object(a)}});

