

/* String utilities */

String.prototype.HTMLEntities = String.prototype.escapeHTML;
/*
function() {
	var div = document.createElement('div');
	var text = document.createTextNode(this);
	div.appendChild(text);
	return div.innerHTML;
}
*/

String.prototype.HTMLentities = String.prototype.HTMLEntities;
String.prototype.encodeHTML = function() {
	var output = this;
	output = output.replace(new RegExp("<",'g'), "&lt;");
	output = output.replace(new RegExp(">",'g'), "&gt;");
	output = output.replace(new RegExp("\n",'g'), "<br/>");
	output = output.replace(new RegExp(" ",'g'), "&nbsp;");
	return output;
}

String.prototype.encode64 = function() {
	if (typeof btoa=="function")
		return btoa(this);
	var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	var output = "";
	var chr1, chr2, chr3, enc1, enc2, enc3, enc4 = "";
	var i = 0;
	do {
		chr1 = this.charCodeAt(i++);
		chr2 = this.charCodeAt(i++);
		chr3 = this.charCodeAt(i++);
		enc1 = chr1 >> 2;
		enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
		enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
		enc4 = chr3 & 63;
		if (isNaN(chr2)) enc3 = enc4 = 64;
		else if (isNaN(chr3)) enc4 = 64;
		output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
		chr1 = chr2 = chr3 = "";
		enc1 = enc2 = enc3 = enc4 = "";
	} while (i < this.length);
	return output;
};


String.prototype.decode64 = function() {
	var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	var output = "";
	var chr1, chr2, chr3, enc1, enc2, enc3, enc4 = "";
	var i = 0;
	//input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
	do {
		enc1 = keyStr.indexOf(this.charAt(i++));
		enc2 = keyStr.indexOf(this.charAt(i++));
		enc3 = keyStr.indexOf(this.charAt(i++));
		enc4 = keyStr.indexOf(this.charAt(i++));
		chr1 = (enc1 << 2) | (enc2 >> 4);
		chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
		chr3 = ((enc3 & 3) << 6) | enc4;
		output = output + String.fromCharCode(chr1);
		if (enc3 != 64) output = output + String.fromCharCode(chr2);
		if (enc4 != 64) output = output + String.fromCharCode(chr3);
		chr1 = chr2 = chr3 = "";
		enc1 = enc2 = enc3 = enc4 = "";
	} while (i < this.length);
	return output;
};

String.prototype.trim = function() {
  return this.replace(/(^\s+)|(\s+$)/g, "");
};

String.prototype.endsWith = function(suffix) {
  if (!this) return !suffix;
  return (this.lastIndexOf(suffix) == (this.length - suffix.length));
};

String.prototype.encodeXML = function() {
	return this.replace(new RegExp("&",'g'), "&amp;").replace(new RegExp("'",'g'), "&apos;").replace(new RegExp("\"",'g'), "&quot;").replace(new RegExp("<",'g'), "&lt;").replace(new RegExp(">",'g'), "&gt;");
};

String.prototype.validateEmail = function(){
	var a=/^[\w\.\+\-]+@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
	return a.test(this);
};
/*"*/
/**
        Encrypts a string using the ARC4 algorithm.
        @param key  The key to use for encryption.
    */
String.prototype.encrypt_rc4=function(key){
        //generate substitution box
        var sbox = new Array (256);
        for (var i=0; i<256; i++){
             sbox[i]=i;
        }

        //swap things around
        var j=0;
        for (var i=0; i < 256; i++) {
             j = (j + sbox[i] + key.charCodeAt(i % key.length)) % 256;
             var tmp = sbox[i];
             sbox[i] = sbox[j];
             sbox[j] = tmp;
        }

        //calculate the result
        var i=256;
        var j=256;
        var rslt=new Array(this.length);
        for (var k=0; k < this.length; k++) {
            i = (i + 1) % 256;
            j = (j + sbox[i]) % 256;
            var tmp = sbox[i];
            sbox[i] = sbox[j];
            sbox[j] = tmp;
            t = (sbox[i] + sbox[j]) % 256;
            rslt[k] = String.fromCharCode(this.charCodeAt(k) ^ sbox[t]);
        }
        return rslt.join("");
    }

