function addQueryParameter(url, name, value) {
	if(url.indexOf("?") > -1) url += "&";
	else url += "?";
	
	url += name + "=" + value;
	
	return url;
}

function replaceQueryParameter(url, name, value) {
	var expr = new RegExp(name + "=\\w*", "g");
	url = url.replace(expr, "");
	
	url = url.replace("&&", "&");
	url = url.replace("?&", "?");
	url = trim(url, "&");
	url = trim(url, "\\?");
	
	url = addQueryParameter(url, name, value)
	
	return url;
}

function popup(url, width, height, name, resizable, scrollbars, centered) {
	if(!resizable) resizable = 0;
	if(!scrollbars) scrollbars = 0;
	
	var properties = [
		"toolbar = 0",
		"location = 0",
		"directories = 0",
		"status = 0",
		"menubar = 0",
		"scrollbars = " + scrollbars,
		"resizable = " + resizable,
		"width = " + width,
		"height = " + height
	]; 
	
	if(centered) {
		var x = (screen.availWidth - width) / 2;
		var y = (screen.availHeight - height) / 2;
		
		if(x < 0) x = 0;
		if(y < 0) y = 0;
		
		properties.push("screenX = " + x);
		properties.push("left = " + x);
		properties.push("screenY = " + y);
		properties.push("top = " + y);
	}
	
	return window.open(url, name, properties.join(", "));
}

function pad(what, length, char) {
	what = String(what);
	var toAdd = length - what.length;
	
	if(char == undefined || char == null) char = " ";
	for(var i = 0; i < toAdd; i++) what = char + what;
	
	return what;
}

function weekDayName(day) {
	return ["domenica", "luned&igrave;", "marted&igrave;", "mercoled&igrave;", "gioved&igrave;", "venerd&igrave;", "sabato"][day];
}

function weekDayShort(day) {
	return ["dom", "lun", "mar", "mer", "gio", "ven", "sab"][day];
}

function monthName(month) {
	return ["gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"][month];
}

function monthShort(month) {
	return ["gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic"][month];
}

function dateFromFormat(format, date) {
	var d = 0, m = 0, Y = 0, H = 0, i = 0, s = 0;
	
	for(var k = 0; k < format.length; k++) {
		switch(format.charAt(k)) {
			case "d": d = parseInt(date.substr(0, 2), 10); date = date.substr(2); break;
			case "m": m = parseInt(date.substr(0, 2), 10) - 1; date = date.substr(2); break;
			case "Y": Y = parseInt(date.substr(0, 4), 10); date = date.substr(4); break;
			case "H": H = parseInt(date.substr(0, 2), 10); date = date.substr(2); break;
			case "i": i = parseInt(date.substr(0, 2), 10); date = date.substr(2); break;
			case "s": s = parseInt(date.substr(0, 2), 10); date = date.substr(2); break;
			default: date = date.substr(1);
		}
	}
	
	return new Date(Y, m, d, H, i, s);
}

function dateFormat(format, date) {
	var formatted = "";
	
	for(var i = 0; i < format.length; i++) {
		switch(format.charAt(i)) {
			case "Y": formatted += pad(date.getFullYear(), 4, "0"); break;
			case "y": formatted += pad(String(new Date().getFullYear()).substr(-2), 2, "0"); break;
			
			case "m": formatted += pad(date.getMonth() + 1, 2, "0"); break;
			case "m": formatted += pad(date.getMonth() + 1, 2, "0"); break;
			case "n": formatted += (date.getMonth() + 1); break;
			//.replace("t", date.getMaxDays())
			case "F": formatted += monthName(date.getMonth()); break;
			case "M": formatted += monthShort(date.getMonth()); break;
			
			//.replace("W", date.getWeekNumber())
			
			case "d": formatted += pad(date.getDate(), 2, "0"); break;
			case "j": formatted += date.getDate(); break;
			case "w": formatted += date.getDay(); break;
			case "N": formatted += date.getDay() ? date.getDay() : 7; break;
			case "D": formatted += weekDayShort(date.getDay()); break;
			case "l": formatted += weekDayName(date.getDay()); break;
			
			case "H": formatted += pad(date.getHours(), 2, "0"); break;
			case "G": formatted += date.getHours(); break;
			case "i": formatted += pad(date.getMinutes(), 2, "0"); break;
			case "s": formatted += pad(date.getSeconds(), 2, "0"); break;
			case "u": formatted += pad(date.getMilliseconds(), 4, "0"); break;
			
			default:
				formatted += format.charAt(i);
		}
	}
	
	return formatted;
}

