//      babadom2.js
//      
//      Copyright 2010 Babaorum <babaorum@baba0rum.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

var doc = document;
var body = doc.body;

utils = {
    encode: function(s, encoding) {
        encoding = encoding || "UTF-8";
 
        var result = "";
 
        if(encoding == "UTF-8") {
            var s = s.replace(/\r\n/g, "\n");
 
            for(var index = 0; index < s.length; index++) {
                var c = s.charCodeAt(index);
 
                if(c < 128) {
                    result += String.fromCharCode(c);
                }
                else if((c > 127) && (c < 2048)) {
                    result += String.fromCharCode((c >> 6) | 192);
                    result += String.fromCharCode((c & 63) | 128);
                }
                else {
                    result += String.fromCharCode((c >> 12) | 224);
                    result += String.fromCharCode(((c >> 6) & 63) | 128);
                    result += String.fromCharCode((c & 63) | 128);
                }
            }
        }
        else {
            throw new Error("Unknown encoding: \"" + encoding + "\"");
        }
 
        return result;
    },
 
    decode: function(s, encoding) {
        encoding = encoding || "UTF-8";
 
        var result = "";
 
        if(encoding == "UTF-8") {
            var index = 0;
            var c = c1 = c2 = 0;
 
            while(index < s.length) {
                c = s.charCodeAt(index);
 
                if(c < 128) {
                    result += String.fromCharCode(c);
                    index++;
                }
                else if((c > 191) && (c < 224)) {
                    c2 = s.charCodeAt(index + 1);
                    result += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                    index += 2;
                }
                else {
                    c2 = s.charCodeAt(index + 1);
                    c3 = s.charCodeAt(index + 2);
                    result += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                    index += 3;
                }
            }
        }
        else {
            throw new Error("Unknown encoding: \"" + encoding + "\"");
        }
 
        return result;
    },
    
	log: function(text) {
		try { console.log(text); } catch(e) {}
		try { dbg.log(text); } catch(e) {}
		try {
			var s = "";
			for(var n = 0, arg; arg = arguments[n]; n++) {
				if(s != "") s += "\n";
				if(typeof arg == "undefined") s += "ERROR : argument #" + (n + 1) + " is UNDEFINED !"
				else if(/string|number|boolean/.test(typeof arg)) s += arg;
				else if(typeof arg == "object") s += arg.toSource();
			}
			GM_log(s);
		} catch(e) {}
	},
	undef: function(something) {
		return (typeof something == "undefined" || something == null);
	},
	defined: function(something) {
		return (typeof something != "undefined" && something != null);
	},
	isString: function(something) {
		return (typeof something == "string");
	},
	isNumber: function(something) {
		return (typeof something == "number");
	},
	isBoolean: function(something) {
		return (typeof something == "boolean");
	},
	isStringNumber: function(something) {
		return (typeof something == "string" || typeof something == "number");
	},
	isStringNumberBoolean: function(something) {
		return (typeof something == "string" || typeof something == "number" || typeof something == "boolean");
	},
	isArray: function(something) {
		return (typeof something == "object" && typeof something.filter == "function");
	},
	isObject: function(something) {
		return (typeof something == "object" && typeof something.filter != "function");
	},
	isDomNode: function(something) {
		return (typeof something == "object" && typeof something.filter != "function" && (something.nodeType == 1 || something.nodeType == 3));
	},
	keys: function(obj) {
		var list = [];
		for(var key in obj)
			list.push(key);
		return list;
	},
	values: function(obj) {
		var list = [];
		for(var key in obj)
			list.push(obj[key]);
		return list;
	},
	objlen: function(obj) {
		if (typeof obj == "object" && typeof obj.filter == "undefined")
		{
			var n = 0;
			for (var prop in obj) n++;
			return n++
		}
		else return false;
	},
	//Fonction d'insertion d'un script JavaScript dans la page
	injectScript : function(url, id)
	{
		if(typeof document.getElementsByTagName("head") != "undefined")
		{
			var oScript = document.createElement("script");
			oScript.setAttribute("type", "text/javascript");
			if(typeof url == "string") oScript.setAttribute("src", url);
			else if(typeof url == "function") oScript.appendChild(document.createTextNode(url.toSource()));
			oScript.setAttribute("id", id);
			document.getElementsByTagName("head")[0].appendChild(oScript);
			return true;
		}
		else return false;
	},
	wikify : function(texte)
	{
		var remplacements = {
			"âàä" : "a",
			"éêèë" : "e",
			"îï" : "i",
			"ôö" : "o",
			"ûùü" : "u",
			"[^a-zA-Z0-9_]" : "_",
			"_+" : "_",
			"^_*" : "",
			"_*$" : ""
		};
		for (var motif in remplacements)
		{
			var re = new RegExp(motif, "g");
			texte = texte.replace(re, remplacements[motif]);
			console.info(texte);
		}
		return texte;
	}
};