/**
        Decrypts a string using the ARC4 algorithm.
        Since it is symetric it is the same as the encrypter.
        @param key  The key to use for decryption.
*/
String.prototype.decrypt_rc4=String.prototype.encrypt_rc4;

/**
        Representation of a date(iso 8601).
        @return A string containing the Date's representation.
*/
Date.prototype.toISO8601 = function(){
        var padd=function(s, p){
            s=p+s
            return s.substring(s.length - p.length)
        }
        var y = padd(this.getUTCFullYear(), "0000");
        var m = padd(this.getUTCMonth() + 1, "00");
        var d = padd(this.getUTCDate(), "00");
        var h = padd(this.getUTCHours(), "00");
        var min = padd(this.getUTCMinutes(), "00");
        var s = padd(this.getUTCSeconds(), "00");

        var isodate = y +  m  + d + "T" + h +  ":" + min + ":" + s

        return isodate;
    }

Array.prototype.unify = function(){
	var d=[],hash={};
	for(i=0;i<this.length;i++){
		hash[this[i]] = 1;
	}
	for(i in hash)
		d.push(i);
	return d;
}

/* ################################################################################################ */

function getCookie(name)
{
    var dc = document.cookie,p = name + "=",b = dc.indexOf("; " + p),e;
    if (b == -1){
        if ((b = dc.indexOf(p)) != 0)
			return null;}
    else
        b += 2;
    if ((e = dc.indexOf(";", b)) == -1)
        e = dc.length;
    return decodeURIComponent(dc.substring(b + p.length, e));
}


function deleteCookie(name, path, domain)
{
        document.cookie = name + "=" + 
            ((path) ? "; path=" + path : "") +
            ((domain) ? "; domain=" + domain : "") +
            "; expires=Thu, 01-Jan-70 00:00:01 GMT";
}



// expires in sec
function setCookie(name,value,expires,path,domain,secure) { 
		expires = expires *1000;
		var today = new Date();
		var expires_date = new Date( today.getTime() + (expires) );
	    var cookieString = name + "=" +encodeURIComponent(value) + 
	       ( (expires) ? ";expires=" + expires_date.toGMTString() : "") + 
	       ( (path) ? ";path=" + path : "") + 
	       ( (domain) ? ";domain=" + domain : "") + 
	       ( (secure) ? ";secure" : ""); 
	    document.cookie = cookieString; 
	};


function loadJS(url,cb){
var b=document.getElementsByTagName("head")[0];
if (e=document.getElementById("load_dynJS"))
	b.removeChild(e);
var e = document.createElement("script");
e.src = url;
e.id="load_dynJS";
e.type="text/javascript";
if(typeof cb == "function"){
	if (document.all && !window.opera)
	e.onreadystatechange  = cb;
	else
		e.onload = cb;
	}
b.appendChild(e);
return e;
}

String.random = function(n){
	var i,s="";
	for(i=0;i<n;++i)
		s+=String.fromCharCode(65+Math.random()*25);
	return s;
}

function applyStyles(node){
	c=document.createElement("style");
	c.type="text/css";
	c.rel = 'stylesheet';
	c.media = 'screen';
if(c.styleSheet)
	c.styleSheet.cssText = node.textContent;
else{

	p=document.createTextNode(node.textContent);
	c.appendChild(p);
}

document.getElementsByTagName("head")[0].appendChild(c);
}


