﻿
/*************************\
* ITALCOM S.p.A.          *
* Library: Core.js        *
* Version: 1.0            *
* Require: none           *
\*************************/

// CLIENT SERVER SCRIPT: check for Browser.serverSide !!


//=====
Browser
=//====
{}
try
{
	Browser.serverSide = window == null;
	Browser.ie = window != null && window.ActiveXObject != null;
	Browser.ie7 = Browser.ie && window.XMLHttpRequest;
	Browser.gecko = document != null && document.getBoxObjectFor != null;
}
catch (e)
{
	Browser.serverSide = true;
	Browser.ie = false;
	Browser.ie7 = false;
	Browser.gecko = false;
}
// Optimization for Internet Explorer
if (Browser.ie)
	try {document.execCommand("BackgroundImageCache", false, true);} catch(e){};


//======
Language
=//=====
{
	// Le label nei vari linguaggi sono contenute nei file "/knos/language/it.js", "/knos/language/en.js", ...
	// Per l'utilizzo lato server invece si caricano i file "/language/it.asp", "/language via ServerCache
	// Language.en = { "key" : "label", ...}
	
	label : function (key, obj_args, defaultResult)
	{
		if (arguments.length < 3) defaultResult = "(?)"+key;
	
		var result;
		var s = null;				
		
		// ricerca della label
		try
		{
			if (IsEmpty(AspDefaultInterfaceLanguage))
				AspDefaultInterfaceLanguage = null;
		}
		catch(e)
		{
			if (Browser.serverSide)
				GetInterfaceLanguage();
			else
			{
				var q = new CQueryString();
				AspDefaultInterfaceLanguage = "it";
				AspInterfaceLanguage = q.getArg("l", AspDefaultInterfaceLanguage);
			}
		}
		s = this.getLabel(AspInterfaceLanguage, key);
		if (s == null)
		    s = this.getLabel(AspDefaultInterfaceLanguage, key);
		
		// restituzione della label
		if (s == null)
			result = defaultResult;
		else
		{
			if (IsStrictObject(obj_args))
				result = StringFormat(s, obj_args);
			else
			{
				var args = [];
				for (var i=0; i<arguments.length; i++)
					args.push(arguments[i]);
				result = StringFormat(s, args);
			}
		}
		return result;
	},

	append : function (idLanguage, o){ for (var i in o) Language[idLanguage][i] = o[i] },
	
	getLabel: function(idLanguage, key)
	{
	    if (idLanguage == null || key == null)
	        return null;
	
		if (Browser.serverSide)
			return ServerCache.getValue("Language_"+idLanguage, key, null);
		else
		{
		    if (Language[idLanguage] == null)
		        return null;
		    else
		        return Language[idLanguage][key];
		}
	}
}


//==
List
=//=
function (item_array)
{
	if (TypeOf(item_array) == "array")
		this.list = item_array;
	else
		this.list = [item_array];
	return this.list;
}


//===
Parse
=//==
{
	int : function (v, def, radix)
	{
		if (radix==null) radix = 10;
		var result = parseInt(v, radix);
		if (isNaN(result) && arguments.length > 1)
			return def;
		return result;
	},
	float : function(v, def)
	{
		var result = parseFloat(v)
		if (isNaN(result) && arguments.length > 1)
			return def;
		return result;
	}
}


//=========
ServerCache
=//========
{
    object : {},		// cache volatile di secondo livello per this.getObject al momento rivalutata ogni volta

	status : function ()
	{
		var result = [];
	 	var meta = Application("ServerCache");
		if (meta == null)	 	
			return result;
		var count, objectList = (new VBArray(meta.Object.Keys())).toArray();
		for (var i in objectList)
		{
			try { count = meta.Object(objectList[i]).Count }catch(e){ count = 0 }
			result.push(
			{
				 name : objectList[i]
				,count : count
			});
		}				
		return result;
	},

	clear : function (objectName)
	{
		try
		{
			Application.Lock;
		 	var meta = Application("ServerCache");
			if (meta == null)
				 return;
			var objectList = (new VBArray(meta.Object.Keys())).toArray();
			for (var i in objectList)
			{
				if (objectName == null || objectName == i)
				{
					meta.Object(objectList[i]).RemoveAll();
					meta.Object.remove(objectList[i]);
				}
			}
		}
		catch(e){ Response.Write(e) }
		finally { Application.Unlock }
	},
	
	getAll : function (objectName)
	{
		var result = null;
		try
		{
			Application.Lock;
			var cache = this.load(objectName);
		 	var meta = Application("ServerCache");
	  		var keyList = (new VBArray(meta.Object(objectName).Keys())).toArray();
			for (var j in keyList)
			{
			    if (result == null)
			        result = {};
			    result[keyList[j]] = meta.Object(objectName).item(keyList[j]);
	        }
		}
		catch(e){}
		finally { Application.Unlock }
		return result;
	},
	
	getValue : function (objectName, keyName, defaultResult)
	{
		if (IsEmpty(defaultResult)) defaultResult = null;
	    if (IsEmpty(objectName))
	        return defaultResult;
	    var cache = this.load(objectName, keyName);
	    if (cache != null)
	    	return cache.item(keyName);
	    else
			return defaultResult;
	},
	
	setValue : function (objectName, keyName, value)
	{
		try
		{
			Application.Lock;
			var cache = this.loadObject(objectName);
			cache.item(keyName) = value;
			return value;
		}
		catch(e){}
		finally { Application.Unlock }
	},

	getObject : function (objectName, keyName, defaultResult)
	{
		if (IsEmpty(defaultResult)) defaultResult = null;
		var i, cache, result;
		if (IsEmpty(keyName))
		{
			result = this.getAll(objectName);
			if (result == null)
				return defaultResult;				
			this.object[objectName] = result;
			for (i in this.object[objectName])
			{
				if (this.object[objectName][i].charAt(0) == "{")
					try { eval("result="+this.object[objectName][i]) } catch(e){ result = null }
				if (result != null)
					this.object[objectName][i] = result;
			}
			return this.object[objectName];
		}
		else
		{
		    result = this.getValue(objectName, keyName);
			if (result == null)
				return defaultResult;
			if (result.charAt(0) == "{")
				try { eval("result="+result) } catch(e){ result = null }
			if (result == null)
				return defaultResult;
			return this.object[objectName][keyName] = result;
	    }
	},
	
	loadObject : function (objectName, bAdd)
	{
		if (bAdd != false) bAdd = true;
	 	var meta = Application("ServerCache");
		if (meta == null)
		{
			 meta = Application("ServerCache") = Server.CreateObject("ICServerUtil.Object");
			 meta.AddObject("CacheInfo", "Scripting.Dictionary");
		}
		var cache = null;
		if (!meta.Object.Exists(objectName) || meta.Object(objectName) == null)
		{
			if (bAdd)
				cache = meta.AddObject(objectName, "Scripting.Dictionary");
		}
		else
			cache = meta.Object(objectName);
		return cache;
	},

	load : function (objectName, keyName)
	{
		if (IsEmpty(keyName)) keyName = "";
		var cache = null;		
		try
		{
			Application.Lock;		
		    cache = this.loadObject(objectName);
			var info = ServerCache.loadObject("CacheInfo");
			var bLoaded = false;
			switch (info.item(objectName))
			{
				case "object": try { if (cache.Count > 0) bLoaded = true; }catch(e){}; break;
				case "key": if (keyName != null && cache.Exists(keyName)) bLoaded = true; break;
			}
			if (!bLoaded)
		    {
                Application("AspParam_objectName") = objectName;
                Application("AspParam_keyName") = keyName;
			    Server.Execute("/knos/system/Cache.asp");
		    }
		}
		catch(e){ cache = null }
		finally	{ Application.Unlock }
	    return cache;
	},
	
	loadLanguage : function (idLanguage)
	{
	    if (idLanguage == null)
	        return;
		var objectName = "Language_"+idLanguage
		var cache = this.loadObject(objectName);
		var label = Language[idLanguage];
		localApplication = Server.CreateObject(ApplicationProgID);
		localApplication.Context.ASPRequest = Request;
		for (var key in label)
		{
			cache.item(key) = label[key];
			// Le stringhe di log utilizzate dal filtro devono finire in System_Global
			switch (key)
			{
				case "log: 9":  // Log di accesso a documento da memorizzare anche su Global
				case "log: 21": // accesso a documento negato
				case "log: 22": // accesso a documento negato per utente non loggato
				case "log: 14": // login
				case "log: 23": // login fallito
				case "log: 24": // login con autenticazione integrata
					try { localApplication.setGlobalString(key+"_"+idLanguage, label[key]) } catch(e) {}
		    	    break;
			    default:
			}
		}
		localApplication.Dispose();
		if (Request.QueryString("dump") == 1)
		{
			var html = new CString();	
			html.append('<table cellpadding="0" cellspacing="0" border="1">');
			for (var i in Language[idLanguage])
			{
				html.append('</tr><td>'+i+'</td><td>'+Language[idLanguage][i]+'</td></tr>');
			}
			html.append('</table>');
			Response.Write(html);
		}
	},

	languageList : function (interface_object /* "interface" | "object" | null */)
	{
		if (IsEmpty(interface_object)) interface_object = "";
		interface_object = (""+interface_object).toLowerCase();
		var result = {};
		var i, list = this.getObject("Language", null, {});
		for (i in list)
		{
			switch (interface_object)
			{
				case "interface": if (list[i].FlagInterfaceLanguage != "1") continue; break;
				case "object": if (list[i].FlagObjectLanguage != "1") continue; break;
			}
			result[i] = this.getObject("Language", i, {});
		}
		return result;
	}
}