dom = {
	id: function(id) {
		return doc.getElementById(id);
	},
	tag: function(node, tag, nth) {
		if(node == "doc") node = document.body;
		var elements=node.getElementsByTagName(tag);
		return (utils.defined(nth)? elements.item(nth) : elements);
	},
	name: function(name, nth) {
		var elements=document.getElementsByName(name);
		return (utils.defined(nth)? elements.item(nth) : elements);
	},
	classname: function(node, classname, nth) {
		if (node = "doc") node = document.body;
		if (utils.defined(node)
		 && utils.isDomNode(node)
		 && utils.defined(node.classname)
		 && node.classname != "")
		{
			var elements = node.getElementsByClassName(classname);
			return (utils.defined(nth) && utils.isNumber(nth) && utils.defined(elements.item(nth))) ?
				elements.item(nth) : elements;
		}
		else
			return false;
			//~ return "Node " + node.toString() + " is not defined or not a valid DOM node";
	},
	att: function(node, attr, newvalue) {
		//~ if(utils.undef(newvalue)) return node.getAttribute(attr);
		//~ else node.setAttribute(attr, newvalue);
		if(utils.isObject(attr))
			for(var attribute in attr) node.setAttribute(attribute, attr[attribute]);
		else if(utils.isString(attr)) {
			if(utils.undef(newvalue)) return node.getAttribute(attr);
			else node.setAttribute(attr, newvalue);
		}
	},
	add: function(root, node) {
		if(root == "doc") root = document.body;
		if(utils.isDomNode(node))
			root.appendChild(node);
		else if(utils.isArray(node))
			for(var n = 0, onenode; onenode = node[n]; n++) root.appendChild(onenode);
		return root;
	},
	insertb: function(root, node, refnode) {
		if(root == "doc") root = document.body;
		if(typeof refnode == "number") root.insertBefore(node, root.childNodes[refnode]);
		else root.insertBefore(node, refnode);
	},
	inserta: function(root, node, refnode) {
		if(root == "doc") root = document.body;
		if(typeof refnode == "number") root.insertBefore(node, root.childNodes[refnode].nextSibling);
		else root.insertBefore(node, refnode.nextSibling);
	},
	before: function(refnode, node) {
		refnode.parentNode.insertBefore(node, refnode);
	},
	after: function(refnode, node) {
		refnode.parentNode.insertBefore(node, refnode.nextSibling);
	},
	txt: function(text) {
		return doc.createTextNode(text);
	},
	el: function(tag, params, css) {
		var element = doc.createElement(tag);
		if(typeof params == "object") {
			for(var prop in params) {
				var value = params[prop];
				if(prop == "text") element.appendChild(dom.txt(value));
				else if(prop == "html") element.innerHTML = value;
				else dom.att(element, prop, value);
			}
		}
		if(typeof css == "object")
			for(var prop in css) {
				var value = css[prop];
				element.style[prop] = value;
			}
		return element;
	},
	filter: function(array, condition) {
		if(utils.isArray(array)) {
			var returnarray = new Array();
			for(var n=0; n<array.length; n++) {
				var s = condition.replace(/element/g, "array[n]").replace(/index/g, "n");
				var condition = eval(s);
				if(condition) returnarray.push(array[n]);
			}
			return returnarray;
		}
		else return false;
	},
	get: function(root, tag, attributes, nth) {
		if(typeof root == "object" && typeof tag == "string" && typeof attributes == "object") {
			var nodes = new Array();
			for(var n = 0, node ; node = dom.tag(root, tag, n) ; n++) {
				var attributesOK = true;
				for(var prop in attributes) {
					//si l'attribut (attributes[prop]) est défini, non nul et qu'il est ce qui est recherché, alors:
					//true && true = true ; sinon : true && false = false
					//attributesOK reste "true" tant que TOUS les attributs recherchés sont valides (=true),
					//au premier false, attributesOK devient et **restera** false
					//(car : false && false = false, mais aussi: false && true = false ...)
					var test = ( utils.defined(dom.att(node, prop)) && node.getAttribute(prop) == attributes[prop] );
					attributesOK = (attributesOK && test);
				}
				if(attributesOK) nodes.push(node);
			}
			if(utils.defined(nth) && utils.defined(nodes[nth])) return nodes[nth];
			else return nodes;
		}
	},
	style: function(node, cssrules, newvalue) {
		if(utils.isDomNode(node)) {
			if(utils.isObject(cssrules))
				for(var prop in cssrules) node.style[prop] = cssrules[prop];
			else if(utils.isString(cssrules)) {
				var prop = cssrules;
				if(utils.defined(newvalue))	node.style[prop] = newvalue;
				else return node.style[prop];
			}
		}
	},
	getSelect: function(node) {
		if(utils.isDomNode(node) && node.tagName.toLowerCase() == "select" 
		                         && typeof node.selectedIndex == "number")
			return node.options[node.selectedIndex].value;
		else return false;
	},
	hide: function(node) {
		if(utils.isDomNode(node)) node.style.display = "none";
		else return false;
	},
	show: function(node, display) {
		if(utils.isDomNode(node)) node.style.display = display || "";
		else return false;
	},
	toggleDisplay: function(node, defaultValue) {
		if(utils.isDomNode(node))
			node.style.display = (node.style.display == defaultValue ? "none": defaultValue);
	},
	hasClass: function(node, classes)
	{
		if (utils.isDomNode(node))
		{
			if (utils.isStringNumber(classes))
			{
				var re = new RegExp(classes);
				return re.test(dom.att(node, "class"));
			}
			else if (utils.isArray(classes))
			{
				for (var n = 0, c; c = classes[n]; n++)
				{
					var re = new RegExp(c);
					if (re.test(dom.att(node, "class")))
					{
						return true;
						break;
					}
				}
				return false;
			}
		}
	},
	getAncestor: function(node, level)
	{
		var ancestor = node;
		for (var n = 0; n < level; n++)
			ancestor = ancestor.parentNode;
		return ancestor;
	},
	getAncestorTag: function(node, tag, level)
	{
		var ancestor = node;
		var ancestorLevel = 0;
		while (true)
		{
			ancestor = ancestor.parentNode;
			if (ancestor.tagName.toLowerCase() == tag.toLowerCase())
			{
				ancestorLevel++;
				if (ancestorLevel == level) return ancestor;
			}
			if (ancestor.tagName.toLowerCase() == "document") break;
		}
		return false;
	}
};