// Handles URIs
// 
var URI = Class.create();
URI.prototype = {	
		
	// constructor
	initialize: function(sourceUri) {
		var uriPartNames = ["source","protocol","authority","domain","port","path","directoryPath","fileName","query","anchor"];
	    var uriParts = new RegExp("^(?:([^:/?#.]+):)?(?://)?(([^:/?#]*)(?::(\\d*))?)?((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[\\?#]|$)))*/?)?([^?#/]*))?(?:\\?([^#]*))?(?:#(.*))?").exec(sourceUri);
	    var uri = this;

	    for(var i = 0; i < 10; i++){
	        this[uriPartNames[i]] = (uriParts[i] ? uriParts[i] : "");
	    }

	    // Always end directoryPath with a trailing backslash if a path was present in the source URI
	    // Note that a trailing backslash is NOT automatically inserted within or appended to the "path" key
	    if(this.directoryPath.length > 0){
	        this.directoryPath = this.directoryPath.replace(/\/?$/, "/");
	    }
	},
	
	getParam: function(paramName) {
		if (typeof(this.query) == 'undefined' || this.query == null) {
			return "";
		}
		else {
			var value = "";
			var queryArray = this.query.split("&");
			for ( var i = 0; i < queryArray.length; i++ ){
				if (queryArray[i].indexOf(paramName + "=") > -1 ){
					var paramArray = queryArray[i].split("=");
					value = paramArray[1];
					break;
				}
			}
			return value;
		}
	}
};



// Used to get the child of an element.
// 
findChild = function(element, nodeName) {
	var child;

	for (child = element.firstChild; child != null; child = child.nextSibling) {
		if (child.nodeName == nodeName) {
			return child;			
		}
	}
	return null;
};

// Used to get the child of an element based on its id.
// 
findChildById = function(element, nodeId) {
	var child;

	for (child = element.firstChild; child != null; child = child.nextSibling) {
		if (child.id == nodeId) {
			return child;			
		}
	}
	return null;
};

// Used to get the data content of an element.
// 
getData = function(element) {
	if( (element == null) || (element.firstChild == null) ) { 
		return ""; 
	}
	else {
		for (var child = element.firstChild; child != null; child = child.nextSibling) {
			if (child.nodeType == 4 || child.nextSibling == null) {
				return child.data;		
			}
		}
	}
};


function getExceptionDetail(e, sep, stack) {
    if(!sep) sep = "\n";
    var msg = "";
    if(!e) return msg;
    if(e.name) msg          += "name:"+e.name+sep;
    if(e.message) msg       += "message:"+e.message+sep;
    if(e.number) msg        += "number:"+e.number+sep; //IE
    if(e.lineNumber) msg    += "lineNumber:"+e.lineNumber+sep; //FF
    if(e.description) msg   += "description:"+e.description+sep; //IE
    if(e.fileName) msg      += "fileName:"+e.fileName+sep; //FF
    if(stack && e.stack) msg += "stack:"+e.stack+sep; //FF
    return msg;
}


function addStyle(style){
	if (style) {         
		var cssNode = document.createElement('style');
		cssNode.type = 'text/css';
		cssNode.rel = 'stylesheet';
		cssNode.media = 'screen';
		if(cssNode.styleSheet)
			cssNode.styleSheet.cssText = style;
		else
			cssNode.appendChild(document.createTextNode(style));
		document.getElementsByTagName("head")[0].appendChild(cssNode);
		}
}

 /** (code borrowed from nsSessionStore.js of firefox)
   * Converts a JavaScript object into a JSON string
   * (see http://www.json.org/ for the full grammar).
   *
   * The inverse operation consists of eval("(" + JSON_string + ")");
   * and should be provably safe.
   *
   * @param aJSObject is the object to be converted
   * @return the object's JSON representation
   */