/* Definitions */
function EmptyFunction(){};
function NullFunction(){return null};

/*** IS FUNCTIONS ***/

var undefined;
function IsUndefined(v) { return (v == undefined); }
function IsEmptyString(v) { return (v == undefined || v === ""); }
//function IsEmpty(v) { try {	return (v == undefined || v == null || v === ""); } catch (e) {	return false; } }
function IsEmpty(o)
{
	if (o==null || o==="")
		return true;
	if (IsArray(o))
	{
		for(var i in o)
			return false;
		return true;
	}
	return false;
}
function IsBoolean(o){return typeof o=="boolean"}
function IsNumber(o){return typeof o=="number"}
function IsString(o){return typeof o=="string"}
function IsFunction(o){return typeof o=="function"}
function IsDate(o){return o instanceof Date}
function IsArray(o){return o instanceof Array}
function IsRegExp(o){return o instanceof RegExp}
function IsObject(o){return o != null && typeof o == "object"}
function IsStrictObject(o){return TypeOf(o) == "object"}
function TypeOf(o)
{
	if (o==null)
		return "null";
	var result = typeof o;
	if (result == "object")
	{
		if (o instanceof RegExp) return "regexp";
		if (o instanceof Date) return "date";
		if (o instanceof Array) return "array";
	}
	return result;
}
function IsInList(strItem, strListArray, sep)
{
	try
	{
		if (IsEmpty(strItem)) return false;
		if (IsEmpty(strListArray)) return false;
		if (IsEmpty(sep)) sep = ",";
		var l = IsArray(strListArray) ? strListArray : strListArray.toString().split(sep);
		strItem = Trim(strItem.toString());
		for (var i=0; i<l.length; i++)
			if (strItem == Trim(l[i].toString()))
				return true;
	}
	catch(e){Dump(e)}
	return false;
}

//=========================
// KnoS attribute DataType
//=========================
function KnosDataTypeName(intDataType)
{
	switch (ParseInt(intDataType, 0))
	{
		case 1: return "Boolean";
		case 2: return "DateTime";
		case 3: return "Integer";
		case 4: return "Decimal";
		case 5: return "Varchar";
		case 6: return "Text";
		case 7: return "Enum";
		case 10: return "External"; // obsoleto
		case 11: return "Catalog"; // sperimentale, incompleto
		case 20: return "Object"; // linkage a pubblicazioni
	}
	return null;
}
function KnosDataTypeValue(strDataType)
{
	switch (strDataType)
	{
		case "Boolean": return 1;
		case "DateTime": return 2;
		case "Integer": return 3;
		case "Decimal": return 4;
		case "Varchar": return 5;
		case "Text": return 6;
		case "Enum": return 7;
		case "External": return 10; // obsoleto
		case "Catalog": return 11; // sperimentale, incompleto
		case "Object": return 20; // linkage a pubblicazioni
	}
	return null;
}
var KnosSystemIdAttr = // Usato solo per le traduzioni parte da -1000 per far spazio ai campi calcolati
{
	 "IdObject":	-1001
	,"IdStatus":	-1002
	,"StatusName":	-1003
	,"IdClass":		-1004
	,"ClassName":	-1005
	,"IdLanguage":	-1006
	,"Title":		-1007
	,"EventText":	-1008
	,"FlagFeedback":-1009
	,"FlagConfirm":	-1010
}
function KnosColumnNameDataType(colName)
{
	var prefix = colName.slice(0, colName.indexOf("_"));
	switch (prefix)
	{
		case "smallint": return 1;
		case "datetime": return 2;
		case "int": return 3;
		case "float": return 4;
		case "varchar": return 5;
		case "text": return 6;
		case "enum": return 7;
		case "object": return 20
		default: return null;
	}
}

//==============
// CMessageList
//==============
// Esempio: ml = new CMessageList({key: {id: 1, msg: "message"}})
function CMessageList(entryList)
{
	if (IsEmpty(entryList)) entryList = {};

	this.all = entryList;
	return this;
}

CMessageList.prototype.isEmpty
=//===========================
function()
{
	for(var i in this.all) 
		return true;
	return false;
}

CMessageList.prototype.addMsgKey
=//=============================
// Es: add({key1: {id: 1, msg: ""}, key2: {id: 2, msg: ""}}, ["key1", "key2"])
function (messageList, keyList)
{
	var i;
	// Se non è specificato keyList si aggiungono tutti
	if (keyList==null)
	{
		for (i in messageList)
			this.all[i] = messageList[i];
	}
	else
	{
		for (var i=0; i<keyList.length; i++)
		this.all[keyList[i]] = messageList[keyList[i]];
	}
}

CMessageList.prototype.addMsgId
=//============================
// Es: add({key1: {id: 1, msg: ""}, key2: {id: 2, msg: ""}}, "1,2")
function (messageList, idList)
{
	// Se non è specificato keyList si aggiungono tutti
	for (var i in messageList)
		if (idList == null || IsInList(messageList[i].id, idList))
			this.all[i] = messageList[i];
}

CMessageList.prototype.getIdList
=//=============================
// Restituisce l'elenco degli id come stringa di interi separati da virgola es. "1,2"
function ()
{
	if (this.all.length == 0)
		return "";
	var result = [];
	for (var i in this.all)
		result[result.length] = this.all[i].id;
	return result.toString();
}

CMessageList.prototype.getMsgList
=//==============================
// Restituisce l'elenco dei messaggi come stringhe separate da \r
function (idList)
{
	if (this.all.length == 0)
		return "";
	var result = "";
	// Se non è specificato keyList si restituiscono tutti
	for (var i in this.all)
	{
		if (idList == null || IsInList(this.all[i].id, idList))
			result += this.all[i].msg + "\r";
	}
	return result;
}

function StringFormat(str, obj_args)
{
	// Es.:     StringFormat("{0}={1}", "v", 1) -> "v=1"
	// Oppure:  StringFormat("{a}={b}", {a: "v", b: 1}) -> "v=1"
	var arg = arguments;
	if (IsStrictObject(obj_args))
	{
		for (var i in obj_args)
			str = str.replace(new RegExp("{"+i+"}", "gi"), obj_args[i]);
		return str;
	}
	if (IsArray(obj_args))
		arg = obj_args;
	return str.replace(StringFormat.regExp, function($0, $1){return arg[1+parseInt($1)]});
}
StringFormat.regExp = /\{(\d+)\}/g;

function StringEscape(str, quotEscape)
{
	if (quotEscape == null) quotEscape = '\"'; //in xml è utile StringEscape(str, "&quot;")
	return '"'+(''+str).replace('"', quotEscape)+'"';
}

function StringCutter(str, sep, option)
{
	// Es.: StringCutter("abcdef", "cd", option)
	// option=0	-> ["abcd", "ef"] separatore appeso al primo
	// option=1 -> ["ab", "cdef"] separatore prefisso al secondo (default)
	// option=2 -> ["ab", "ef"]   separatore eliminato
	// Se sep non  presente si ritorna sempre [str, ""]
	if (option == null) option = 1
	
	var p = str.indexOf(sep);
	if (p>=0)
	{
		switch (option)
		{
			case 0:
				return [str.slice(0, p+sep.length), str.slice(p+sep.length)];
			case 2:
				return [str.slice(0, p), str.slice(p+sep.length)];
			case 1:
			default:
				return [str.slice(0, p), str.slice(p)];
		}
	}
	else
		return [str,""];
}

/* Macros */
function MacroReplace(str, list, flag)
{
	// Es.: MacroReplace(HTML, [["#id#", this.id], ["#cls#", this.cls]], "i")
	if (flag == null) flag = "g";
	var re = "("+ list[0][0] +")";
	var val = [];
	val[list[0][0]] = list[0][1]
	for (var i=1; i<list.length; i++)
	{
		re += "|("+ list[i][0] +")";
		val[list[i][0]] = list[i][1]
	}
	re = new RegExp(re, flag);
	return str.replace(re, function($0){return val[$0]});
}