dom.css = dom.style;

ui = {
	popup : function(id, content, params, cssContainer, cssTitle, cssContent)
	{
	/*
		propriétés possibles de params :
		 - title : titre du popup
		 - anchor : noeud DOM sur lequel sera branché le popup dans l'arborescence DOM
	*/
		var popup, closebutton;
		if(utils.undef(params)) params = { title: "", anchor: document.body };
		if(utils.undef(cssContainer))
		{
			cssContainer = {
				width: "auto",
				height: "auto",
				fontSize: "11px",
				backgroundColor: "white",
				color: "black",
				borderWidth: "1px",
				borderStyle: "solid",
				borderColor: "black",
				opacity: 0.8
			};
		}
		//~ if(utils.defined(dom.id(id)))
		if(dom.id(id))
		{
			popup = document.getElementById(id);
			popup.innerHTML = "";
			popup.style.display = "";
		}
		else
		{
			//création du popup
			popup = document.createElement("div");
			popup.setAttribute("id", id);
			popup.className = "babadom2_popup";
			popup.style.position = "absolute";
			popup.style.zIndex = 1000;
		}
		//bouton de fermeture
		closebutton = dom.el("div", {
			class: "babadom2_popup_close",
			id: id + "_close",
			title: "Fermer",
			style: "float: right;",
			text: " "
		}, {
			position: "relative",
			top: 0,
			left: 0,
			width: "18px",
			height: "18px",
			backgroundImage: "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAADAFBMVEUAAAD%2FAAAA%2FwD%2F%2FwAAAP%2F%2FAP8A%2F%2F%2F%2F%2F%2F%2Fb29u2traSkpJtbW1JSUkkJCTbAAC2AACSAABtAABJAAAkAAAA2wAAtgAAkgAAbQAASQAAJADb2wC2tgCSkgBtbQBJSQAkJAAAANsAALYAAJIAAG0AAEkAACTbANu2ALaSAJJtAG1JAEkkACQA29sAtrYAkpIAbW0ASUkAJCT%2F29vbtra2kpKSbW1tSUlJJCT%2FtrbbkpK2bW2SSUltJCT%2FkpLbbW22SUmSJCT%2FbW3bSUm2JCT%2FSUnbJCT%2FJCTb%2F9u227aStpJtkm1JbUkkSSS2%2F7aS25Jttm1JkkkkbSSS%2F5Jt221JtkkkkiRt%2F21J20kktiRJ%2F0kk2yQk%2FyTb2%2F%2B2ttuSkrZtbZJJSW0kJEm2tv%2BSktttbbZJSZIkJG2Skv9tbdtJSbYkJJJtbf9JSdskJLZJSf8kJNskJP%2F%2F%2F9vb27a2tpKSkm1tbUlJSST%2F%2F7bb25K2tm2SkkltbST%2F%2F5Lb2222tkmSkiT%2F%2F23b20m2tiT%2F%2F0nb2yT%2F%2FyT%2F2%2F%2Fbttu2kraSbZJtSW1JJEn%2Ftv%2Fbktu2bbaSSZJtJG3%2Fkv%2Fbbdu2SbaSJJL%2Fbf%2FbSdu2JLb%2FSf%2FbJNv%2FJP%2Fb%2F%2F%2B229uStrZtkpJJbW0kSUm2%2F%2F%2BS29tttrZJkpIkbW2S%2F%2F9t29tJtrYkkpJt%2F%2F9J29sktrZJ%2F%2F8k29sk%2F%2F%2F%2F27bbtpK2km2SbUltSSRJJAD%2FtpLbkm22bUmSSSRtJAD%2Fttvbkra2bZKSSW1tJElJACT%2FkrbbbZK2SW2SJEltACTbtv%2B2ktuSbbZtSZJJJG0kAEm2kv%2BSbdttSbZJJJIkAG222%2F%2BSttttkrZJbZIkSW0AJEmStv9tkttJbbYkSZIAJG22%2F9uS27ZttpJJkm0kbUkASSSS%2F7Zt25JJtm0kkkkAbSTb%2F7a225KStm1tkklJbSQkSQC2%2F5KS221ttklJkiQkbQD%2FtgDbkgC2bQCSSQD%2FALbbAJK2AG2SAEkAtv8AktsAbbYASZIAAAAAAADPKgIEAAAAqElEQVQoz2Msyw5jIB2w%2FPnzlxxtf%2F%2BSqe0PPW1D9VvLhCUMDAw1BTF4RBgYGJj%2B%2FP2DjOBKIVyIHgYGBjRljPEh9mgO6J62Gk2kNCsUTYTp75%2B%2FaKgoLQhZRVFaEKYawiGJVQEThkF%2FJ87dhKxi4txNmGqY0ESmLtgKUZ0R654R6w5hT12wFU0Zut8g6lIjXSDc1EgXqFNRlTH6OGiTlZQHMnHRNgcAAK4Z6c1VXo8HAAAAAElFTkSuQmCC)",
			backgroundRepeat: "no-repeat",
			backgroundPosition: "top left",
			cursor: "pointer",
		});
		dom.add(popup, closebutton);
		//insérer le titre
		if(utils.defined(params.title))
		{
			var titlediv = dom.el("div", {
				class: "babadom2_popup_title",
				id: id + "_title",
				text: (params.title || "")
			}, {
				fontSize: "1.25em",
				fontWeight: "bold",
				textAlign: "center",
				textIndent: closebutton.style.width,
				backgroundColor: "#666",
				color: "white",
				minHeight: "18px"
			});
			if(utils.defined(cssTitle))
				for(var prop in cssTitle) dom.style(titlediv, prop, cssTitle[prop]);
			dom.add(popup, titlediv);
		}
		//insérer le contenu
		dom.add(popup, dom.el("div", {
			class: "babadom2_popup_content",
			id: id + "_content",
			html: content
		}, (cssContent || {})));
		//Placer le conteneur
		if(utils.undef(params.anchor))
		{
			anchor_ = document.body;
			//~ popup.style.top = "4px";
			//~ popup.style.left = "4px";
			popup.style.top = "0px";
			popup.style.left = "0px";
		}
		else anchor_ = params.anchor;
		dom.add(anchor_, popup);
		//appliquer le style
		for(var prop in cssContainer) popup.style[prop] = cssContainer[prop];
		//évènement de fermeture du popup
		var closebutton = dom.get(dom.id(id), "div", { class: "babadom2_popup_close" }, 0);
		closebutton.addEventListener("click", function()
			{
				var div = dom.id(id) || this.parentNode;
				div.style.display = "none"; }
			, true);
		popup.style.display = "block";
		return popup;
	}
};


/**
*
*  UTF-8 data encode / decode
*  http://www.webtoolkit.info/
*
**/
 
utf8 = {
 
	// public method for url encoding
	encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";
 
		for (var n = 0; n < string.length; n++) {
 
			var c = string.charCodeAt(n);
 
			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
 
		}
 
		return utftext;
	},
 
	// public method for url decoding
	decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;
 
		while ( i < utftext.length ) {
 
			c = utftext.charCodeAt(i);
 
			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}
 
		}
 
		return string;
	}
 
};




if (typeof u == "undefined") u = utils;