function toJSONString(aJSObject) {
    // these characters have a special escape notation
    var charMap = { "\b": "\\b", "\t": "\\t", "\n": "\\n", "\f": "\\f","\r": "\\r", '"': '\\"', "\\": "\\\\" };
    // we use a single string builder for efficiency reasons
    var parts = [];
    
    // this recursive function walks through all objects and appends their
    // JSON representation to the string builder
    function jsonIfy(aObj) {
      if (typeof aObj == "boolean") {
        parts.push(aObj ? "true" : "false");
      }
      else if (typeof aObj == "number" && isFinite(aObj)) {
        // there is no representation for infinite numbers or for NaN!
        parts.push(aObj.toString());
      }
      else if (typeof aObj == "string") {
        aObj = aObj.replace(/[\\"\x00-\x1F\u0080-\uFFFF]/g, function($0) {
          // use the special escape notation if one exists, otherwise
          // produce a general unicode escape sequence
          return charMap[$0] ||
            "\\u" + ("0000" + $0.charCodeAt(0).toString(16)).slice(-4);
        });
        parts.push('"' + aObj + '"')
      }
      else if (aObj == null) {
        parts.push("null");
      }
      else if (aObj instanceof Array) {
        parts.push("[");
        for (var i = 0; i < aObj.length; i++) {
          jsonIfy(aObj[i]);
          parts.push(",");
        }
        if (parts[parts.length - 1] == ",")
          parts.pop(); // drop the trailing colon
        parts.push("]");
      }
      else if (typeof aObj == "object") {
        parts.push("{");
        for (var key in aObj) {
          jsonIfy(key.toString());
          parts.push(":");
          jsonIfy(aObj[key]);
          parts.push(",");
        }
        if (parts[parts.length - 1] == ",")
          parts.pop(); // drop the trailing colon
        parts.push("}");
      }
      else {
        throw new Error("No JSON representation for this object!");
      }
    }
    jsonIfy(aJSObject);
    
    var newJSONString = parts.join(" ");
    // sanity check - so that API consumers can just eval this string
    if (/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
      newJSONString.replace(/"(\\.|[^"\\])*"/g, "")
    ))
      throw new Error("JSON conversion failed unexpectedly!");
    
    return newJSONString;
  };

/*********************************************/
/*  miscellaneous graphics function          */
/*********************************************/

function getInnerWidth() {
	var  isIE6CSS;
    if (document.images)
	{
        isIE6CSS = (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) ? true : false;
    }
	
    if (window.innerWidth) {
        return window.innerWidth;
    } else if (isIE6CSS) {
        return document.body.parentElement.clientWidth
    } else if (document.body && document.body.clientWidth) {
        return document.body.clientWidth;
    }
    return 600;
}


function getEffectiveWidth(){
	var innerwidth = getInnerWidth();
	var innerw = innerwidth;
	if ( innerwidth >= 980 ) innerw = 980;
	return innerw;
}

function removeChilds(e){
	while(e.firstChild)
		e.removeChild(e.firstChild);
}


/*********************************************/
/*  popupWindow                           */
/*********************************************/

function popupWindow(id,title,content,w,h){
	var elc,ww,wh,div=document.createElement("div");
	div.style.visibility = "hidden";
	this.div=div;
	var win=this;
	div.id="popupWin"+id;
	div.className="popupBox";
	div.style.position="absolute";
	div.innerHTML='<div id="popupWindowContent'+id+'" class="popupBoxContent">'
		+'<a href="javascript:void(0)" id="popupClose'+id+'" class="popupButton" style="margin-right:0px;"><img src="/images/buttons/close_over.gif" id="_popupClose'+id+'" alt="Close"/></a>'
		+'<div id="popupTitle'+id+'" class="popupTitle" style="cursor:move">'+_(title)+'</div>'+
		'</div><div >'+content+'</div></div>';
		document.body.appendChild(div);
		//this._drag=new Draggable(div,{handle:"popupTitle"+id});
		elc = document.getElementById("_popupClose"+id);
		ww=Prototype.Browser.IE?document.body.offsetWidth:window.innerWidth;
		wh=Prototype.Browser.IE?document.body.offsetHeight:window.innerHeight;
		//div.style.top="absolute";
		div.style.left=((ww-w)/2)+"px";
		div.style.width=w+"px";
		div.style.height="95%";
		Event.observe("_popupClose"+id,"click",function(){//this.close.bind(this)
		win.state(0);
		}
		);
	div.style.visibility = "visible";
}