function ErrorAlert(e, fName)
{
	try
	{
		var msg = "";
		if ( arguments.length > 1 )
			msg += fName;
		msg += "\n"+ e.name +" "+ e.number;
		msg += "\n"+ e.description;
		if ( e.description != e.message )
			msg += "\n"+ e.message;
		window.alert(msg);		
	}
	catch(e)
	{	
		window.alert(Language.label("Errore sconosciuto"));
	}
}

function GetLicense(drvpath)
{
	var result = null;
	try
	{
		var fso, d, s, t;
		fso = new ActiveXObject("Scripting.FileSystemObject");
		if (IsEmpty(fso))
			result = "Error 1";
		d = fso.GetDrive(fso.GetDriveName(fso.GetAbsolutePathName("c:")));
		result = d.SerialNumber;
	}
	catch(e)
	{
		result = null;
	}
	return result;
}


//=============
// CQueryString
//=============
function CQueryString()
{
	this.args = [];
	this.init();
}

CQueryString.prototype.init
=//======================
function ()
{
try
{
	var str = document.location.search;
	if ( IsEmpty(str) )
		return [];
	var tmp = str.split(/[\?&]/);
	this.args = [];
	for (var i=0; i<tmp.length; i++)
	{
		var pos = tmp[i].indexOf("=");
		if (pos <0)
			continue;
		var arg = tmp[i].substr(0, pos);
		var val = tmp[i].substr(pos+1);
		this.args[this.args.length] = [unescape(arg), unescape(val)];
	}
}
catch(e)
{
	this.args = [];
}
}

CQueryString.prototype.getArg
=//========================
function (name, defValue)
{
	if (arguments.length < 2) defValue = null;

	var tmp = name.toLowerCase();
	for (var i=0; i<this.args.length; i++)
	{
		if ( this.args[i][0].toLowerCase() == tmp )
			return this.args[i][1];
	}		
	return defValue;
}


function GetPageName(url)
{
	if ( IsEmpty(url) )
		return "";
	url = unescape(url);
	var pos1 = url.lastIndexOf('/') + 1;
	var pos2 = url.lastIndexOf('\\') + 1;
	var pos = pos1 > pos2 ? pos1 : pos2;
	return url.slice(pos).toLowerCase();
}


function GetStyleAttribute(style, attribute, defValue)
{
try
{
	if ( IsEmpty(style) )
		return defValue;
	var tmp = style.split(/;/);
	for (var i=0; i<tmp.length; i++)
	{
		tmp[i] = tmp[i].split(":");
		if (tmp[i][0] == attribute)
			return tmp[i][1];
	}
}
catch(e)
{}
	return defValue;
}


/* CLIPBOARD */
function ClipboardGet(idClip)
{
	var result = "";
	try
	{
		var clip = window.clipboardData.getData("Text");
		if (!IsEmpty(idClip))
		{
			if ( clip.slice(0, idClip.length) == idClip )
				result = clip.slice(idClip.length);
		}
		else
			result = clip;
	}
	catch (e)
	{
		result = "";
	}
	return result;
}

function ClipboardSet(idClip, value)
{
	for (var i=0; i<5; i++)
	{
	try
	{
		window.clipboardData.clearData("Text");
		if (arguments.length == 0)
		    return true;
		window.clipboardData.setData("Text", idClip+value);
		if (ClipboardGet(idClip) == value)
			return true;
	}
	catch(e){}
	}
	return false;
}

 //////////
// Cookie
//
//	date = null: cookie di sessione
//	date = "":   scadenza di default 30/10/2029
function CookieSet(name, value, date, path, domain, bSecure) 
{
	var result = escape(name) + "=" + escape(value) + ";";	
	if (date !== null) // se null viene omessa, passare "" per il default
	{
		if (IsEmpty(date)) 
			date = new Date(2029,10,30);
		result += " expires=" + date.toGMTString() + ";";
	}
	if (path !== null)
	{
		if (IsEmpty(path)) 
			path = "/";
		result += " path=" + path + ";";
	}
	if (!IsEmpty(domain))
		result += " domain=" + domain + ";";
	if (!IsEmpty(bSecure) && bSecure)
		result += " secure;";
	document.cookie = result;
	return result;
}
function CookieGet(name) 
{
	if (IsEmpty(name)) return document.cookie;
	
	// cookies are separated by semicolons
	var aCookie = document.cookie.split(/;\s*/);
	var aCrumb;
	for (var i=0; i < aCookie.length; i++)
	{
		// a name/value pair (a crumb) is separated by an equal sign
		aCrumb = aCookie[i].split("=");
		if (name == aCrumb[0])
		{
			if (aCrumb.length > 1)
				return unescape(aCrumb[1]);
			else
				return "";
		}
	}
	// a cookie with the requested name does not exist
	return null;
}
function CookieDel(name) 
{
	var date=new Date(2000,10,30); 
	return CookieSet(name, "", date);
}


/*** DEBUGGING ***/

function Debug(expr)
{
	window.alert(expr);
}

function DebugPoint(debugLevel, currLevel)
{
	if (debugLevel != null && currLevel != null && currLevel < debugLevel)
		return;
	if (Browser.ie && window.confirm("Debug?"))
		debugger;
}

function DebugProperties(target)
{
	var p;
	var str = "";
	for (p in target)
		if (typeof target[p] != "function")
			str += "\n" + p + " = " + target[p];
	return str;
}

function Dump(object_text)
{	
	var HTML = '<div style="font-size: 8pt;">'+ object_text +'</div>';
	if (IsObject(object_text))
		for (var i in object_text)
			if (!IsFunction(object_text[i]))
				HTML += '<div style="font-size: 8pt; padding-left: 20px;">'+ i +'='+ object_text[i] +'</div>';
	Response.Write(HTML);
}

//=====
// Log
//=====
var LogFormat = 0;  // 0=ASCII, -1=Unicode -2=system default
function Log(str, format)
{
	if (format == null) format = LogFormat;
		
	var fso, ts, filePath;
	try
	{
    	if (!Browser.serverSide)
        	return;
	    fso = Server.CreateObject("Scripting.FileSystemObject");
    	filePath = (""+Server.MapPath("/"))+"\\..\\log\\asp.txt"
	    ts = fso.OpenTextFile(filePath, 8, true, format);
    	ts.WriteLine(str);
	}
	catch(e){}
	finally {ts.Close()}
}

/*** LOW LEVEL ***/
function ODD_INT(i)    	{ return (i & 0x01) ? true : false };
function EVEN_INT(i)    { return (i & 0x00) ? true : false };
var NIBBLE_TO_ESA =     "0123456789ABCDEF";
var ESA_CHAR =          ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];

function StringToEsa(str)
{
	var strEsa = "";
	for (i=0; i<str.length; i++)
	{
		h = (str.charCodeAt(i) & 0xf0) >> 4;
		l = (str.charCodeAt(i) & 0x0f);
		strEsa += ESA_CHAR[h];
		strEsa += ESA_CHAR[l];
	}
	return strEsa;
}


function EsaToString(esaChar)
{
	if (IsEmpty(esaChar)) return "";
	var str = "";
	var currByte = EsaToByte(esaChar, 0, esaChar.length);
	for (var i=0; i<currByte.length; i++)
		str += String.fromCharCode(currByte[i]);
	return str;
}


function ByteToEsa(byteArray, start, nLong)
{
	var h, l;
	var end = start+nLong;
	var strEsa = "";
	for (i=start; i<end; i++)
	{
		h = (byteArray[i] & 0xf0) >> 4;
		l = (byteArray[i] & 0x0f);
		strEsa += ESA_CHAR[h] + ESA_CHAR[l];
	}
	return strEsa;
}


function EsaToByte(esaChar, start, nChar)
{   
    var i, j, c;
    var low, high;    
    var outByte = new Array(nChar/2);
        
    esaChar = esaChar.toUpperCase();
    for (i=start, j=0; i<nChar; i++)
    {		
		c = esaChar.charAt(i);
        if ( (('0' <= c) && (c <= '9')) || (('A' <= c) && (c <= 'F')) )
        {
            if ( ODD_INT(i) )
                low = NIBBLE_TO_ESA.indexOf(c);
            else
                high = NIBBLE_TO_ESA.indexOf(c) << 4;
        }
        else 
        {
			return null;
        }
        if ( ODD_INT(i) )
            outByte[j++] = high | low;
    }    
    return outByte;
}


function StringPadding(str, padStr, mod)
{
	var n = str.length % mod;
	if ( n == 0 )
		n = str.length;
	else
		n = str.length + (mod - n);
	while ( str.length < n )
			str += padStr;
	return str.slice(0, n);
}