function dateAdd(date, what) {
	var d = date.getDate(), 
		m = date.getMonth(), 
		Y = date.getFullYear(), 
		H = date.getHours(), 
		i = date.getMinutes(), 
		s = date.getSeconds();
	
	if(what.length == arguments.length - 2) {
		for(var k = 0; k < what.length; k++) {
			var howMany = parseInt(arguments[k + 2], 10);

			switch(what.charAt(k)) {
				case "d": d += howMany; break;
				case "m": m += howMany; break;
				case "Y": Y += howMany; break;
				case "H": H += howMany; break;
				case "i": i += howMany; break;
				case "s": s += howMany; break;
			}
		}
	}
	
	return new Date(Y, m, d, H, i, s);
}

function addEvent(element, event, action) {
	if(element.addEventListener) element.addEventListener(event, action, false);
	else if(element.attachEvent) element.attachEvent("on" + event, action);
}

function removeEvent(element, event, action) {
	if(element.removeEventListener) element.removeEventListener(event, action, true);
	else if(element.detachEvent) element.detachEvent("on" + event, action);
}

function stopEvent(event) {
	event.cancelBubble = true;
	event.returnValue = false;
	
	if(event.stopPropagation) {
		event.stopPropagation();
		event.preventDefault();
	}
}

function target(event) {
	if(event.target) return event.target;
	else if(event.srcElement) return event.srcElement;
}

function fireEvent(element, event, params) {
	if (document.createEventObject) {
		var e = document.createEventObject();
		
		return element.fireEvent("on" + event, e)
	} else if(document.createEvent) {
		var e = null;
		
		switch(event) {
			case "abort": case "blur": case "change": case "error": case "focus": case "load": case "reset": case "resize": case "scroll": case "select": case "submit": case "unload":
				e = document.createEvent("HTMLEvents");
				e.initEvent(event, true, true);
				break;
			case "keydown": case "keypress": case "keyup":
				if(window.KeyEvent) {
					e = document.createEvent("KeyEvents");
					e.initKeyEvent(event, true, true);
					break;
				}
			case "DOMActivate": case "DOMFocusIn": case "DOMFocusOut":
				e = document.createEvent("UIEvents");
				e.initUIEvent(event, true, true);
				break;
			case "click": case "mousedown": case "mousemove": case "mouseout": case "mouseover": case "mouseup":
				e = document.createEvent("MouseEvents");
				e.initMouseEvent(event, true, true);
				break;
			case "DOMAttrModified": case "DOMNodeInserted": case "DOMNodeRemoved": case "DOMCharacterDataModified": case "DOMNodeInsertedIntoDocument": case "DOMNodeRemovedFromDocument": case "DOMSubtreeModified":
				e = document.createEvent("MutationEvents");
				e.initMutationEvent(event, true, true);
				break;
			default: return false;
		}
		
		return !element.dispatchEvent(e);
	}
}

function trim(string, what) {
	var trimmed = string;
	if(!what) what = " ";

	var regExLeft = new RegExp("^(" + what + ")+");
	//var regExLeft = eval("/^(" + what + ")+/");
	var regExRight = new RegExp("(" + what + ")+$");
	//var regExRight = eval("/(" + what + ")+$/");
	
	trimmed = trimmed.replace(regExLeft, "");
	trimmed = trimmed.replace(regExRight, "");

	return trimmed;
}

function getScrollXY() {
	var scrOfX = 0, scrOfY = 0;
	
	if( typeof( window.pageYOffset ) == 'number' ) {
		//Netscape compliant
		scrOfY = window.pageYOffset;
		scrOfX = window.pageXOffset;
	} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
		//DOM compliant
		scrOfY = document.body.scrollTop;
		scrOfX = document.body.scrollLeft;
	} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
		//IE6 standards compliant mode
		scrOfY = document.documentElement.scrollTop;
		scrOfX = document.documentElement.scrollLeft;
	}
	
	return {x: scrOfX, y: scrOfY};
}

function setCookie(name, value, expire, path) {
	var cookie = name + "=" + value;
	
	if(expire) {
		var date = new Date();
		date.setTime(date.getTime() + (expire * 24 * 60 * 60 * 1000));
		
		cookie = cookie + "; expires=" + date.toGMTString();
	}
	if(path) cookie = cookie + "; path=" + path;
	
	document.cookie = cookie;
}

function getCookie(name) {
	var cookies = document.cookie.split(";");
	for(cookie in cookies) {
		var splittedCookie = trim(cookies[cookie]).split("=");
		var cookieName = splittedCookie[0];
		var cookieValue = splittedCookie[1];
		
		if(cookieName == name) return cookieValue;
	}

	return false;
}

function urlencode(str) {
	str = (str+'').toString();
	return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+').replace(/~/g, '%7E');
}