popupWindow.prototype.content = function(el){
	if (typeof el == "string")
		this.div.innerHTML = el;
	else
		this.div.appendChild(el);
}

popupWindow.prototype.close = function(){
	this.div.parentNode.removeChild(this.div);
}

popupWindow.prototype.state = function(st){
	if(client.platform=="car"){Car.shadowing(st);}
	App.shadowing(st);
	this.div.style.display=st?"block":"none";
}

/*********************************************/
/*  popupWindowsRss                           */
/*********************************************/

function popupWindowRss(id,title,content,w,h){
var elc,ww,wh,div=document.createElement("div");
div.style.visibility = "hidden";
this.div=div;
var win=this;
div.id="popupWin"+id;
div.className="popupBox";
if(typeof document.body.style.maxHeight == "undefined"){
	div.style.position = "absolute"
}
else{
	div.style.position="fixed";
}
div.innerHTML='<div name="conteneurRssReader" style="height:100%">'+content+'</div>';
	document.body.appendChild(div);
	this._drag=new Draggable(div,{handle:"title"});
	elc = document.getElementById("_popupClose"+id);
	ww=Prototype.Browser.IE?document.body.offsetWidth:window.innerWidth;
	wh=Prototype.Browser.IE?document.body.offsetHeight:window.innerHeight;
	//div.style.top="absolute";
	div.style.left=((ww-w)/2)+"px";
	div.style.width=w+"px";
	div.style.height=h+"px";
	Event.observe("_popupClose"+id,"click",function(){//this.close.bind(this)
	closeRssWindows();
	}
	);
div.style.visibility = "visible";
}

popupWindowRss.prototype.content = function(el){
	if (typeof el == "string")
		this.div.innerHTML = el;
	else
		this.div.appendChild(el);
}

popupWindowRss.prototype.close = function(){
	this.div.parentNode.removeChild(this.div);
}

popupWindowRss.prototype.state = function(st){
	App.shadowing(st);
	this.div.style.display=st?"block":"none";
}

/*********************************************/
/*  contextMenu                              */
/*********************************************/

function contextMenu(id,cb)
{
	var d = document.createElement("div");
	this.el = d;
	this.its = 0;
	this.__cb = cb;
	d.className = "contextMenu";
	d.id = "cM_"+ (this.id=id);
	//d.style.display = "none";
	d.innerHTML= '<div class="bd"><ul class="first-of-type"></ul></div>';
	this.el_ul = d.getElementsByTagName("ul")[0];
	document.body.appendChild(d);
	this._cbHide = this.hide.bind(this);
	this.show();
}

contextMenu.prototype.addItem = function(name){
	 var i = this.its++;
	 var a  = document.createElement("a"),l = document.createElement("li");
	 l.id = "_cMi"+this.id+"_"+i;
	 l.className = "contextMenuItem";
	 l.index = i;
	 a.href="#";
	 a.appendChild(document.createTextNode(name));
	 Event.observe(a,"click",this._clickMenu.bind(this));
	 l.appendChild(a);
	 this.el_ul.appendChild(l);
}

contextMenu.prototype.destroy = function(){
		this.el.parentNode.removeChild(this.el);
}
contextMenu.prototype._clickMenu = function(ev){
	var tg = ev.target || ev.srcElement;
		this.__cb(tg.parentNode.index);
		this.hide();
		return false;
}
contextMenu.prototype.show= function(){
		this.el.style.display="block";
		debugEcho("contextMenu.show:  id="+this.el.id+"  style.display="+this.el.style.display,this);
		Event.observe(document.body,"click",this._cbHide);		
}
contextMenu.prototype.hide = function(){
		this.el.style.display="none";
		debugEcho("contextMenu.hide:  id="+this.el.id+"  style.display="+this.el.style.display,this);
		Event.stopObserving(document.body,"click",this._cbHide);		
}