// Unione insiemistica degli elementi di due liste.
// Le due liste possono essere indifferentemente array oppure stringhe (con gli elementi separati da virgola).
// L'unione è restituita come array.
function Union(list1, list2)
{
	if (list1 == null) list1 = [];
	if (list2 == null) list2 = [];

	// Se list1 è una stringa non vuota la riconduco ad un array.
	if (IsString(list1))
		list1 = IsEmpty(list1) ? [] : list1.split(",");

	// Se list2 è una stringa lo riconduco ad un array.
	if (IsString(list2))
		list2 = IsEmpty(list2) ? [] : list2.split(",");

	// Se list1 è vuoto allora il risultato è list2.
	if (list1.length == 0)
		return list2;
	
	// (list1 non è vuoto) Se list2 è vuoto allora il risultato è list1.
	if (list2.length == 0)
		return list1;

	// Copio list1 in result.
	var result = list1.concat();

	// Merge di list1 e list2.
	for (var i = 0; i < list2.length; i++)
	{
		var found = false;
		for (var j = 0; j < list1.length; j++)
		{
			if (list2[i] == list1[j])
			{
				found = true;
				break;
			}
		}
		
		if (!found)
			result[result.length] = list2[i];
	}
	
	return result;
}

/*** TRIM ***/

function TrimLeft(s, c, nMax)
{
	s = s.toString();
	if (!IsEmpty(c))
	{
		var re;
		if (IsEmpty(nMax))
		{
			re = new RegExp("(^"+ c +"*)","");
			return s.replace(re, ""); 
		}
		else
		{
			var result = s;
			re = new RegExp("(^"+ c +")","");
			for (var i=0; i<nMax; i++)
				result = result.replace(re, "");
			return result;
		}
	}
	else
		return s.replace(/(^\s*)/, "");
}
function TrimRight(s, c, nMax) 
{
	s = s.toString();
	if (!IsEmpty(c))
	{
		var re;
		if (IsEmpty(nMax))
		{
			re = new RegExp("("+ c +"*$)","");
			return s.replace(re, "");
		}
		else
		{
			var result = s;
			re = new RegExp("("+ c +"$)","");
			for (var i=0; i<nMax; i++)
				result = result.replace(re, "");
			return result;
		}
	}
	else
		return s.replace(/(\s*$)/, "");
}
function Trim(s, c, nMax)
{
	if (!IsEmpty(c))
		return TrimRight(TrimLeft(s, c, nMax), c, nMax);
	else
		return TrimRight(TrimLeft(s));
}