function AjaxRequest(method, url, params, callback, failure) {
	var _req;
	var _params = new Array();
	var _send = "";
	var _method = "";
	var _url = "";
	
	if(params) {
		for(var k in params) {
			if(typeof params[k] == "string" || typeof params[k] == "number") _params.push(k + "=" + urlencode(params[k]));
			else if(params[k] instanceof Array) {
				var array = params[k];
				for(var i = 0; i < array.length; i++) {
					if(typeof array[i] == "string" || typeof array[i] == "number") _params.push(k + "=" + urlencode(array[i]));
					else throw(new Error("Parametri array troppo in profondit�"));
				}
			} else throw(new Error("Parametri non validi. Usa la forma {param1: value1, param2: value2} con value = stringa, numero o array. params['" + k + "'] = " + typeof(params[k])));
		}
	}

	if(_params.length) _params = _params.join("&");
	else _params = "";

	if(typeof url != "string") throw(new Error("Url non valido"));
	else _url = url;
	
	if(method.toLowerCase() == "get") {
		_method = "get";
		
		if(_params) _url += "?" + _params;
	} else if(method.toLowerCase() == "post") {
		_method = "post";
		_send = _params;
	} else throw(new Error("Metodo non valido"));
	
	function _processReqChange() {
		if (_req.readyState == 4) {
			if (_req.status == 200) {
				if(callback) {
				   if(typeof callback == "function") callback(_req.responseText);
				   else throw(new Error("Funzione callback non valida"));
				}
			} else {
				if(failure) {
					if(typeof failure == "function") failure();
					else throw(new Error("Funzione failure non valida"));
				}
			}
		}
	}

	if(window.XMLHttpRequest && !(window.ActiveXObject)) {
		try {
			_req = new XMLHttpRequest();
		} catch(e) {
			_req = false;
		}
	} else if(window.ActiveXObject) {
		try {
			_req = new ActiveXObject("Msxml2.XMLHTTP");
		} catch(e) {
			try {
				_req = new ActiveXObject("Microsoft.XMLHTTP");
			} catch(e) {
				_req = false;
			}
		}
	}

	this.send = function() {
		if(_req) {
			_req.onreadystatechange = _processReqChange;
			_req.open(_method, _url, true);
			
			if(_method == "post") {
				_req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
				_req.setRequestHeader("Content-length", _send.length);
				_req.setRequestHeader("Connection", "close");
			}
			
			_req.send(_send);
		}
	};
}

function sprintf ( ) {
    var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuidfegEG])/g;
    var a = arguments, i = 0, format = a[i++];

    var pad = function (str, len, chr, leftJustify) {
        if (!chr) chr = ' ';
        var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
        return leftJustify ? str + padding : padding + str;
    };

    var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {
        var diff = minWidth - value.length;
        if (diff > 0) {
            if (leftJustify || !zeroPad) value = pad(value, minWidth, customPadChar, leftJustify);
            else value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
        }
        
        return value;
    };

    var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
        var number = value >>> 0;
        
        prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || '';
        value = prefix + pad(number.toString(base), precision || 0, '0', false);
        
        return justify(value, prefix, leftJustify, minWidth, zeroPad);
    };

    var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) {
        if (precision != null) value = value.slice(0, precision);
        
        return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
    };

    var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) {
        var number;
        var prefix;
        var method;
        var textTransform;
        var value;

        if (substring == '%%') return '%';

        var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, customPadChar = ' ';
        var flagsl = flags.length;
        for (var j = 0; flags && j < flagsl; j++) {
            switch (flags.charAt(j)) {
                case ' ': positivePrefix = ' '; break;
                case '+': positivePrefix = '+'; break;
                case '-': leftJustify = true; break;
                case "'": customPadChar = flags.charAt(j+1); break;
                case '0': zeroPad = true; break;
                case '#': prefixBaseX = true; break;
            }
        }

        if (!minWidth) minWidth = 0;
        else if (minWidth == '*') minWidth = +a[i++];
        else if (minWidth.charAt(0) == '*') minWidth = +a[minWidth.slice(1, -1)];
        else minWidth = +minWidth;

        if(minWidth < 0) {
            minWidth = -minWidth;
            leftJustify = true;
        }

        if(!isFinite(minWidth)) throw new Error('sprintf: (minimum-)width must be finite');

        if (!precision) precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined;
        else if (precision == '*') precision = +a[i++];
        else if (precision.charAt(0) == '*') precision = +a[precision.slice(1, -1)];
        else precision = +precision;

        value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];

        switch (type) {
            case 's': return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
            case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
            case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();
            case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'i':
            case 'd':
                number = parseInt(+value, 10);
                prefix = number < 0 ? '-' : positivePrefix;
                value = prefix + pad(String(Math.abs(number)), precision, '0', false);
                return justify(value, prefix, leftJustify, minWidth, zeroPad);
            case 'e':
            case 'E':
            case 'f':
            case 'F':
            case 'g':
            case 'G':
                number = +value;
                prefix = number < 0 ? '-' : positivePrefix;
                method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
                textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
                value = prefix + Math.abs(number)[method](precision);
                return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
            default: return substring;
        }
    };

    return format.replace(regex, doFormat);
}