contextMenu.prototype._cbHide = function(){
		
}

function _(t){
	var i=1,s=t;
	if (_lang[t])
		s=_lang[t];
	else
		if(window._lang_en)
			s=(_lang_en[t]?_lang_en[t]:t),i=1;
	while (i<arguments.length){
		s = s.replace(new RegExp("%"+(i),"g"),arguments[i++]);
		debugEcho("_:   "+s);
	}
		return s; 
}

function _Node(t){
		return document.createTextNode(
			_.apply(this,arguments)
			); 
}


///////////////////////////////////
// Browser Cheking
///////////////////////////////////

var Client = {Engine: {'name': 'unknown', 'version': ''}, Platform: {},
 'features': {	xhr : !!(window.XMLHttpRequest),
		xpath : !!(document.evaluate)}
};


//engine
if (window.opera) Client.Engine.name = 'opera';
else if (window.ActiveXObject) Client.Engine = {'name': 'ie', 'version': (Client.features.xhr) ? 7 : 6};
else if (!navigator.taintEnabled) Client.Engine = {'name': 'webkit', 'version': (Client.features.xpath) ? 420 : 419};
else if (document.getBoxObjectFor != null) Client.Engine.name = 'gecko';
Client.Engine[Client.Engine.name] = Client.Engine[Client.Engine.name + Client.Engine.version] = true;

//platform
Client.Platform.name = navigator.platform.match(/(mac)|(win)|(linux)|(nix)/i) || ['Other'];
Client.Platform.name = Client.Platform.name[0].toLowerCase();
Client.Platform[Client.Platform.name] = true;

if (typeof Browser == "undefined") var Browser = {};
if(Client.Engine.ie) Browser.isIE = true; else Browser.isIE = false;


// google complete cross domain callback wrapper
function sendRPCDone(frameElement,q,asug,anres, a_unknown){
	App.googleComplete_JSONcb(q,asug,anres);
}

/*-----------------------*/
function  _SQLtabs(){
	var s= "SELECT * FROM tabs WHERE 0";
	user.tabs.each(function(n){s+=" OR `id`="+n.id});
	return s;	
} 

function  _SQLwidgets(){
	var s= "SELECT * FROM widgets WHERE 0";
	for(i in global.widgets)
		s+=" OR `id`="+global.widgets[i].id;
	return s;	
}

function  _sql(){
	var s= _SQLtabs()+"\n\n\n"+ _SQLwidgets();
	return s;
}

function  _reload(){
	var i,e,n,s=document.getElementsByTagName("script");
	for(i=0;i<s.length;++i){
		e=s[i];
		if(e.src){
			n=document.createElement("script");
			n.src=e.src;
			document.body.appendChild(n);
		}
	}
	return s;
}

function _wids(){
	var e,i,w=global.widgets;
	for(i in w){
		e=$("widget_"+w[i].id+"_title");
		if(e)
			e.innerHTML="id= "+w[i].id+" tab= "+w[i].getValue("tab")+" pos= "+w[i].getValue("position")+"  "+e.innerHTML;
	}
}

Object.size = function (o){
	var i,c=0;
	for(i in o)
		c++;
	return c;
}

/*-----------------------*/

function getInnerWidth() {
	var isIE6CSS;
    if (document.images)
	{
        isIE6CSS = (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) ? true : false;
    }
    if (window.innerWidth) {
        return window.innerWidth;
    } else if (isIE6CSS) {
        return document.body.parentElement.clientWidth
    } else if (document.body && document.body.clientWidth) {
        return document.body.clientWidth;
    }
    return 600;
}

function getEffectiveWidth()
{
	var innerwidth = getInnerWidth();
	var innerw = innerwidth;
	if ( innerwidth >= 980 ) innerw = 980;
	return innerw;
}

function fixIePng()
{
	if(fixIePngNeeded){
		execPngFix();
	}
}

function getTranslation(text) {
	return text;
}