function TrimSearchExpression(s)
{
	// Sostituzione di cr, tab, ecc. con spazi singoli
	s = s.replace(/(\f|\n|\r|\t|\v)+/g, " ");
	// Raddoppio degli apici e trim degli spazi
	return Trim(s.replace(/'/g, "''"));
}

function NormalizeString(s)
{
	// Semplificazione whitespace
	return s.replace(/\s+/g, " ");
}

function LikeSearchExpression(field, value)
{
	var s = ""+ value;
	return "["+ field +"] LIKE '%<!_CDATA_"+ s.replace(/'/g, "''") +"__>%'";
}

function WildDateExpression(colName, stdDateTime_Date)
{
	if (stdDateTime_Date === null || stdDateTime_Date === "")
		return "";
	var d = new Object();
	StdDateTimeObject(stdDateTime_Date, d);
	return "dbo.fn_ReplaceWildDate("+ colName +",'"+ d.year +"','"+ d.month +"','"+ d.day +"','"+ (parseInt(d.year, 10)+1) +"')";
}

function AppendSearchExpression(s1, s2)
{
	if (IsEmpty(s1)) s1 = "";
	if (IsEmpty(s2)) s2 = "";
	if (!IsEmpty(s1) && !IsEmpty(s2))
	{
		s1 = "("+ s1 +") AND ";
		s2 = "("+ s2 +")";
	}
	return s1 += s2;
}


/* ParseSearchText

Lo switch automatico su LIKE è ammesso solo su singoli attributi ed è attivato dalla
presenza di un % nella stringa di ricerca. 
Rispetto alla CONTAINS c'è la possibilità di specificare prefissi con % e caratteri jolly con _
Perchè la contains trovi anche sigle tipo S.p.A. bisogna svuotare il file:
(SQL SERVER 2000) C:\Program Files\Microsoft SQL Server\MSSQL\FTDATA\SQLServer\Config\noise.dat (lingua neutrale)
(SQL SERVER 2005) C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\FTDATA\SQLServer\Config\noiseneu.txt (lingua neutrale)
Il risultato del parsing ritorna l'oggetto:
{
	 result : <stringa di ricerca se ok>
	,error1 : <parte di str fino all'errore riscontrato>
	,error2 : <parte restante di str>
	,ok: <true se ok>
}
*/
function ParseSearchText(str, colName, bAlert)
{
	// 20/10/2009: Per evitare attacchi su SQLSERVER la lunghezza della stringa viene limitata
	if (str.length > 500)
	{
		try { window.alert(Language.label("Errore nell'espressione di ricerca:\n  ... {0}", "> 500 Byte")) }catch(e){}
		return { result : "", error1 : "", error2 : "", ok : false }	
	}
	
	if (IsEmpty(colName)) colName = "*";
	if (IsEmpty(bAlert)) bAlert = true;
	
	var bLike = (colName != "*" && str.indexOf("%") >= 0) ? true : false;
	colName = "Object_Index."+colName;

	// Parsing dei token
	// item | + | - 
	var re = /("[^"]+")|(\+|\-)|([^ \f\n\r\t\v\+\-]+)/g
	var i, c, s, t, bFirst = true;
	var token = [];
	while ((t = re.exec(str)) != null)
	{
		for (i=0; i<t.length; t++)
			if (t[i] != "")
				token[token.length] = t[i];
	}

	function filterToken(t)
	{
		if (t.charAt(0) != '"')
			t = '"'+ t +'"';
		if (t.charAt(t.length-1) != '"')
			t = t + '"';
		if (bLike)
		{
			t = Trim(t, '"', 1);
			if (bFirst)
				bFirst = false;
			else
				t = "%"+t+"%";
		}
		t = t.replace(/'/g, "''");
		return t;
	}

	var status =
	{
		item : 0,
		near : 1,
		end : -1,
		error : -2
	}
	var result = "";
	var error1 = "";
	var error2 = "";
	s = status.item;
	i = 0;
	while (s != status.end && i<token.length)
	{		
		lookahead = token[i+1] == null ? null : token[i+1].charAt(0);
		switch (s)
		{
			case status.item:
				switch (token[i].charAt(0))
				{
					case '+':
						s = status.error;
						break;
					case '-':
						if (result == "")
						{
							result = bLike 
								? "("+ colName +" NOT LIKE '" 
								: "NOT CONTAINS("+ colName +", '";
							s = status.item;
							i++;
						}
						break;
					default:
						if (result == "")
						{
							result = bLike
								? "("+ colName +" LIKE '"
								: "CONTAINS("+ colName +", '";
						}
						switch (lookahead)						
						{
							case null:
								result += filterToken(token[i]) + "')";
								s = status.end;
								break;
							case '-':
								result += bLike
									? filterToken(token[i]) + "%') AND ("+ colName +" NOT LIKE '" 
									: filterToken(token[i]) + "') AND NOT CONTAINS("+ colName +", '";
								s = status.item;
								i += 2;
								break;
							case '+':
								result += bLike
									? filterToken(token[i]) + "%"
									: filterToken(token[i]) + " NEAR ";
								s = status.near;
								i += 2;
								break;
							default:
								result += bLike 
									? filterToken(token[i]) + "%') AND ("+ colName +" LIKE '" 
									: filterToken(token[i]) + "') AND CONTAINS("+ colName +", '";
								s = status.item;
								i += 1;
								break;
						}
				}
				break;

			case status.near:
				switch (token[i].charAt(0))
				{
					case '+':
					case '-':
						s = status.error;
						break;
					default:
						switch (lookahead)
						{
							case null:
								result += filterToken(token[i]) + "')";
								s = status.end;
								break;
							case '-':
								result += bLike
									? filterToken(token[i]) + "%') AND ("+ colName +" NOT LIKE '"
									: filterToken(token[i]) + "') AND NOT CONTAINS("+ colName +", '";
								s = status.item;
								i += 2;
								break;
							case '+':
								result += bLike
									? filterToken(token[i]) + "%"
									: filterToken(token[i]) + " NEAR ";
								s = status.near;
								i += 2;
								break;
							default:
								result += bLike
									? filterToken(token[i]) + "%') AND ("+ colName +" LIKE '"
									: filterToken(token[i]) + "') AND CONTAINS("+ colName +", '";
								s = status.item;
								i += 1;
								break;
						}
				}
				break;
			
			case status.error:
			default:
				var j;
				for (j=0; j<i; j++)
					error1 += token[j] + " ";
				for (j=i; j<token.length; j++)
					error2 += token[j] + " ";	
				s = status.end;
				break;
		}
	}
	result = { result : result, error1 : error1, error2 : error2, ok : (error1 == "" && error2 == "") }
	if (!result.ok && bAlert)
		try { window.alert(Language.label("Errore nell'espressione di ricerca:\n  ... {0}", result.error2)) }catch(e){}
	if (result.ok && bLike)
	{
		result.result = result.result.replace(/\*+/g, "%");
		result.result = result.result.replace(/\%+/g, "%");
	}
	return result;
}

function OpenUrl(url, target, features)
{
	if ( IsEmpty(url) )
		return;
	
	switch ( target )
	{
		case "_same": 
			window.location = url;
			break;
		
		case "_replace":
			window.location.replace(url);
			break;
		
		default:	
			if ( IsEmpty(features) )
				window.open(url, target);
			else
				window.open(url, target, features);
	}	
}


/* CHECKED INPUT */

function ParseInt(v, def, radix)
{
	if (radix==null) radix = 10;
	var result = parseInt(v, radix);
	if (isNaN(result) && arguments.length > 1)
		return def;
	return result;
}

function ParseFloat(v, def)
{
	var result = parseFloat(v)
	if (isNaN(result) && arguments.length > 1)
		return def;
	return result;
}

// Ottenimento di un valore intero
// Ritorna:
//	"" se il valore e' in bianco
//	null se non è un intero valido
//	
function GetCheckedInteger(target, bAlert)
{
	if (IsEmpty(bAlert)) bAlert = true;
	
	target.value = Trim(target.value+"");
	if (IsEmptyString(target.value))
		return "";
	if (isNaN(target.value) || parseInt(target.value,10) != target.value)
	{
		if (bAlert)
		{
			window.alert(Language.label("Inserire un'espressione numerica intera valida"));
			target.focus();
		}
		return null;
	}
	return target.value;
}


// Ottenimento di un valore float
// Ritorna:
//	"" se il valore e' in bianco
//	null se non è un float valido
//
function GetCheckedFloat(target, bAlert)
{
	if (IsEmpty(bAlert)) bAlert = true;	
	target.value = Trim(target.value);
	if (IsEmptyString(target.value))
		return "";
	if (isNaN(target.value))
	{
		if (bAlert)
		{
			window.alert(Language.label("Inserire un'espressione numerica valida (come separatore decimali usare il punto '.')"));
			target.focus();
		}
		return null;
	}
	return target.value;
}


/* ARROTONDAMENTO */

// Arrotondamento di un numero con nDecimali specificati
// se sono indicati cPoint o bZero ritorna una stringa
function Round(value, nDecimal, cPoint, bZero)
{
try
{
	var defZero = false;
	if (IsEmpty(nDecimal)) nDecimal = 4;
	if (IsEmpty(cPoint)) { cPoint = null; } else { defZero = true; }
	if (!IsEmpty(bZero)) defZero = bZero;
	bZero = defZero;
	
	var dec = Math.pow(10, nDecimal);
	var result = Math.round(value * dec) / dec;
	if ( !bZero && cPoint === null )
		return result;

	strResult = result.toString();
	if (bZero)
	{
		var z = strResult.lastIndexOf(".");
		if (z < 0 && nDecimal > 0)
		{
			strResult += ".";
			z = nDecimal;
		}
		else
			z = z + nDecimal + 1 - strResult.length;
		for (var i=0; i<z; i++)
			strResult += "0";
	}

	if (!IsEmpty(cPoint))
		strResult = strResult.replace(/\./g, cPoint);

	return strResult;
}
catch(e)
{
	return 0;
}
}


/*** FORMATI STANDARD ***/

// Format
var Format_bool_x = ["", "x", "", "x"];
var Format_bool_1 = ["0", "1", "0", "1"];
var Format_bool_t = ["F", "V", "F", "T"];
var Format_bool_T = ["Falso", "Vero", "False", "True"];
var Format_bool_y = ["N", "S", "N", "Y"];
var Format_bool_Y = ["No", "Si", "No", "Yes"];
var Format_month = null;

function Format(str, fmt)
{
	var val, result;
	
	if (Format_month == null)
		Format_month = 
		[
			Language.label("gennaio"), 
			Language.label("febbraio"), 
			Language.label("marzo"), 
			Language.label("aprile"), 
			Language.label("maggio"), 
			Language.label("giugno"), 
			Language.label("luglio"), 
			Language.label("agosto"), 
			Language.label("settembre"), 
			Language.label("ottobre"), 
			Language.label("novembre"), 
			Language.label("dicembre") 
		];

	// Formato		
	if ( IsEmptyString(fmt) )
		return str;
	var result = fmt.match(/\s*([^:]*):([^|]*)\|*([^$]*)/);
	if ( result == null )
		return "?";
	var tipo = result[1].toLowerCase();
	var campi = result[2];
	var opzioni = result[3].toLowerCase();

	// Lettura Opzioni
	
	// lang + separatori decimali e migliaia
	var o_lang = opzioni.match(/\S*lang=([^ ,]*)/);
	var o_dsep = ",";
	var o_tsep = ".";
	if ( o_lang == null )
		o_lang = "it";
	else
	{
		o_lang = o_lang[1];
		if ( o_lang == "en" )
		{
			o_dsep = ",";
			o_tsep = ".";
		}
	}
	// case
	var o_case = opzioni.match(/\S*case=([^ ,]*)/);
	if ( o_case == null )
		o_case = "c";
	else
		o_case = o_case[1];
	// curr
	var o_curr = opzioni.match(/\S*curr=([^ ,]*)/);
	if ( o_curr == null )
		o_curr = "";
	else
		o_curr = o_curr[1];
	
	// Costruzione del risultato
	switch (tipo)
	{
		case "bool":	// Es. "bool:%Y|lang=it"
			val = parseInt(str, 10);
			if ( !isNaN(val) )
				val = val ? 1 : 0;
			else
				val = ( str.search(/^t|v|s|y/i) >= 0 )? 1 : 0;
			// Opzione lang
			if ( o_lang == "en" )
				val += 2;
			result = campi.replace(/%x/, Format_bool_x[val]);
			result = result.replace(/%1/, Format_bool_1[val]);
			result = result.replace(/%t/, Format_bool_t[val]);
			result = result.replace(/%T/, Format_bool_T[val]);
			result = result.replace(/%y/, Format_bool_y[val]);
			result = result.replace(/%Y/, Format_bool_Y[val]);
			// Opzione case
			switch ( o_case )
			{
				case "l": result = result.toLowerCase(); break;
				case "u": result = result.toUpperCase(); break;
			}
			break;
						
		case "dt":
			// Il valore da rappresentare e' in formato fisso:
			//	YYYY-MM-DDThh:mm:ss con la parte Thh:mm:ss opzionale e T che può essere un qualunque carattere
			//	1    2  3  4  5  6
			//var val = str.match(/(\d*)-(\d*)-(\d*)T(\d*):(\d*):(\d*)/);
			if (IsEmpty(str))
				return "";
			var val = str.match(/(\d*)-(\d*)-(\d*)(?:.(\d*):(\d*):(\d*))*/);
			if ( val == null )
				return "";
			result = campi.replace(/%Y/, val[1]);
			result = result.replace(/%y/, val[1].slice(-2));
			result = result.replace(/%mm/, Format_month[val[2]-1]);
			result = result.replace(/%m/, val[2]);
			result = result.replace(/%d/, val[3]);			
			result = result.replace(/%H/, val[4]);
			result = result.replace(/%M/, val[5]);
			result = result.replace(/%S/, val[6]);
			// Opzione case
			switch ( o_case )
			{
				case "l": result = result.toLowerCase();
				case "u": result = result.toUpperCase();
			}
			break;

		case "enum":
			// L'elenco si suppone in formato Vs V
			result = GetCollectionList(str, campi == "li");
			break;

		case "int":
			result = str;
			break;
			
		case "dec":
			var nDecimal = parseInt(campi, 10);
			if (isNaN(nDecimal))
				result = str;
			else
				result = Round(str, nDecimal, o_dsep, true);
			break;
		
		default:
			result = "?";
	}		
	return result;
}

// Funzione utilizzata per l'estrazione dei riferimenti al glossario
function GetCollectionList(arg, bList)
{
	if ( arguments.length < 2 ) bList = true;
	
	var HTML = "";
	var l = GetCollectionValue(arg);
	if ( bList )
	{
		for (var i=0; i<l.length; i++)
		{
			if ( Trim(l[i]) != "" )
				HTML += "{_<_}LI{_>_}" + l[i] + "{_<_}/LI{_>_}";
		}
		if (!IsEmpty(HTML))
			HTML = "{_<_}UL{_>_}"+ HTML +"{_<_}/UL{_>_}";
		else
			HTML = "";
	}
	else
	{
		for (var i=0; i<l.length; i++)
		{
			if ( Trim(l[i]) != "" )
			{
				if ( HTML != "" )
					HTML += ", ";
				HTML += l[i];
			}
		}
	}	
	return HTML;
}

// Ritorna un array con i valori della collection
// Se non c'e' nulla ritorna un array con un solo elemento stringa vuota
function GetCollectionValue(arg)
{
	var i, s; 
	if ( !IsEmptyString(arg) )
	{
		s = arg.match(/<Vs>([^$]*)<\/Vs>/g);
		if ( s != null )
		{
			s = arg.split("<!\[CDATA\[");
			if ( s != null )
			{
				if ( s.length > 1 )
				{ 
					s = s.slice(1);
					for (i=0; i<s.length; i++)
						s[i] = s[i].replace(/\]\]>.*/, "");
					return s;
				}
			}
		}
	}
	return [""];
}


/* Text conversion */

function TextTranslation(value, translation)
{
	if (!IsEmpty(translation))
		return translation;
	if (!IsEmpty(value));
		return "("+ value + ")";
	return "";
}


function UrlToXHTML(url)
{
	if (IsEmpty(url))
		return "";
	return (""+url).replace(/(\/)|(\\)|(&)|(")|(<)|(>)/g,
	function(c)
	{
		switch (c)
		{
			case "\\": return "\\\\";
			case "'": return "&apos";
			case "&": return "&amp;";
			case '"': return "&quot;";
			case "<": return "&lt;";
			case ">": return "&gt;";
		}
		return c;
	});
}

function XHTMLToUrl(url)
{
	if (IsEmpty(url))
		return "";
	return (""+url).replace(/(\\\\)|(&#47;)|(&apos;)|(&amp;)|(&quot;)|(&lt;)|(&gt;)/g, 
	function(c)
	{
		switch (c)
		{
			case "\\\\" : return "\\";
			case "&#47;" : return "/";
			case "&apos;": return "'";
			case "&amp;" : return "&";
			case "&quot;": return '"';
			case "&lt;"  : return "<";
			case "&gt;"  : return ">";
		}
		return c;
	});
}

function OpenLocalUrl(url)
{
	if (IsEmpty(url))
		return;
	var fileEditCtrl;
    try
    {
        fileEditCtrl = new ActiveXObject("FileEditCtrl.FileEdit");
    }
    catch(e)
    {
		if (e.number == -2146827859)
			window.open("/KnoS/plugin/FileEditSetup2.msi");
     	else
     		ErrorAlert(e);
    	return;
    }
    url = XHTMLToUrl(url);
    var tmp = url.toLowerCase();
    if (tmp.indexOf("file:") == 0)
    {
    	url = url.replace(/file:\/*/i, "");
		try 
		{
    		fileEditCtrl.OpenFile(url);
    	}
    	catch(e){ErrorAlert(e)}
    }
}

function TextToInputValue(text)
{
	if (IsEmpty(text)) return "";
	
	var result = "" + text;
	result = result.replace(/&/g, "&amp;");
	result = result.replace(/"/g, "&quot;");
	result = result.replace(/</g, "&lt;");
	return result.replace(/>/g, "&gt;");
}

function TextToHTML(text)
{
	if (IsEmpty(text)) return "&nbsp;";
	
	var result = "" + text;
	result = result.replace(/&/g, "&amp;");
	result = result.replace(/\s\s/g, " &nbsp;");
	result = result.replace(/"/g, "&quot;");
	result = result.replace(/</g, "&lt;");
	return result.replace(/>/g, "&gt;");
}

function TextToXHTML(text)
{
	var result = "" + text;
		if (result==null) return "";
	// ' vs &apos; non è necessario
	return result.replace(/(&)|(")|(<)|(>)/g, 
	function(c)
	{
		switch (c)
		{
			case "&": return "&amp;";
			case '"': return "&quot;";
			case "<": return "&lt;";
			case ">": return "&gt;";
		}
		return c;
	});
}

function XHTMLToText(text)
{
	var result = "" + text;
		if (result==null) return "";
	return result.replace(/(&amp;)|(&quot;)|(&lt;)|(&gt;)/g, 
	function(c)
	{
		switch (c)
		{
			case "&amp;": return "&";
			case "&quot;": return '"';
			case "&lt;": return "<";
			case "&gt;": return ">";
		}
		return c;
	});
}

/*** SQL ***/

function SQL_NVARCHAR(value)
{
	var result = ""+value;
	return "N'"+ result.replace(/'/g, "''") +"'";
}

/*** XML ***/

function XMLAttributeValue(attr, def){if (arguments.length<2) def = ""; try {return attr.text;} catch(e) {return def}}

function XMLAttributeValueToHTML(attr)
{
	var result;
	try
	{
		result = attr.xml.replace(/[^"]*"/, "");
		result = result.replace(/\"[^$]*/, "");
	} 
	catch(e)
	{
		result = ""
	} 
	if (IsEmpty(result))
		result = "&nbsp;";
	return result;
}

function XMLCreateNode(dom, name, data, attributes)
{
try
{
	var node = dom.createElement(name);
	if (data !== null)
		node.appendChild(dom.createCDATASection(data));
	if (!IsEmpty(attributes))
		for (var i=0; i<attributes.length; i++)
			node.setAttribute(attributes[i][0], attributes[i][1]);
	return node;
}
catch(e)
{
	return null;
}
}

function XMLAppendNode(dom, parentName, childName, data, attributes)
{
try
{
	var parent = dom.selectSingleNode(parentName);
	var node = XMLCreateNode(dom, childName, data, attributes);
	parent.appendChild(node);
	return node;
}
catch(e)
{
	return null;
}
}

function XMLGetNodeText(dom, nodeName, defaultResult)
{
	if (arguments.length<3) defaultResult = null; 
	try
	{
		return dom.selectSingleNode("//"+nodeName).text
	}
	catch(e)
	{
		return defaultResult;
	}
}

function XMLGetAttributeText(node, attrName, defaultResult)
{
	if (arguments.length<3) defaultResult = null; 
	try
	{
		return node.attributes.getNamedItem(attrName).text;
	}
	catch(e)
	{
		return defaultResult;
	}
}

function XMLGetNodeAttributeText(dom, nodeName, attrName, defaultResult)
{
	if (arguments.length<4) defaultResult = null; 
	try
	{		
		return dom.selectSingleNode("//"+nodeName).attributes.getNamedItem(attrName).text;
	}
	catch(e)
	{
		return defaultResult;
	}
}

function XMLEnumString(list, colValue)
{
	if (IsEmpty(colValue)) colValue = null;

	var result = "<Vs>";
	for (i=0; i<list.length; i++)
		result += "<V><![CDATA["+ ((colValue==null) ? list[i] : list[i][colValue]) +"]]></V>";
	result += "</Vs>";
	return result;
}

function XMLEnumValues(enumString)
{
	var result = [];
	var t, s = enumString.split("]]></V>");
	for (var i=0; i<s.length-1; i++)
	{
		t = s[i].split("<![CDATA[");
		if (t.length>1)
			result[result.length] = t[1];
	}
	return result;
}


// attrList è un array di stringhe con i nomi degli attributi da considerate
// se attrList è un array vuoto viene riempito con l'elenco dei nomi degli attributi trovati
function XMLGetNodeList(dom, nodeName, attrList)
{
	var result = []	
	try 
	{
		var i, j, o;
		var nodeList = dom.selectNodes("//"+nodeName);
		if (IsEmpty(attrList))
		{
			if (!IsArray(attrList))
				attrList = [];
			var map = [];
			var attrName;
			for (i=0; i<nodeList.length; i++)
			{
				var node = nodeList[i];
				o = new Object();
				for (j=0; j<node.attributes.length; j++)
				{
					attrName = node.attributes[j].nodeName;
					if (map[attrName] == null)
						attrList.push(attrName);
					o[attrName] = node.attributes[j].nodeValue;
				}
				result[result.length] = o;
			}			
		}
		else
		{
			for (i=0; i<nodeList.length; i++)
			{
				o = new Object();
				for (j=0; j<attrList.length; j++)
					o[attrList[j]] = XMLGetAttributeText(nodeList[i], attrList[j], "");
				result[result.length] = o;
			}
		}
	}
	catch(e) 
	{ 
		result = []; 
	}
	return result;
}

function ArrayListToRow(arrayList, propList, def)
{
	if (IsEmpty(def)) def = "";

	var result = [];
	var v, row;
	for (var i in arrayList)
	{
		row = [];
		for (var j=0; j<propList.length; j++)
		{
			v = arrayList[i][propList[j]];
			if (v != null)
				row[row.length] = v;
			else
				row[row.length] = def;
		}
		result[result.length] = row.slice(0);
	}
	return result;
}

/* DATETIME */

function StdDateString(y, m, d) { y = "0000"+ y; m = "00"+ m; d = "00"+ d; return y.slice(-4) +"-"+ m.slice(-2) +"-"+ d.slice(-2); }
function StdTimeString(h, m, s) { h = "00"+ h; m = "00"+ m;	s = "00"+ s; return h.slice(-2) +":"+ m.slice(-2) +":"+ s.slice(-2); }
function StdDateTimeString(year, month, day, hour, min, sec) { if (IsEmpty(hour)) hour = 0; if (IsEmpty(min)) min = 0; if (IsEmpty(sec)) sec = 0; return StdDateString(year, month, day) +" "+ StdTimeString(hour, min, sec) }
function DateToStdDateString(date) { return StdDateString(date.getFullYear(), 1+date.getMonth(), date.getDate()) }
function DateToStdTimeString(date) { return StdTimeString(date.getHours(), date.getMinutes(), date.getSeconds()) }
function DateToStdDateTimeString(date) { return StdDateTimeString(date.getFullYear(), 1+date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()) }
function StdDateTimeObject(stdDateTime_Date, object)
{
	var d = stdDateTime_Date;
	if (IsEmpty(object)) object = new Object();
	if (IsEmpty(d)) 
	{
		object.year = "";
		object.month = "";
		object.day = "";
		object.hour = "";
		object.min = "";
		object.sec = "";
	}
	else
	{		
		if (IsEmpty(d.getDate))
		{
			object.year = d.slice(0,4);
			object.month = d.slice(5,7);
			object.day = d.slice(8,10);
			object.hour = d.slice(11,13);
			object.min = d.slice(14,16);
			object.sec = d.slice(17,19);
		}
		else
		{
			object.year = d.getFullYear();
			object.month = 1+d.getMonth();
			object.day = d.getDate();
			object.hour = d.getHours();
			object.min = d.getMinutes();
			object.sec = d.getSeconds();
		}
	}
	return object;
}
function StdDateTimeToDate(stdDateTime)
{
	var d = new Object();
	StdDateTimeObject(stdDateTime, d);
	return new Date(ParseInt(d.year), ParseInt(d.month)-1, ParseInt(d.day), ParseInt(d.hour, 0), ParseInt(d.min, 0), ParseInt(d.sec, 0));
}
function DateToVBdate(date){ return VBdate(date.getFullYear(),	1+date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()) }

/* OBJECT */

function ObjectClone(obj, as)
{
	var i, result;
	if (as=="array")
		result = [];
	else if (as=="object")
		result = {};
	else if (IsArray(obj))
		result = [];
	else if (IsObject(obj))
		result = {};
	else
		return obj;
	for (i in obj)
		result[i] = ObjectClone(obj[i]);	
	return result;
}

function ObjectCompare(partial, complete)
{
	for (var i in partial)
		if (partial[i] != complete[i])
			return false;
	return true;
}

function ObjectAppend(obj, append)
{
	for (var i in append)
		obj[i] = append[i];
}

function ObjectSerialize(obj, defObj)
{
	if (IsEmpty(defObj)) defObj = {};
	var result = new CString();
	var sep = "";
	for (var i in obj)
	{		
		if (defObj != null && obj[i] != null && obj[i] == defObj[i])
			continue;
		if (IsObject(obj[i]))
		{
			var sub = ObjectSerialize(obj[i]);
			var defSub = ObjectSerialize(defObj[i]);
			if (sub == defSub)
				continue;
			result.append(sep +'"'+ i +'":'+ sub);
		}
		else if (typeof obj[i] == "number")
			result.append(sep +'"'+ i +'":'+ obj[i]);
		else
			result.append(sep +'"'+ i +'":"'+ (obj[i].toString()).replace('"', '\"') +'"');
		sep = ','
	}
	result = result.toString();
	if (result != "")
		result = "{"+ result +"}";
	return result;
}

function ObjectNormalize(obj, defObj)
{
	try
	{
		if (IsString(obj))
			eval("obj="+obj);
		if (IsEmpty(obj))
			return ObjectClone(defObj);
		for (var i in defObj)
			if (obj[i] == null)
				obj[i] = defObj[i];
		return obj;
	}
	catch(e)
	{
		return defObj;
	}
}

function ObjectToString(obj, sep)
{
	if (IsEmpty(sep)) sep=",";

	var item, result = "";
	for (var i in obj)
	{
		item = "" + obj[i];
		if (item == "")
			continue;
		if (result != "")
			result += ",";
		result += obj[i];
	}
	return result;
}

//===========
// CSelection
//===========
function CSelection()
{
	this.all = [];
	this.get = function(id){return this.all[id]};
	this.add = function(id, object)
	{
		if (IsEmpty(id)) return;
		if (object == null) object = true;
		var tmp = id.toString().split(",");
		for (var i=0; i<tmp.length; i++)
			this.all[tmp[i]] = object
	};
	this.del = function(id){delete this.all[id]};
	this.reset = function(id, object){this.all=[]; this.add(id, object)};
	this.serialize = function(emptyDef)
	{
		var result = "";
		for (var i in this.all)
		{
			if (result != "")
				result += ",";
			result += i;
		}
		if (IsEmpty(result))
			result = emptyDef;		
		return result;
	}
}


/*** Serialization ***/

var __reString1 = /(&)|(<)|(>)|(')|(")|(\t)|(\n)|(\v)|(\f)|(\r)|(\x08)/gm;
var __reString2 = /(&amp;)|(&lt;)|(&gt;)|(&apos;)|(&quot;)|(&x0009;)|(&x000A;)|(&x000B;)|(&x000C;)|(&x000D;)|(&x0008;)/gm;
var __reTag = /(<(?:\s|\S)*?>)/gm;
var __reType = /<(\/?\S*)(\s|>)/m;
var __reName = /\sn="([^"]*)"/m;
var __reValue = /\sv="([^"]*)"/m;
var __reOwner = /(<owner(?:\s|\S)*?>(?:\s|\S)*?<\/owner>)/gi;
var __reClient = /(<client(?:\s|\S)*?>(?:\s|\S)*?<\/client>)/m;
var __reServer = /(<server(?:\s|\S)*?>(?:\s|\S)*?<\/server>)/m;
function SerializeString(s, bXML)
{
	if (IsEmpty(bXML)) bXML = true;

	return (""+s).replace
	(
		__reString1,
		function($0)
		{
			switch($0)
			{
				case "&": return "&amp;";
				case "<": return "&lt;";
				case ">": return "&gt;";
				case "'": return bXML ? "&apos;" : "\'";
				case '"': return "&quot;";
				case "\t": return "&x0009;";
				case "\n": return "&x000A;";
				case "\v": return "&x000B;";
				case "\f": return "&x000C;";
				case "\r": return "&x000D;";
				case "\x08": return "&x0008;";
				default: return $0;
			}
		}
	)
}
function DeserializeString(s, bHtml)
{
	if (s==null)
		return "";
	return s.replace
	(
		__reString2,
		function($0)
		{
			switch($0)
			{
				case "&amp;": return "&";
				case "&lt;": return "<";
				case "&gt;": return ">";
				case "&apos;": return "'";
				case "&quot;": return '"';
				case "&x0009;": return "\t";
				case "&x000A;": return "\n";
				case "&x000B;": return "\v";
				case "&x000C;": return "\f";
				case "&x000D;": return "\r";
				case "&x0008;": return "\b";
				default: return $0;
			}
		}
	)
}

function SerializeDate(d) { return d.getFullYear() +'-'+ ('0'+(d.getMonth()+1)).slice(-2) +'-'+ ('0'+d.getDate()).slice(-2) +' '+ ('0'+d.getHours()).slice(-2) +':'+ ('0'+d.getMinutes()).slice(-2) +':'+ ('0'+d.getSeconds()).slice(-2) +':'+ ('00'+d.getMilliseconds()).slice(-3) }
function DeserializeDate(s) { return new Date(parseInt(s.slice(0,4), 10), parseInt(s.slice(5,7), 10)-1, parseInt(s.slice(8,10), 10), parseInt(s.slice(11,13), 10), parseInt(s.slice(14,16), 10), parseInt(s.slice(17,19), 10), parseInt(s.slice(20,22), 10)) }

/* Serialize
***************
	Funzione ricorsiva utilizzata per la serializzazione di un oggetto JavaScript in una stringa XML. 
	La funzione opera interamente in JavaScript per aumentare la compatibilità con i browser. 
	Possono essere serializzati solo: Number, String, Boolean, Date, RegExp, Array e Object. 
	Non vengono ad esempio serializzati oggetti di tipo Function, ActiveX, Applet, ecc.  
__o  
	Oggetto da serializzare.  
__id  
	Identificativo dell'oggetto serializzato. Normalmente si tratta dell'identivicativo di __o (cioè: eval(__id)==__o) ma può essere usato un identificativo qualunque. In fase di deserializzazione l'oggetto serializzato verrà ripristinato con il nome __id.  
Nota:  
	Per motivi di implementazione l'oggetto serializzato, l'identificativo specificato e le sue eventuali proprietà enumerabili non possono avere nomi che iniziano con "__" come ad esempio __o oppure __id.  
*/
function Serialize(__o, __id)
{
	var __xml = arguments[2] == undefined ? "" : arguments[2];
	var __result = "";
	var __i;
	switch (TypeOf(__o))
	{
		case "number": return '<n n="'+ __id +'" v="'+ __o +'"/>';
		case "string": return '<s n="'+ __id +'" v="'+ SerializeString(__o) +'"/>';
		case "boolean": return '<b n="'+ __id +'" v="'+ (__o?1:0) +'"/>';
		case "date": return '<d n="'+ __id +'" v="'+ SerializeDate(__o) +'"/>';
		case "regexp": return '<r n="'+ __id +'" v="'+ SerializeString(__o.toString()) +'"/>';
		case "array": for (__i in __o) __result += Serialize(__o[__i], __i, __xml); return __xml += '<a n="'+ __id +'">'+ __result +'</a>';
		case "object": for (__i in __o) __result += Serialize(__o[__i], __i, __xml); return __xml += '<o n="'+ __id +'">'+ __result +'</o>';
		default: return "";
	}
}

/* Deserialize
*****************
	Funzione ricorsiva utilizzata per la serializzazione di un oggetto JavaScript in una stringa XML. 
	La funzione opera interamente in JavaScript per aumentare la compatibilità con i browser. 
	Possono essere serializzati solo: Number, String, Boolean, Date, RegExp, Array e Object. 
	Non vengono ad esempio serializzati oggetti di tipo Function, ActiveX, Applet, ecc.  
__xml  
	Stringa xml contenente l'oggetto da deserializzare.  
__parentObjectId optional  
	Identificativo opzionale di un oggetto al di sotto del quale collocare l'oggetto da deserializzare. 
	Se omesso l'oggetto viene deserializzato come oggetto globale sovrascrivendo un eventuale oggetto già presente con lo stesso identificativo. 
	Se indicato l'oggetto deserializzato verrà appeso come property all'oggetto indicato. L'oggetto con identificativo parentObjectId viene creato solo se non è già esistente e non viene mai sovrascritto (mentre vengono sovrascritte eventuali property conincidenti con quelle deserializzate).  
Nota:  
	Per motivi di implementazione __parentObject non può iniziare con "__".  
*/
function Deserialize(__xml, __parentObjectId)
{
	__parentObjectId = __parentObjectId == null ? "" : __parentObjectId;
	var __i, __j, __k, __node;
	var __r = __xml.match(__reTag);
	for (__i=0; __i<__r.length; __i++)
	{
		__node = new Object();
		__node.type = __reType.exec(__r[__i]);
		if (__node.type)
			__node.type = __node.type[1];
		__node.name = __reName.exec(__r[__i]);
		if (__node.name)
			__node.name = __node.name[1];
		__node.value = __reValue.exec(__r[__i]);
		if (__node.value)
		{
			__node.value = __node.value[1];
			switch (__node.type)
			{
				case "n": __node.value = parseFloat(__node.value); break;
				case "s": __node.value = DeserializeString(__node.value); break;
				case "b": __node.value = __node.value = '1' ? true : false; break;
				case "d": __node.value = DeserializeDate(__node.value); break;
				case "r": __node.value = __node.value.toString(); break;
			}
		}
		__r[__i] = __node;
	}
	for (__i=0; __i<__r.length; __i++)
	{
		switch (__r[__i].type)
		{
			case "a":
				for (__j=__i+1, __k=0; __j<__r.length; __j++)
				{
					if (__r[__j].type == "/a" || __r[__j].type == "/o")
					{
						__k--;
						if (__k<=0 && __r[__j].type == "/a") break;
						continue;
					}
					if (__k==0)
					{
						if (isNaN(parseInt(__r[__j].name, 10)))
							__r[__j].name = __r[__i].name +'["'+ __r[__j].name +'"]';
						else
							__r[__j].name = __r[__i].name +'['+ __r[__j].name +']';
					}
					if (__r[__j].type == "a" || __r[__j].type == "o")
						__k++;
				}
				break;
			case "o":
				for (__j=__i+1, __k=0; __j<__r.length; __j++)
				{
					if (__r[__j].type == "/a" || __r[__j].type == "/o")
					{
						__k--;
						if (__k<=0 && __r[__j].type == "/o") break;
						continue;
					}
					if (__k==0)
						__r[__j].name = __r[__i].name +'.'+ __r[__j].name;
					if (__r[__j].type == "a" || __r[__j].type == "o")
						__k++;
				}
				break;
		}
	}
	if (__parentObjectId !== "")
	{
		if ( eval("typeof "+__parentObjectId) != "object" )
			eval( __parentObjectId +"= new Object()");
		__parentObjectId += ".";
	}
	for (__i=0; __i<__r.length; __i++)
	{
		switch (__r[__i].type)
		{
			case "n":
			case "s":
			case "b":
			case "d":
			case "r":
				eval(__parentObjectId + __r[__i].name +'= __r[__i].value'); 
				break;
			case "a":
				eval(__parentObjectId + __r[__i].name +"=[]");
				break;
			case "o":
				eval(__parentObjectId + __r[__i].name +"= new Object()");
				break;
		}
	}
}


/* PLACE HOLDER */

function OpenInnerLink(){}
function OpenInnerRef(){}
function OpenExternal(url)
{
    if (url.indexOf("file:") == 0)
    {
        try
        {
        	var fileName = url.replace("file:", "");
        	fileName = fileName.replace(/\\/g, "\\");
            fileEditObj = new ActiveXObject("FileEditCtrl.FileEdit");
            fileEditObj.OpenFile(url);
        }
        catch(e)
        {
            if (e.number == -2146827859)
            {
                // ActiveX can't create object.
                if (!window.confirm(Language.label("Questa funzionalità richiede l'installazione di un componente ActiveX.\nProcedere con l'installazione?")))
                    return null;

                // Download del setup.
                window.open("/knos/plugin/FileEditSetup.msi", "_blank");
            }
            else
                throw e;
        }
    }
	else
		window.open(url, "External").focus()
}



//========
// CString
//========
function CString(value, obj_args)
{
	if (value == null) value = ""

	// Server side or Internet Explorer
	if (Browser.ie || Browser.serverSide)
	{
    	this.string = new Array("");
    	this._append = function (value) { this.string.push(value); return this; }
    	this.clear = function () { delete this.string; this.string = new Array("") }
    	this.toString = function ()	{ return this.string.join(""); }
    	this.isEmpty = function()
    	{
    	    for(var i=0; i<this.string.length; i++)
    	        if (this.string[i] != "")
    	            return false;
    	    return true;
    	}
	}
	// Other browsers
	else
	{
    	this.string = new String(value);
    	this._append = function (value) { this.string += value; return this; }
    	this.clear = function () { this.string = ""; }
    	this.toString = function ()	{ return this.string }
    	this.isEmpty = function(){ return this.string == "" }
	}
	// Common function
   	this.append = function (value, obj_args)
   	{
   		var result = value;
   		if(obj_args != null)
		{
			if (IsStrictObject(obj_args))
				result = StringFormat(value, obj_args);
			else
			{
				var args = [];
				for (var i=0; i<arguments.length; i++)
					args.push(arguments[i]);
				result = StringFormat(value, args);
			}
		}
		return this._append(result);
   	}
   	// Initialize
	var result = value;
	if(obj_args != null)
	{
		if (IsStrictObject(obj_args))
			result = StringFormat(value, obj_args);
		else
		{
			var args = [];
			for (var i=0; i<arguments.length; i++)
				args.push(arguments[i]);
			result = StringFormat(value, args);
		}
	}
	else
		return this._append(result);
}


//========
// Profile
//========
var Profile =
{
	item : [],
	start: function (name)
	{
		var item = this.item[name];
		if (item == null)
			item = this.item[name] = { count: 0, total: 0, time: 0, max: 0, min: 0, avg: 0 }
		item.time = new Date();
	},
	stop: function (name)
	{
		var t = new Date();
		var item = this.item[name];
		if (item == null)
			return;
		t = t-item.time;
		item.count++;
		item.total += t;
		item.avg = item.total / item.count;
		if (item.max < t) item.max = t;
		if (item.min == 0 || item.min > t) item.min = t;
	},
	stat: function (name)
	{
		var result = "";
		for (var i in this.item)
		{
			var item = this.item[i];
			result += i +":\n    count="+ item.count +", total="+ (item.total/1000) +" sec, max="+ (item.max/1000) +" sec, average="+ (Math.round(item.avg)/1000) + " sec, min="+ (item.min/1000) +" sec\n\n";
		}
		return result;
	},
	clear: function (name)
	{
		if (name != null && this.item[name] != null)
			return delete this.item[name];
		delete this.item;
		this.item = [];
	}
}


// Rappresentazioe unicode \u00A1
function UCN(str)
{
	var result = "";
	str = str.toString();
	for (var j=0; j<str.length; j++)
		result += "\\u"+("0000"+(str.charCodeAt(j).toString(16))).slice(-4);
	return result;
}
