/**
 * IHM - Interface between Humans and Machine
 *
 * Javascript 1.3 compliant
 * Compatibility tested with :
 * - Internet Explorer 6.0
 * - Firefox 1.5
 * If you tested with other browsers, please send and email to compatibility@pillot.fr
 *
 * LICENCE: This source file is subject to version of the GPL license
 * that is available through the world-wide-web at the following URL :
 * http://www.gnu.org/licenses/gpl.txt.  If you did not receive a copy of
 * the GPL License and are unable to obtain it through the web, please
 * send a note to license@pillot.fr so we can mail you a copy immediately.
 *
 * @author    Baptiste Pillot <baptiste@pillot.fr>
 * @copyright 2000-2006 Baptiste Pillot
 * @license   http://www.gnu.org/licenses/gpl.txt
 * @log
 * 2006-06-16 BP + formToUrl + urlEncode for parameters
 * 2007-11-15 BP + urlEncode with multiple + encoding
 * @link      http://www.pillot.fr
 * 2008-06-25 EC Dynamic_Lines_move : éviter d'intervertir la 1ère ligne avec la ligne de titre
 */

//##############################################################################
//============================================================================== Misc functions

//------------------------------------------------------------------------------ var ihm_time
/** ihm_time gives the number of seconds executed since IHM beginning */
var ihm_time = 0;

//------------------------------------------------------------------------------ function counterSeconds
function counterSeconds()
{
	window.setTimeout("counterSeconds();",1000);
	ihm_time++;
}
counterSeconds();

//------------------------------------------------------------------------------ function formAutoClone
function formAutoClone(layer)
{
	formAutoCloneOnChange(layer, layer);
}

//------------------------------------------------------------------------ function formAutoCloneDo
function formAutoCloneDo(layer)
{
	alert("clone" + layer.id);
}

//------------------------------------------------------------------ function formAutoCloneOnChange
function formAutoCloneOnChange(layer, layer_to_clone)
{
	var action = "formAutoCloneDo(layerFind('" + layer_to_clone.id + "'));";
	if (layer.tagName == "SELECT") layer.onchange = action;
	if (layer.tagName == "INPUT") layer.onkeypress = action;
	for (var i = 0; i<layer.childNodes.length; i++) {
		formAutoCloneOnChange(layer.childNodes[i], layer_to_clone);
	}
}

//--------------------------------------------------------------------------- function formCheckAll
function formCheckAll(form, check)
{
	if (check == undefined) {
		check = true;
	}
	if (form && form.elements) {
		for (var i = 0; i < form.elements.length; i++) {
			if (form.elements[i].type == "checkbox") {
				form.elements[i].checked = check;
			}
		}
	}
}

//---------------------------------------------------------------------- function formContainsFiles
/**
 * Return true if form contains files
 */
function formContainsFiles(form)
{
	if (form.elements) {
		for (var i = 0; i < form.elements.length; i++) {
			if (form.elements[i].type == "file" && form.elements[i].value) {
				return true;
			}
		}
	}
	return false;
}

//--------------------------------------------------------------------- function formElementFollows
/**
 * Return first element of form that follows from element and is named name
 */
function formElementFollows(form, from, name)
{
	var from_now = false;
	var found = null;
	for (var i = 0; i < form.elements.length && !found; i++) {
		// begin real search on document_lines_from element, memorised by caller
		if (form.elements[i] === from) {
			from_now = true;
		}
		// found destination field and set found
		if (from_now && form.elements[i].name === name) {
			found = form.elements[i];
			from_now = false;
		}
	}
	return found;
}

//-------------------------------------------------------------------------- function formElementId
/**
 * Return element id in its form's elements array property
 */
function formElementId(element)
{
	var index = 0;
	for (var i = 0; i < element.form.elements.length && !index; i++) {
		if (element.form.elements[i] === element) {
			index = i;
		}
	}
	return index;
}

//--------------------------------------------------------------------- function formElementFollows
/**
 * Return first element of form that is previous element and is named name
 */
function formElementPrevious(form, from, name)
{
	var from_now = false;
	var found = null;
	for (var i = form.elements.length - 1; i >=0 && !found; i--) {
		// begin real search on document_lines_from element, memorised by caller
		if (form.elements[i] === from) {
			from_now = true;
		}
		// found destination field and set found
		if (from_now && form.elements[i].name === name) {
			found = form.elements[i];
			from_now = false;
		}
	}
	return found;
}

//------------------------------------------------------------------------------ function formToUrl
/**
 * Return form content as an url component like var=val&var2=val2&...
 * If prefix is given, this will return prefix[var]=val&prefix[var2]=val2&...
 */
function formToUrl(form, prefix, exclude, prm)
{
	if (prm == undefined) {
		var prm = "";
	}
	var deja = Array();
	var field = "";
	var pos = 0;
	if (form.elements) {
		if (exclude == undefined) {
			exclude = "-";
		}
		for (var i = 0; i < form.elements.length; i++) {
			if (form.elements[i].name && form.elements[i].name.substr(0, exclude.length) != exclude) {
				if (prm) prm = prm + "&";
				field = form.elements[i].name;
				if (prefix) {
					pos = field.indexOf("[");
					if (pos > -1) {
						field = "[" + field.substr(0, pos) + "]"
						+ field.substr(field.indexOf("["));
					} else {
						field = "[" + field + "]";
					}
					prm = prm + prefix;
				}
				prm = prm + field;
				if (form.elements[i].type == "checkbox") {
					prm = prm + "=" + (form.elements[i].checked ? (((form.elements[i].value && (form.elements[i].value != "on"))) ? form.elements[i].value : "1") : "0");
				} else if (form.elements[i].type == "radio") {
					if (form.elements[i].checked) {
						prm = prm + "=" + urlEncode(form.elements[i].value);
					}
				} else if (form.elements[i].type != "file") {
					prm = prm + "=" + urlEncode(form.elements[i].value);
				}
			}
		}
	}
	if (form.merged_form != undefined) {
		prm = formToUrl(form.merged_form, prefix, exclude, prm); 
	}
	return prm;
}

//------------------------------------------------------------------------------- function isChkDis
function isChkDis(form)
{
	var checkbox = false;
	if (form.elements) {
		for (var i = 0; i < form.elements.length; i++) {
			if (form.elements[i].type == "checkbox") {
				if (form.elements[i].checked) {
					return true;
				} else {
					checkbox = true;
				}
			}
		}
	}
	if (checkbox) {
		alert("Please check anything\nVeuillez sélectionner un élément");
	}
	return false;
}

//------------------------------------------------------------------------------- function nextNode
/**
 * Returns next node following start node, using criterium 
 * Default criterium is "id". Can use "id", "className", "tagName", etc.
 *
 * @param node start first node to search in
 * @param string search search string (ie : "my_node_id")
 * @param string criterium node's property to search in (default: "id")
 * @param bool reverse true to execute a reverse search (default: false)
 * @param bool no_parent_search true to disable search into node's parents (default: false)
 */
function nextNode(start, search, criterium, reverse, no_parent_search)
{
	if (criterium == undefined) {
		criterium = "id";
	}
	if (reverse == undefined) {
		reverse = false;
	}
	if (no_parent_search == undefined) {
		no_parent_search = false;
	}
	var found;
	var expr = "found = start." + criterium + ' == "' + search + '" ? start : false;';
	// test current start node
	eval(expr);
//eval("alert(start.tabName + ' : ' + criterium + ' = ' + start." + criterium + ");");
	// search into child nodes
	if (!found && (!reverse ? start.firstChild : start.lastChild)) {
//alert(start.tagName + " : go firstChild");
		found = nextNode(!reverse ? start.firstChild : start.lastChild, search, criterium, reverse, true);
//alert(start.tagName + " : back from firstChild");
	}
	// search into next node
	if (!found && (!reverse ? start.nextSibling : start.previousSibling)) {
//alert(start.tagName + " : go nextSibling");
		found = nextNode(!reverse ? start.nextSibling : start.previousSibling, search, criterium, reverse, true);
	}
	// look if parent node corresponds (reverse mode only)
	if (!found && reverse && start.parentNode) {
		var back_start = start;
		start = start.parentNode;
		eval(expr);
//eval("alert(start.tagName + ' : ' + criterium + ' = ' + start." + criterium + ");");
		start = back_start;
	}
	// search into parent node
	if (!found && !no_parent_search && start.parentNode) {
		while (!found && start.parentNode && (!reverse ? !start.parentNode.nextSibling : !start.parentNode.previousSibling)) {
			start = start.parentNode;
			if (!found && reverse && start.parentNode) {
				var back_start = start;
//alert(start.tagName + " : go parentNode");
				start = start.parentNode;
				eval(expr);
//eval("alert(start.tagName + ' : ' + criterium + ' = ' + start." + criterium + ");");
				start = back_start;
			}
		}
		if (!found && start.parentNode && (!reverse ? start.parentNode.nextSibling : start.parentNode.previousSibling)) {
//alert(start.tagName + " : go parentNode.nextSibling");
			found = nextNode(!reverse ? start.parentNode.nextSibling : start.parentNode.previousSibling, search, criterium, reverse, no_parent_search);
		}
	}
	// return found node
//if (found) eval("alert(found.tagName + ' : ' + criterium + ' = ' + found." + criterium + " + ' was found');");
	return found;
}

//--------------------------------------------------------------------------- function previousNode
/**
 * Same as nextNode, with reverse search
 * (see nextNode)
 */
function previousNode(start, search, criterium, reverse, no_parent_search)
{
	return nextNode(start, search, criterium, reverse ? false : true, no_parent_search);
}

//------------------------------------------------------------------------- function selectionEmpty
function selectionEmpty()
{
	// IE only
	if (document.selection) document.selection.empty();
}

//------------------------------------------------------------------------------ function urlEncode
/**
 * Encode a string to be included into an url
 * Identical to escape, but plus + replacements
 * Use this to replace each element of an url, and not the complete url !
 */
function urlEncode(str)
{
	str = escape(str);
	// +
	while (str.indexOf("+") > -1) {
		str = str.replace("+", "%2B");
	}
	// €
	while (str.indexOf("%u20AC") > -1) {
		str = str.replace("%u20AC", "%80");
	}
	// ?
	while (str.indexOf("%u0103") > -1) {
		str = str.replace("%u0103", "%C4%83");
	}
	return str;
}

//################################################################################# Mouse functions
// Capture des évenements de souris, mise à jour des coordonnées mouse_x et mouse_y,
// et de l'état de la souris. Appel des sous-événements sur l'objet pointé.
var mouse_x      = 0;
var mouse_y      = 0;
var mouse_status = 0;
var mouse_drag_x  = 0;
var mouse_drag_y  = 0;
var mouse_drop_x  = 0;
var mouse_drop_y  = 0;
var mouse_controls     = null;
var mouse_drag_control = null;
var mouse_drop_control = null;
var mouse_right_block = false;

//---------------------------------------------------------------------------- function OnMouseMove
function OnMouseMove(e)
{
	// mise à jour des coordonnées de la souris
	if (e) {
		mouse_x = e.pageX;
		mouse_y = e.pageY;
	} else {
		// IE : temporary move 2 pixels left, please search corresponding variable
		mouse_x = event.clientX + document.body.scrollLeft - 2;
		mouse_y = event.clientY + document.body.scrollTop - 2;
	}
	// liste des contrôles sur lesquels pointe la souris
	mouse_controls = controlsAtXY(mouse_x, mouse_y);
	var dragged = false;
	if (mouse_controls) {
		// déclenche onMouseMove pour chacun d'entre eux
		for (var i = 0; i < mouse_controls.length ; i++) {
			if (mouse_controls[i] == mouse_drag_control) {
				dragged = true;
			}
			mouse_controls[i].onMouseMove(e);
		}
	}
	// déclenche onMouseMove pour le contrôle en cours de drag&drop
	if (mouse_drag_control && !dragged) {
		mouse_drag_control.onMouseMove(e);
	}
}
document.onmousemove = OnMouseMove;

//---------------------------------------------------------------------------- function OnMouseDown
function OnMouseDown(e)
{
	mouse_drag_x = mouse_x;
	mouse_drag_y = mouse_y;
	mouse_status = 1;
	mouse_drag_control = controlAtXY(mouse_drag_x, mouse_drag_y);
	if (mouse_drag_control) {
		mouse_drag_control.onMouseDown(e);
	}
}
document.onmousedown = OnMouseDown;

//------------------------------------------------------------------------------ function OnMouseUp
function OnMouseUp(e)
{
	mouse_drop_x = mouse_x;
	mouse_drop_y = mouse_y;
	mouse_status = 0;
	mouse_drop_control = controlAtXY(mouse_drop_x, mouse_drop_y);
	if (mouse_drag_control) {
		mouse_drag_control.onMouseUp(e);
	}
}
document.onmouseup = OnMouseUp;

//--------------------------------------------------------------------------- function OnMouseRight
function OnMouseRight(e)
{
	mouse_right_x = mouse_x;
	mouse_right_y = mouse_y;
	mouse_status = 0;
	mouse_right_control = controlAtXY(mouse_right_x, mouse_right_y);
	if (mouse_right_control) {
		mouse_right_control.onMouseRight(e);
	}
	if (mouse_right_block) {
		return false;
	}
}
document.oncontextmenu = OnMouseRight;

//---------------------------------------------------------------------------------- initialisation
if (document.captureEvents) {
	document.captureEvents(Event.MOUSEMOVE);
}

//################################################################################### Key functions

function event_key_decode(event)
{
	if (event.keyCode) {
		return event.keyCode;
	} else if (event.which) {
		return event.which;
	}
}

//##############################################################################
//============================================================================== Layers functions

/** ajax zIndex */
var layer_zindex = 1;

//----------------------------------------------------------------------------- function layerPosX
// lecture des coordonnées d'un layer
function layerPosX(ctrl,absolute)
{
	if (ctrl.offsetParent && absolute !== false) {
		return ctrl.offsetLeft + layerPosX(ctrl.offsetParent);
	} else {
		return ctrl.offsetLeft;
	}
}

//----------------------------------------------------------------------------- function layerPosY
function layerPosY(ctrl,absolute)
{
	if (ctrl.offsetParent && absolute !== false) {
		return ctrl.offsetTop + layerPosY(ctrl.offsetParent);
	} else {
		return ctrl.offsetTop;
	}
}

//--------------------------------------------------------------------------- function layerToFront
/** Bring layer to front of others layers */
function layerToFront(layer)
{
	if (layer.style !== undefined) {
		layer.style.zIndex = layer_zindex++;
	}
}

//----------------------------------------------------------------------------- function layerWidth
function layerWidth(ctrl)
{
	if (ctrl.nodeName == "DIV" && ctrl.firstChild && ctrl.firstChild.offsetWidth) {
		return ctrl.firstChild.offsetWidth;
	} else {
		return ctrl.offsetWidth;
	}
}

//----------------------------------------------------------------------------- function layerHeight
function layerHeight(ctrl)
{
	return ctrl.offsetHeight;
}

//----------------------------------------------------------------------------- function layerPosX2
function layerPosX2(ctrl)
{
	return layerPosX(ctrl) + layerWidth(ctrl) - 1;
}

//----------------------------------------------------------------------------- function layerPosY2
function layerPosY2(ctrl)
{
	return layerPosY(ctrl) + layerHeight(ctrl) - 1;
}

//------------------------------------------------------------------------------ function layerSetPosXY
// modifie les coordonnées d'un layer
function layerSetPosXY(ctrl, x, y)
{
	ctrl.style.left = x;
	ctrl.style.top = y;
}

//------------------------------------------------------------------------------ function layerSetPosX
function layerSetPosX(ctrl, x)
{
	ctrl.style.left = x;
}

//------------------------------------------------------------------------------ function layerSetPosY
function layerSetPosY(ctrl, y)
{
	ctrl.style.top = y;
}

//------------------------------------------------------------------------------ function layerSetWidth
function layerSetWidth(ctrl, width)
{
	ctrl.style.width = width;
}

//------------------------------------------------------------------------------ function layerSetHeight
function layerSetHeight(ctrl, height)
{
	ctrl.style.height = height;
}

//------------------------------------------------------------------------------ function layerFind
// renvoie un layer à partir de son nom
function layerFind(name)
{
	if (document.getElementById) return document.getElementById(name);
	if (document.layers)         return document.layers(name);
	if (document.all)            return document.all(name);
	if (document[name])          return document[name];
	return false;
}

//------------------------------------------------------------------------------ function layerHide
// cache un layer
function layerHide(layer, method)
{
	if (method == "display") {
		if (layer.style) {
			layer.style.display = "none";
		}
	} else {
		if (layer.visibility) {
			layer.visibility = "hide";
		} else if (layer.style) {
			layer.style.visibility = "hidden";
		}
	}
}

//------------------------------------------------------------------------------ function layerShow
// affiche un layer
function layerShow(layer, method)
{
	if (method == "display") {
		if (layer.style) {
			layer.style.display = "";
		}
	} else {
		if (layer.visibility) {
			layer.visibility = ((method == undefined) ? "show" : method);
		} else if (layer.style) {
			layer.style.visibility = ((method == undefined) ? "visible" : method);
		}
	}
}

//--------------------------------------------------------------------------- function layerVisible
function layerVisible(layer, method)
{
	if (method == "display") {
		if (layer.style && (layer.style.display == "none")) {
			return false;
		}
	} else {
		if (layer.visibility) {
			if (layer.visibility == "hide") {
				return false;
			}
		} else if (layer.style) {
			if (layer.style.visibility == "hidden") {
				return false;
			}
		}
	}
	return true;
}

//---------------------------------------------------------------------------- function layerSwitch
function layerSwitch(layer, method)
{
	if (layerVisible(layer, method)) {
		layerHide(layer, method);
	} else {
		layerShow(layer, method);
	}
}

//------------------------------------------------------------------------------ function layerWrite
// écrit à l'intégrieur d'un layer. mode='replace', 'append' ou 'insert'
// seul le mode replace est implémenté à ce jour
function layerWrite(layer, content, mode, pos)
{
	if (!mode) mode = 'replace';
	if (mode == 'replace') {
		if (layer.innerHTML != undefined) {
			try {
				layer.innerHTML = content;
			} catch(e) {
				alert("ERROR - Use firefox www.mozilla.fr/firefox/ (" + layer.id + ")");
			}
		} else if (document.layers && window.Layer) {
			layer.document.open();
			layer.document.write(
				"<LAYER"
				+ " LEFT=" + x
				+ " NAME=" + name
				+ " TOP="  + y
				+ ">"
				+ content
				+ "</LAYER>"
			);
			layer.document.close();
		}
	}
}

//###########################################################################################################
//======================================================================================= généralités classes

//------------------------------------------------------------------------------ function Class.Inherit
// initialise les informations d'héritage d'une classe
// c'est la première méthode à appeler par un constructeur de classe
// quoi doit pouvoir appeler des méthodes parentes
function Inherit(class_name)
{
	if (!this.heritage) this.heritage = new Array();
	this.heritagePos = 0;
	this.inherit = InheritCall;
	this.heritage[this.heritage.length] = class_name;
	this.inheritConstructor = eval(class_name);
}

//------------------------------------------------------------------------------ function Class.InheritCall
// appelle la fonction de la classe héritée (jusqu'à 5 paramètres)
// exemple : this.inherit("OnMouseMove",e) pour appeler onMouseMove(e) du parent
function InheritCall(method, a, b, c, d, e)
{
	var result = null;
	if (this.heritagePos < this.heritage.length) {
		this.lastInheritedFunc = eval(this.heritage[this.heritagePos] + method);
		if (this.lastInheritedFunc) {
			this.heritagePos++;
			result = this.lastInheritedFunc(a, b, c, d, e);
			this.heritagePos--;
		}
	}
	return result;
}

//##############################################################################
//============================================================================== class Controls
// var controls
var controls = new Object();
controls.elements = new Object();
controls.count = 0;
controls.autoShow = true;
controls.getElementById = ControlsGetElementById;

//------------------------------------------------------------------------------ function ControlsGetElementById
// renvoie le contrôle d'identifiant id
function ControlsGetElementById(id)
{
	return eval("controls." + id);
}

//============================================================================== class Control
// class Control

//------------------------------------------------------------------------------ function __construct
// constructeur
function Control(name, content, x, y, w, h, underwhere, layer, hide)
{
	if (typeof(content) != "string") {
		layer = content;
		content = undefined;
	}
	// valeurs par défaut des arguments
	if (!x) x = 0;
	if (!y) y = 0;
	if (!w) w = 100;
	if (!h) h = 50;
	// initalisation méthodes et propiétés
	this.name           = name;
	this.layer          = layer ? layer : false;
	this.posX           = ControlPosX;
	this.posY           = ControlPosY;
	this.width          = ControlWidth;
	this.height         = ControlHeight;
	this.posX2          = ControlPosX2;
	this.posY2          = ControlPosY2;
	this.setPosXY       = ControlSetPosXY;
	this.setPosX        = ControlSetPosX;
	this.setPosY        = ControlSetPosY;
	this.setWidth       = ControlSetWidth;
	this.setHeight      = ControlSetHeight;
	this.show           = ControlShow;
	this.hide           = ControlHide;
	this.write          = ControlWrite;
	this.linkControl    = ControlLinkControl;
	this.linkedControls = new Array();
	this.onMouseMove    = ControlOnMouseMove;
	this.onMouseDown    = ControlOnMouseDown;
	this.onMouseUp      = ControlOnMouseUp;
	this.onMouseRight   = ControlOnMouseRight;
	this.free           = ControlFree;
	this.selectable     = true;
	this.visible        = true;
	// crée le contrôle (seulement si le contenu est défini)
	if (!this.layer) if (document.layers && window.Layer) {
		this.layer = new Layer(16);
		this.layer.document.open();
		this.layer.document.write(
			"<LAYER"
			+ " LEFT=" + x
			+ " NAME=" + name
			+ " TOP="  + y
			+ ">"
			+ content
			+ "</LAYER>"
		);
		this.layer.document.close();
		if (!controls.autoShow){
			layerHide(this.layer);
			this.visible = false;
		}
	}
	if (!this.layer) if(document.body) {
		if (document.body.insertAdjacentHTML) {
			document.body.insertAdjacentHTML(
				'beforeEnd',
				"<DIV"
				+ " ID=" + name
				+ " STYLE=position:absolute;"
				+ (controls.autoShow ? "" : "visibility:hidden;")
				+ "z-index:" + (layer_zindex++) + ";"
				+ ">"
				+ content
				+ "</DIV>"
			);
			this.layer = layerFind(name);
		}
	}
	if (!this.layer) if (document.appendChild && document.createElement && document.getElementsByTagName) {
		var div = document.createElement('div');
		div.setAttribute('ID', name);
		div.setAttribute(
			'STYLE',
			"position:absolute;"
			+ (controls.autoShow ? "" : "visibility:hidden;")
			+ "z-index:" + (layer_zindex++) + ";"
		);
		div.innerHTML = content;
		if (!underwhere) {
			var body = document.getElementsByTagName('BODY');
			body = body[0];
		} else {
			var body = document.getElementById(underwhere);
		}
		body.appendChild(div);
		this.layer = layerFind(name);
	}
	if (!this.layer) {
		alert("ERREUR ! Votre navigateur ne permet pas de créer le controle " + name + ".");
	} else {
		// retrouve les dimensions réelles du contrôle d'après le tableau contenu
		for (var cnn = 0; cnn < this.layer.childNodes.length; cnn++) {
			if (this.layer.childNodes[cnn].nodeName == "TABLE") {
				w = layerWidth(this.layer.childNodes[cnn]);
				h = layerHeight(this.layer.childNodes[cnn]);
				cnn = this.layer.childNodes.length;
			}
		}
		// repositionne le contrôle en tenant compte des limites de la fenêtre
		if (x + w > document.width) x = Math.max(0, document.width - w - 2);
		if (y + h > document.height) y = Math.max(0, document.height - h - 2);
		// défini la position et les dimensions
		this.setPosXY(x, y);
		this.setWidth(w);
		this.setHeight(h);
		// affichage du contrôle
		if (!hide) this.show();
		controls.elements[controls.count] = this;
		eval("controls." + name + " = this");
		controls.count = controls.count + 1;
	}
	// id classe, fin du contructeur
	this.class_name = 'Control';
	return this;
}

//------------------------------------------------------------------------------ function free
function ControlFree()
{
	// supprime les contrôles liés
	if (this.linkedControls) {
		for (var link in this.linkedControls) {
			this.linkedControls[link].free();
		}
	}
	// supprime le layer
	var child = this.layer;
	var parent = child.parentNode;
	if (parent) parent.removeChild(this.layer);
	delete(controls.elements[this.name]);
	eval("delete(controls." + this.name + ")");
	// seulement sous Firefox (hélas)
	if (!document.all) delete(this);
}

//------------------------------------------------------------------------------ function posX, posY, width, height, posX2, posY2
// lecture des coordonnées d'un contrôle
function ControlPosX()   { return layerPosX(this.layer); }

function ControlPosY()   { return layerPosY(this.layer); }

function ControlWidth()  { return layerWidth(this.layer); }

function ControlHeight() { return layerHeight(this.layer); }

function ControlPosX2()  { return layerPosX2(this.layer); }

function ControlPosY2()  { return layerPosY2(this.layer); }

//------------------------------------------------------------------------------ function set...
// modifie les coordonnées d'un contrôle
function ControlSetPosXY(x,y)     { layerSetPosXY(this.layer, x, y); }

function ControlSetPosX(x)        { layerSetPosX(this.layer, x); }

function ControlSetPosY(y)        { layerSetPosY(this.layer, y); }

function ControlSetWidth(width)   { layerSetWidth(this.layer, width); }

function ControlSetHeight(height) { layerSetWidth(this.layer, height); }

//------------------------------------------------------------------------------ function show, hide
function ControlShow() { layerShow(this.layer); this.visible = true; }

function ControlHide() { layerHide(this.layer); this.visible = false; }

//------------------------------------------------------------------------------ function write
// écriture dans le contenu d'un contrôle. mode='replace', 'append' ou 'insert'
function ControlWrite(content, mode, pos)
{
	layerWrite(this.layer, content, mode, pos);
}

//------------------------------------------------------------------------------ function linkControl
// relie un autre contrôle dont on appellera les événements en simultané
function ControlLinkControl(control)
{
	this.linkedControls[this.linkedControls.length] = control;
}

//------------------------------------------------------------------------------ function onMouseMove
// déplacement de la souris dans le contrôle sélectionné
function ControlOnMouseMove(e)
{
	// appelle le onMouseMove des contrôles reliées
	for (var i = 0 ; i < this.linkedControls.length ; i++) {
		this.linkedControls[i].onMouseMove(e);
	}
}

//------------------------------------------------------------------------------ function onMouseDown
// bouton pressé dans le contrôle sélectionné
function ControlOnMouseDown(e)
{
	// appelle le onMouseDown des contrôles reliées
	for (var i = 0 ; i < this.linkedControls.length ; i++) {
		this.linkedControls[i].onMouseDown(e);
	}
}

//------------------------------------------------------------------------------ function onMouseUp
// bouton relaché dans le contrôle sélectionné
function ControlOnMouseUp(e)
{
	// appelle le onMouseUp des contrôles reliées
	for (var i = 0 ; i < this.linkedControls.length ; i++) {
		this.linkedControls[i].onMouseUp(e);
	}
}

//-------------------------------------------------------------------- function ControlOnMouseRight
// clic droit dans le contrôle sélectionné
function ControlOnMouseRight(e)
{
	// appelle le onMouseUp des contrôles reliées
	for (var i = 0 ; i < this.linkedControls.length ; i++) {
		this.linkedControls[i].onMouseRight(e);
	}
}

//------------------------------------------------------------------------------ function controlAtXY (HORS CLASSE)
// indique quel contrôle se trouve sous le curseur de la souris
// renvoie le dernier créé seulement, parmis ceux qui sont "selectable"
function controlAtXY(x, y)
{
	var i, result = null;
	for (i = 0 ; i < controls.count ; i++) {
		e = controls.elements[i];
		if (e) {
			if (e.selectable) {
				try {
					if ((e.posX() <= x) && (e.posX2() >= x) && (e.posY() <= y) && (e.posY2() >= y)) {
						result = controls.elements[i];
					}
				} catch(e) {
					// ie : purge element
				}
			}
		}
	}
	return result;
}

//------------------------------------------------------------------------------ function controlsAtXY (HORS CLASSE)
// indique quels contrôles se trouvent sous le curseur de la souris
// parmi tous les contrôles (même ceux qui ne sont pas "selectable")
function controlsAtXY(x, y)
{
	var i, result = null, nresult = 0;
	for (i = 0 ; i < controls.count ; i++) {
		e = controls.elements[i];
		if (e && e != undefined) {
			try {
				if ((e.posX() <= x) && (e.posX2() >= x) && (e.posY() <= y) && (e.posY2() >= y)) {
					if (!result) result = new Array();
					result[nresult++] = controls.elements[i];
				}
			} catch(e) {
				// ie : purge element
			}
		}
	}
	return result;
}

//============================================================================== class HintControl
// class HintControl : FENETRE POPUP D'AIDE QUI SUIT LA SOURIS
// utiliser les fonctions de haut niveau hintOn et hintOff

//------------------------------------------------------------------------------ function __construct
// constructeur
function HintControl(name, content, followMouse, w)
{
	this.inherit = Inherit;
	this.inherit("Control");
	// valeurs par défaut
	if (!followMouse) followMouse = false;
	if (!w)           w = 100;
	// réécriture contenu
	if (content) {
		content = "<TABLE CELLSPACING=0 CELLPADDING=1 BORDER=0 WIDTH=100%><TR><TH BGCOLOR=black>"
		+ "<TABLE CELLSPACING=0 CELLPADDING=2 BORDER=0 BGCOLOR=#FFFFAA WIDTH=100%>"
		+ "<TR><TD>" + content + "</TD></TR>"
		+ "</TABLE>"
		+ "</TH></TR></TABLE>";
	}
	// appel constructeur hérité
	this.inheritConstructor(name, content, mouse_x + 10, mouse_y + 6, w);
	// initialisation propriétés
	this.followMouse = followMouse;
	// surcharge méthodes
	this.write = HintControlWrite;
	// captures d'événements
	if (this.followMouse) {
		this.onMouseMove = HintControlOnMouseMove;
		mouse_drag_control = this;
	}
	// id classe, fin du constructeur
	this.class_name = "HintControl";
	return this;
}

//------------------------------------------------------------------------------ function write
// écriture dans le contrôle, en conservant la présentation "hint"
function HintControlWrite(content, mode, pos)
{
	if ((mode == 'replace') && content) {
		content = "<TABLE CELLSPACING=0 CELLPADDING=1 BORDER=0 WIDTH=100%><TR><TH BGCOLOR=black>"
		+ "<TABLE CELLSPACING=0 CELLPADDING=2 BORDER=0 BGCOLOR=#FFFFAA WIDTH=100%>"
		+ "<TR><TD>" + content + "</TD></TR>"
		+ "</TABLE>"
		+ "</TH></TR></TABLE>";
	}
	this.inherit("Write", content, mode, pos);
}

//------------------------------------------------------------------------------ function onMouseMove
// déplacement de la souris dans la fenêtre simple sélectionné
// gestion du déplacement de fenêtres si la souris est cliquée
function HintControlOnMouseMove(e)
{
	this.inherit("OnMouseMove", e);
	if (mouse_drag_control == this) {
		this.setPosXY(mouse_x + 10, mouse_y + 6);
	}
	if (this.userOnMouseMove) {
		this.userOnMouseMove(e);
	}
}

// fenêtre "hint" : une seule à la fois
var hintControl;

//------------------------------------------------------------------------------ function hintOn (hors classe)
function hintOn(content, followMouse, w)
{
	name = 'hintControl';
	if (!hintControl) {
		hintControl = new HintControl(name, content, followMouse, w);
	} else {
		hintControl.write(content, 'replace');
		if (mouse_x < hintControl.width()) {
			hintControl.setPosXY(mouse_x + 10, mouse_y + 6);
		} else {
			hintControl.setPosXY(mouse_x - hintControl.width(), mouse_y + 6);
		}
		hintControl.show();
		if (hintControl.followMouse) {
			mouse_drag_control = hintControl;
		}
	}
}

//------------------------------------------------------------------------------ function hintOff
function hintOff()
{
	if(hintControl){
		hintControl.hide();
		mouse_drag_control = null;
	}
}

//============================================================================== class SimpleWindow
// class SimpleWindow : FENETRE SIMPLE

//------------------------------------------------------------------------------ function __construct
// contructeur
function SimpleWindow(name, title, content, x, y, w, h, title_style)
{
	// héritage constructeur
	this.inherit = Inherit;
	this.inherit("Control");
	// valeurs par défaut
	if (!title_style) title_style = "cursor:move;background-color:blue;color:white;text-align:left";
	// réécriture contenu
	if (title) {
		content = "<TABLE CELLSPACING=0 CELLPADDING=1 BORDER=0><TR><TH BGCOLOR=blue>"
		+ "<TABLE CELLSPACING=0 CELLPADDING=2 BORDER=0 BGCOLOR=white"
		+ (w ? (" WIDTH=" + w) : "")
		+ (h ? (" HEIGHT=" + h) : "")
		+ ">"
		+ "<TR><TH STYLE=" + title_style + " NOWRAP>" + title + "</TH></TR>"
		+ (content ? "<TR><TD NOWRAP>" + content + "</TD></TR>" : "")
		+ "</TABLE>"
		+ "</TH></TR></TABLE>";
	}
	// appel constructeur hérité
	this.inheritConstructor(name, content, x, y, w, h);
	// initialisation propriétés
	this.title = title;
	// capture d'événements
	this.onMouseMove = SimpleWindowOnMouseMove;
	this.onMouseDown = SimpleWindowOnMouseDown;
	this.onMouseUp   = SimpleWindowOnMouseUp;
	// id classe, fin du contructeur
	this.class_name = "SimpleWindow";
	return this;
}

//------------------------------------------------------------------------------ function onMouseMove
// déplacement de la souris dans la fenêtre simple sélectionné
// gestion du déplacement de fenêtres si la souris est cliquée
function SimpleWindowOnMouseMove(e)
{
	this.inherit("OnMouseMove", e);
	if( mouse_drag_control == this && mouse_status) {
		this.setPosXY(this.dragPosX + mouse_x - mouse_drag_x, this.dragPosY + mouse_y - mouse_drag_y);
		selectionEmpty();
	}
	if (this.userOnMouseMove) {
		this.userOnMouseMove(e);
	}
}

//------------------------------------------------------------------------------ function onMouseDown
// pression sur le bouton de la souris
function SimpleWindowOnMouseDown(e)
{
	this.inherit("OnMouseDown", e);
	if (mouse_drag_control == this) {
		this.dragPosX = this.posX();
		this.dragPosY = this.posY();
		if (this.userOnMouseDown) {
			this.userOnMouseDown(e);
		}
	}
}

//------------------------------------------------------------------------------ function onMouseUp
// relachement du bouton de la souris
function SimpleWindowOnMouseUp(e)
{
	this.inherit("OnMouseUp",e);
	if(this.userOnMouseUp) this.userOnMouseUp(e);
}

//============================================================================== class Arrow
// class Arrow : FLECHE QUI RELIE DEUX CONTROLES

//------------------------------------------------------------------------------ function __construct
// constructeur
function Arrow(name, control_source, control_destination, color, hv)
{
	if (!hv) hv = 'auto';
	// héritage constructeur
	this.inherit = Inherit;
	this.inherit("Control");
	// renseigne les propriétés essentielles au tracé
	this.redraw      = ArrowRedraw;
	this.name        = name;
	this.source      = control_source;
	this.destination = control_destination;
	this.color       = color;
	this.horizvert   = hv;
	// relacule la position et lance le constructeur hérité
	this.redraw(true);
	// initalisation propriétés
	this.selectable = false;
	// capture d'événements
	this.onMouseUp = ArrowOnMouseUp;
	// id classe, fin du contructeur
	this.class_name = "Arrow";
	return this;
}

//------------------------------------------------------------------------------ function redraw
// recalcule la position de la flêche (ne pas renseigner constructeur)
function ArrowRedraw(constructeur)
{
	// calcul des réglages flêche à partir des positions de ctrl1 et ctrl2
	var ctrl1 = this.source;
	var ctrl2 = this.destination;
	var gauche = ctrl1.posX() + ctrl1.width() / 2 < ctrl2.posX() + ctrl2.width() / 2 ? ctrl1 : ctrl2;
	var droite = gauche == ctrl2 ? ctrl1 : ctrl2;
	var haute = ctrl1.posY() < ctrl2.posY() ? ctrl1 : ctrl2;
	var basse = haute == ctrl2 ? ctrl1 : ctrl2;
	var x = gauche.posX() + Math.round(gauche.width() / 2);
	var y = haute.posY() + haute.height() - 1;
	var w = droite.posX() - gauche.posX() + Math.round(droite.width() / 2 - gauche.width() / 2); if (w < 8) w = 8;
	var h = basse.posY() - haute.posY() - haute.height() + 1; if (h < 8) h = 8;
	var r = gauche == ctrl1 ? 1 : 0;
	var d = haute == ctrl1 && gauche == ctrl1 || haute == ctrl2 && gauche == ctrl2 ? 1 : 0;
	// réécriture contenu
	content = "<IMG SRC=dynimg/img_fleche.php"
	+ "?w=" + w + "&h=" + h + "&d=" + d + "&r=" + r
	+ "&c=" + this.color + " WIDTH=" + w + " HEIGHT=" + h + ">";
	if (constructeur) {
		// appel constructeur hérité
		this.inheritConstructor(this.name, content, x, y, w, h);
		ctrl1.linkControl(this);
		ctrl2.linkControl(this);
	} else {
		// réécriture contenu
		this.setPosXY(x, y);
		this.setWidth(w);
		this.setHeight(h);
		this.write(content, 'replace');
	}
	// mise à jour dernières positions des contrôles
	this.lastSourceX = ctrl1.posX();
	this.lastSourceY = ctrl1.posY();
	this.lastDestinationX = ctrl2.posX();
	this.lastDestinationY = ctrl2.posY();
}

//------------------------------------------------------------------------------ function onMouseMove
// déplacement de la souris
function ArrowOnMouseUp(e)
{
	this.inherit("OnMouseMove", e);
	// si l'un des deux contrôles reliés a bougé, on recalcule l'affichage
	if (
		this.source.posX() != this.lastSourceX
		|| this.source.posY() != this.lastSourceY
		|| this.destination.posX() != this.lastDestinationX
		|| this.destination.posY() != this.lastDestinationY
	) {
		this.redraw();
	}
}

//============================================================================== class ArrowH
// class ArrowH : FLECHE QUI RELIE DEUX CONTROLES (en mode horizontal)

//------------------------------------------------------------------------------ function __construct
// constructeur
function ArrowH(name, control_source, control_destination, color, hv)
{
	if (!hv) hv = 'auto';
	// héritage constructeur
	this.inherit = Inherit;
	this.inherit("Control");
	// renseigne les propriétés essentielles au tracé
	this.redraw       = ArrowHRedraw;
	this.name         = name;
	this.source       = control_source;
	this.destination  = control_destination;
	this.color        = color;
	this.horizvert    = hv;
	// relacule la position et lance le constructeur hérité
	this.redraw(true);
	// initalisation propriétés
	this.selectable = false;
	// capture d'événements
	this.onMouseUp = ArrowOnMouseUp;
	// id classe, fin du contructeur
	this.class_name = "ArrowH";
	return this;
}

//------------------------------------------------------------------------------ function redraw
// recalcule la position de la flêche (ne pas renseigner constructeur)
function ArrowHRedraw(constructeur)
{
	// calcul des réglages flêche à partir des positions de ctrl1 et ctrl2
	var ctrl1 = this.source;
	var ctrl2 = this.destination;
	var gauche = ctrl1.posX() + ctrl1.width() / 2 < ctrl2.posX() + ctrl2.width() / 2 ? ctrl1 : ctrl2;
	var droite = gauche == ctrl2 ? ctrl1 : ctrl2;
	var haute = ctrl1.posY() < ctrl2.posY() ? ctrl1 : ctrl2;
	var basse = haute == ctrl2 ? ctrl1 : ctrl2;
	var x = gauche.posX() + gauche.width();
	var y = haute.posY() + Math.round(haute.height() / 2);
	var w = droite.posX() - gauche.posX() - gauche.width() + 0;
	var rw = w < 8 ? 8 : w;
	var h = basse.posY() - haute.posY() + Math.round(basse.height()) / 2 - Math.round(haute.height() / 2) + 0;
	var rh = h < 1 ? 1 : h;
	var r = gauche == ctrl1 ? 1 : 0; // 1: gauche vers droite, 0: droite vers gauche
	var d = haute == ctrl1 ? 1 : 0;  // 1: haut vers bat, 0: bas vers haut
	// réécriture contenu
	content = "<IMG SRC='dynimg/img_fleche.php?s=standard"
	+ "&w=" + w + "&h=" + h + "&d=" + d + "&r=" + r + "&c=" + this.color + "'>";
	if (constructeur) {
		// appel constructeur hérité
		this.inheritConstructor(this.name, content, x, y, rw, rh);
		ctrl1.linkControl(this);
		ctrl2.linkControl(this);
	} else {
		// réécriture contenu
		this.setPosXY(x, y);
		this.setWidth(rw);
		this.setHeight(rh);
		this.write(content, 'replace');
	}
	// mise à jour dernières positions des contrôles
	this.lastSourceX      = ctrl1.posX();
	this.lastSourceY      = ctrl1.posY();
	this.lastDestinationX = ctrl2.posX();
	this.lastDestinationY = ctrl2.posY();
}

//############################################################################## Menus classes

// var menus
var menus = new Object();
menus.elements = new Object();
menus.count = 0;
menus.getElementById = ControlsGetElementById;

//============================================================================== class SimpleMenu

//------------------------------------------------------------------------------ function __construct
// contructeur
function SimpleMenu(name, content, sansboutonfermer, th_class_menu, th_class_link, a_class, img_popup, img_close)
{
	// héritage constructeur
	this.inherit = Inherit;
	this.inherit("Control");
	// valeurs paramètres
	if (th_class_menu) {
		this.th_class_menu = " CLASS=" + th_class_menu;
	} else {
		this.th_class_menu = "";
	}
	if (th_class_link) {
		this.th_class_link = " CLASS=" + th_class_link;
	} else if (th_class_menu) {
		this.th_class_link = th_class_menu;
	} else {
		this.th_class_link = "";
	}
	if (a_class) {
		this.a_class = " CLASS=" + a_class;
	} else {
		this.a_class = "";
	}
	if (img_popup) {
		this.img_popup = img_popup;
	} else {
		this.img_popup = "img/tridroit.gif";
	}
	if (img_close) {
		this.img_close = img_close;
	} else {
		this.img_close = "img/btnFermer.gif";
	}
	// valeurs par défaut
	this.submenus = new Array();
	this.selected = null;
	// réécriture contenu
	var texte = "", i, j, txt, url, subname;
	// bouton fermer
	if (!sansboutonfermer) {
		texte = texte + "<TR><TH" + this.th_class_menu + ">"
		+ "<A HREF=javascript:controls." + name + ".hide()>"
		+ "<IMG SRC=" + this.img_close + " BORDER=0 HEIGHT=8>"
		+ "</A>"
		+ "</TH></TR>";
	}
	for (i = 0 ; i < content.length ; i++) {
		if (typeof(content[i]) == 'object') {
			// sous-menu
			txt = content[i][0].split('->');
			subname = name + "_" + i;
			url = txt[1];
			txt = txt[0];
			subcontent = new Array();
			for (j = 0 ; j < content[i].length - 1 ; j++) {
				subcontent[j] = content[i][j + 1];
			}
			this.submenus[i] = new Array(subname, subcontent);
			texte = texte + "<TR ONMOUSEOVER=\""
			+ "if(controls." + name + ".selected) controls." + name + ".selected.hide();"
			+ "controls." + name + ".selected=null;"
			+ "controls." + name + ".selected=controls." + subname + ";"
			+ "controls." + subname + ".show(controls." + name + ".posX()"
			+ "+document.getElementById('td_" + subname + "').offsetParent.offsetLeft+1,"
			+ "controls." + name + ".posY()"
			+ "+document.getElementById('td_" + subname + "').offsetParent.offsetTop+2);"
			+ "\"><TH NOWRAP" + this.th_class_menu + ">"
			+ (url ? "<A" + this.a_class + " HREF=\"javascript:location='" + url + "'\">" : "")
			+ "&nbsp;" + txt
			+ (url ? "</A>" : "")
			+ "</TH><TH WIDTH=1%" + this.th_class_menu + "><IMG SRC=" + this.img_popup
			+ " BORDER=0 ID=td_" + subname + ">" + "</TH></TR>";
		} else {
			// lien hypertexte
			txt = content[i].split('->');
			url = txt[1];
			txt = txt[0];
			texte = texte + "<TR><TH NOWRAP COLSPAN=2" + this.th_class_link + " ONMOUSEOVER=\""
			+ "if(controls." + name + ".selected) controls." + name + ".selected.hide();"
			+ "controls." + name + ".selected=null;"
			+ "\">"
			+ (url ? "<A" + this.a_class + " HREF=\"javascript:location='" + url + "'\">" : "")
			+ "&nbsp;" + txt
			+ (url ? "</A>" : "")
			+ "</TH></TR>";
		}
	}
	content = "<TABLE CELLSPACING=1 CELLPADDING=1 BORDER=0 WIDTH=100% BGCOLOR=white>"
	+ texte
	+ "</TABLE>";
	// appel constructeur hérité
	this.inheritConstructor(name, content, 0, 0, 50);
	// initialisation propriétés
	this.boutonFermer = !sansboutonfermer;
	// initialisation méthodes
	this.show = SimpleMenuShow;
	this.hide = SimpleMenuHide;
	// capture d'événements
	// id classe, fin du contructeur
	this.class_name = "SimpleMenu";
	this.hide();
	// crée les sous-menus
	for (i = 0 ; i < this.submenus.length ; i++) {
		if (typeof(this.submenus[i]) == 'object') {
			this.submenus[i] = new SimpleMenu(this.submenus[i][0], this.submenus[i][1], true);
		}
	}
	// rajout à la liste des menus (seulement si fermable)
	if (this.boutonFermer) {
		menus.elements[menus.count] = this;
		eval("menus." + name + "=this");
		menus.count++;
	}
	return this;
}

//------------------------------------------------------------------------------ function show
// affichage du menu
function SimpleMenuShow(x, y)
{
	// cache les autres menus affichés
	if (this.boutonFermer) {
		for (var i = 0 ; i < menus.count ; i++) {
			if (menus.elements[i] != this) {
				menus.elements[i].hide();
			}
		}
	}
	// montre ce menu ci
	if (x || y) {
		this.setPosXY(x, y);
	} else {
		this.setPosXY(mouse_x - 5, mouse_y - 5);
	}
	this.inherit("Show");
}

//------------------------------------------------------------------------------ function hide
// affichage du menu
function SimpleMenuHide()
{
	if (this.selected) {
		this.selected.hide();
		this.selected = null;
	}
	this.inherit("Hide");
}

//============================================================================== class MenuSel

//------------------------------------------------------------------------------ function __construct
function MenuSel(name, into)
{
	// héritage constructeur
	this.inherit = Inherit;
	this.inherit("Control");
	// appel constructeur hérité
	this.name = name;
	this.inheritConstructor(name, into);
	// initialisation propriétés
	this.into = into;
	this.menus = new Array();
	this.html = "";
	// initialisation méthodes
	this.build = MenuSelBuild;
	this.redraw = MenuSelRedraw;
	// id classe, fin du contructeur
	this.class_name = "MainMenu";
	return this;
}

//------------------------------------------------------------------------------ function build
function MenuSelBuild(sublevel)
{
	var thiscontrol = "controls." + this.name;
	if (sublevel == undefined) {
		this.html = "<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100% no_ONMOUSEOUT=" + thiscontrol + ".redraw(-1)>";
	}
	// pour chaque item...
	if (sublevel != undefined) var menus = this.menus[sublevel];
	else var menus = this.menus;
	for (var i = sublevel != undefined ? 1 : 0 ; i < menus.length ; i++) {
		if (typeof(menus[i]) == 'object') {
			this.html = this.html + "<TR><TD NOWRAP ONMOUSEOVER=" + thiscontrol + ".redraw(" + i + ")>" + menus[i][0] + "</TD></TR>";
			if (i == this.focused) {
				this.build(i);
			}
		} else {
			this.html = this.html + "<TR><TD NOWRAP>" + menus[i] + "</TD></TR>";
		}
	}
	if (sublevel == undefined) {
		this.html = this.html + " </TABLE>";
	}
}

//------------------------------------------------------------------------------ function redraw
function MenuSelRedraw(focus)
{
	this.build();
	if (focus) this.focused = focus;
	layerWrite(this.into, this.html);
}

//################################################################################## class MainMenu

//---------------------------------------------------------------------------- function __construct
/**
 * constructeur. id doit être unique
 */
function MainMenu(name)
{
	// héritage constructeur
	this.inherit = Inherit;
	this.inherit("Control");
	// valeurs par défaut
	this.submenus = new Array();
	// appel constructeur hérité
	this.inheritConstructor(name);
	// initialisation propriétés
	this.visibleMenu = null;
	// initialisation méthodes
	this.build       = MainMenuBuild;
	this.show        = MainMenuShow;
	this.showIn      = MainMenuShowIn;
	this.showSubMenu = MainMenuShowSubMenu;
	// capture d'événements
	// id classe, fin du contructeur
	this.class_name = "MainMenu";
	this.hide();
	return this;
}

//------------------------------------------------------------------------------------ function add
/**
 * construit le menu à partir d'une arborescence de tableaux
 */
function MainMenuBuild(content, sublevel)
{
	// début : initialise niveau, et chaine menu
	if (!sublevel) {
		sublevel = 0;
		this.html = "<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 ONMOUSEOUT=controls."
		+ this.name + ".showSubMenu(null)>\n";
	}
	// pour chaque item...
	for (var i = sublevel ? 1 : 0 ; i < content.length ; i++) {
		if (typeof(content[i]) == 'object') {
			// si tableau
			// identifiant du sous-menu à cacher/afficher
			var subid = "mainmenu_" + this.name + (sublevel ? sublevel + "_" : "") + i;
			// premier élément = élément du niveau
			this.html = this.html + "<TR ONMOUSEOVER=controls." + this.name + ".showSubMenu('" + subid + "')><TD>"
			+ content[i][0]
			+ "</TD></TR>\n";
			// éléments suivants = sous-éléments
			this.html = this.html + "<TR><TD><TABLE ID=" + subid + " CELLSPACING=0 CELLPADDING=0 BORDER=0>\n";
			this.build(content[i], sublevel + 1);
			this.html = this.html + "</TABLE></TD></TR>\n";
		} else {
			// si pas tableau
			// élément simplement
			this.html = this.html + "<TR><TD>" + content[i] + "</TD></TR>\n";
		}
	}
	// fin : remplace le contenu du menu
	if (!sublevel) {
		this.html = this.html + "</TABLE>\n";
		this.write(this.html);
		alert(this.html);
	}
}

//----------------------------------------------------------------------------------- function show
/**
 * affiche le menu aux coordonnées spécifiées
 */
function MainMenuShow(x, y)
{
	if (x || y) {
		this.setPosXY(x, y);
	} else {
		this.setPosXY(mouse_x - 5, mouse_y - 5);
	}
	this.inherit("Show");
}

//--------------------------------------------------------------------------------- function showIn
/**
 * affiche le menu à l'emplacement spécifié
 */
function MainMenuShowIn(where)
{
	document.getElementById(where).innerHTML = this.html;
}

//---------------------------------------------------------------------------- function showSubMenu
/**
 * affiche le sous-menu en question
 */
function MainMenuShowSubMenu(visibleMenu)
{
	if (this.visibleMenu != null) {
		layerFind(this.visibleMenu).hiddenText = layerFind(this.visibleMenu).innerHTML;
		layerFind(this.visibleMenu).innerHTML = "";
	}
	this.visibleMenu = visibleMenu;
	if (visibleMenu) {
		if (layerFind(this.visibleMenu).hiddenText) {
			layerFind(this.visibleMenu).innerHTML = layerFind(this.visibleMenu).hiddenText;
		}
	}
}

//####################################################################### class Assigned_Scroll_Bar
/**
 * Gestion de scollbar
 * Cette classe ne dessine pas de ScrollBar, elle permet la gestion d'une ScrollBar
 * déjà dessinée en HTML, il lui renseignant :
 * - l'élément html (généralement une cellule de tableau) à agrandir pour modifier la position
 * - l'élément html (généralement une cellule de tableau) représentant la taille
 * - la coordonnée haute précédent le début de la scrollbar
 * - la coordonnée basse suivant la fin de la scrollbar
 * - la taille totale en nombre d'éléments
 * - la position (numéro du premier élément sélectionné
 * - le nombre d'éléments visibles simultanément
 * - la hauteur de la marge autour de l'élément html représentant la taille (1 pour une ligne noire simple)
 * Elle prendra pour nom le nom de l'élément html sizeLayer
 */

//---------------------------------------------------------------------------- function __construct
function Assigned_Scroll_Bar(positionLayer, sizeLayer, begin, end, total, position, size, sizeMargin, horizontal, weight)
{
	// héritage constructeur
	this.inherit = Inherit;
	this.inherit("Control");
	// appel constructeur hérité
	this.inheritConstructor(
		sizeLayer.id,
		"",
		layerPosX(sizeLayer),
		layerPosY(sizeLayer),
		layerWidth(sizeLayer),
		layerHeight(sizeLayer),
		false,
		sizeLayer
	);
	// empêche la sélection sur les layers
	positionLayer.onselectstart = new Function("return false");
	sizeLayer.onselectstart     = new Function("return false");
	positionLayer.onmousedown   = new Function("return false");
	sizeLayer.onmousedown       = new Function("return false");
	// properties
	this.positionLayer = positionLayer;
	this.sizeLayer     = sizeLayer;
	this.begin         = begin;
	this.end           = end;
	this.total         = total;
	this.size          = size < total ? size : total;
	this.position      = position + this.size < total ? position : total - this.size;
	this.sizeMargin    = sizeMargin ? sizeMargin : 0;
	this.horizontal    = horizontal ? horizontal : 0;
	this.weight        = weight ? weight : 19;
	this.cbRefresh     = 5000;
	// methods
	this.calculatePos = Assigned_Scroll_Bar_calculatePos;
	this.redraw       = Assigned_Scroll_Bar_redraw;
	this.callBackCall = Assigned_Scroll_Bar_callBackCall;
	this.onMouseMove  = Assigned_Scroll_BarOnMouseMove;
	this.onMouseDown  = Assigned_Scroll_BarOnMouseDown;
	this.onMouseUp    = Assigned_Scroll_BarOnMouseUp;
	// rafraichissement initial
	this.redraw();
	//this.calculatePos();
	// id classe, fin du contructeur
	this.class_name = "Scroll_Bar";
	return this;
}

//--------------------------------------------------------------------------- function calculatePos
/**
 * Calculate real position from visual position
 */
function Assigned_Scroll_Bar_calculatePos()
{
	var size = this.size;
	var vTotal = this.end - this.begin;
	var vSize = Math.round(this.size * vTotal / this.total);
	if (vSize <= 8 + this.sizeMargin * 2) {
		size = Math.round(vSize * this.total / vTotal);
		vSize = 8 + this.sizeMargin * 2;
	}
	var vPos = this.horizontal ? layerWidth(this.positionLayer) : layerHeight(this.positionLayer);
	var total = this.total - this.size;
	this.position = Math.min(Math.max(0, Math.round(vPos * total / (vTotal - vSize))), total);
	return this.position;
}

//--------------------------------------------------------------------------------- function redraw
/**
 * Calculate and redraw visual position from real position
 */
function Assigned_Scroll_Bar_redraw()
{
	var size = this.size;
	var vTotal = this.end - this.begin;
	var vSize = Math.round(this.size * vTotal / this.total);
	if (vSize < 8 + this.sizeMargin * 2) {
		size = Math.round(vSize * this.total / vTotal);
		vSize = 8 + this.sizeMargin * 2;
	}
	var vPos = Math.min(Math.round(this.position * (vTotal - vSize) / Math.max(this.total - size, 1)), this.end - vSize);
	vSize -= this.sizeMargin * 2;
	if (this.horizontal) {
		layerSetHeight(this.sizeLayer, this.weight);
		layerSetWidth(this.sizeLayer, vSize);
		layerSetWidth(this.positionLayer, vPos);
	} else {

		layerSetWidth(this.sizeLayer, this.weight);
		layerSetHeight(this.sizeLayer, vSize);
		layerSetHeight(this.positionLayer, vPos);
	}
}

//--------------------------------------------------------------------------- function callBackCall
/**
 * Call callBack method if assigned by owner, every cbRefresh ms
 */
function Assigned_Scroll_Bar_callBackCall(step)
{
	if (step) this.step = step;
	if (this.callBack) {
		this.callBack();
		if (step != "end") {
			window.setTimeout(
				"controls." + this.name + ".callBackCall(controls." + this.name + ".step);",
				this.cbRefresh
			);
		}
	}
}

//---------------------------------------------------------------------------- function onMouseMove
function Assigned_Scroll_BarOnMouseMove(e)
{
	this.inherit("OnMouseMove", e);
	if (mouse_drag_control == this && mouse_status) {
		if (this.horizontal) {
			layerSetWidth(this.positionLayer, Math.max(0, Math.min(
				this.dragWidth + mouse_x - mouse_drag_x,
				this.end - this.begin - layerWidth(this.sizeLayer) - this.sizeMargin * 2
			)));
		} else {
			layerSetHeight(this.positionLayer, Math.max(0, Math.min(
				this.dragHeight + mouse_y - mouse_drag_y,
				this.end - this.begin - layerHeight(this.sizeLayer) - this.sizeMargin * 2
			)));
		}
		this.calculatePos();
		selectionEmpty();
	}
}

//---------------------------------------------------------------------------- function onMouseDown
function Assigned_Scroll_BarOnMouseDown(e)
{
	this.inherit("OnMouseDown", e);
	if (this.horizontal) {
		this.dragWidth = layerWidth(this.positionLayer);
	} else {
		this.dragHeight = layerHeight(this.positionLayer);
	}
	this.callBackCall("begin");
}

//------------------------------------------------------------------------------ function onMouseUp
function Assigned_Scroll_BarOnMouseUp(e)
{
	this.inherit("OnMouseUp", e);
	this.callBackCall("end");
}

//################################################################################ class Scroll_Bar
/**
 * Gestion de scollbar
 * Hérité directement de Assigned_Scroll_Bar, cette classe dessine la scrollbar
 * dans l'élément passé en paramètre (privilégier une cellule de tableau)
 */

//---------------------------------------------------------------------------- function __construct
function Scroll_Bar(name, into, width, height, total, position, size, horizontal, foreColor, backColor, border)
{
	// valeur par défaut des paramètres
	if (!into) alert("ERROR ! Scroll_Bar " + name + " : into control does not exist");
	if (!width) width = layerWidth(into);
	if (!height) height = layerHeight(into);
	if (!foreColor) foreColor ="#8080ff";
	if (!backColor) backColor = "white";
	if (border == undefined) border = true;
	// construction du code html
	var html;
	if (horizontal) {
		html = "<TABLE WIDTH=" + width + " BORDER=0 CELLSPACING=0 CELLPADDING=0 BGCOLOR=" + backColor + ">"
		+ (border ? "<TR><TH COLSPAN=2 BGCOLOR=black HEIGHT=1></TH></TR>" : "")
		+ "<TR>"
		+ "<TD WIDTH=100%>"
		+ "<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0><TR>"
		+ "<TD ID=" + name + "_position HEIGHT=" + height + "><IMG SRC=blk.gif WIDTH=1 HEIGHT=" + height + " ID=" + name + "_before></TD>"
		+ "<TH BGCOLOR=black WIDTH=1><IMG SRC=b.gif WIDTH=1 HEIGHT=1></TH>"
		+ "<TD BGCOLOR=" + foreColor + " ID=" + name + "_size STYLE=cursor:e-resize></TD>"
		+ "<TH BGCOLOR=black WIDTH=1><IMG SRC=b.gif WIDTH=1 HEIGHT=1></TH>"
		+ "</TR></TABLE>"
		+ "</TD>"
		+ "<TH BGCOLOR=black WIDTH=1 ID=" + name + "_after><IMG SRC=b.gif WIDTH=1 HEIGHT=1></TH>"
		+ "</TR>"
		+ (border ? "<TR><TH COLSPAN=2 BGCOLOR=black HEIGHT=1></TH></TR>" : "")
		+ "</TABLE>";
	} else {
		html = "<TABLE WIDTH=" + width + " BORDER=0 CELLSPACING=0 CELLPADDING=0 BGCOLOR=" + backColor + ">"
		+ "<TR>"
		+ (border ? "<TH ROWSPAN=2 WIDTH=1 BGCOLOR=black></TH>" : "")
		+ "<TD HEIGHT=" + height + " VALIGN=TOP>"
		+ "<TABLE WIDTH=100% BORDER=0 CELLSPACING=0 CELLPADDING=0>"
		+ "<TR><TD ID=" + name + "_position VALIGN=TOP>"
		+ "<TABLE WIDTH=100% CELLSPACING=0 CELLPADDING=0>"
		+ "<TR><TH HEIGHT=1 BGCOLOR=black ID=" + name + "_before></TH></TR>"
		+ "</TABLE>"
		+ "</TD></TR>"
		+ "<TR><TH BGCOLOR=black HEIGHT=1></TD></TR>"
		+ "<TR><TD ID=" + name + "_size BGCOLOR=" + foreColor + " STYLE=cursor:s-resize></TD></TR>"
		+ "<TR><TH BGCOLOR=black HEIGHT=1></TD></TR>"
		+ "</TABLE>"
		+ "</TD>"
		+ (border ? "<TH ROWSPAN=2 WIDTH=1 BGCOLOR=black></TH>" : "")
		+ "</TR>"
		+ "<TR><TH HEIGHT=1 BGCOLOR=black ID=" + name + "_after></TH></TR>"
		+ "</TABLE>";
	}
	// écriture du code html
	layerWrite(into, html);
	// héritage constructeur
	this.inherit = Inherit;
	this.inherit("Assigned_Scroll_Bar");
	// appel constructeur hérité
	this.inheritConstructor(
		layerFind(name + "_position"),
		layerFind(name + "_size"),
		horizontal ? layerPosX(layerFind(name + "_before")) : layerPosY(layerFind(name + "_before")),
		horizontal ? layerPosX(layerFind(name + "_after")) : layerPosY(layerFind(name + "_after")),
		total,
		position,
		size,
		1,
		horizontal,
		horizontal ? height : width
	);
	// id classe, fin du contructeur
	this.class_name = "Scroll_Bar";
	return this;
}

//############################################################################# class Dynamic_Lines
/**
 * Dynamic Table Lines with +/- control buttons management
 */

//---------------------------------------------------------------------------- function __construct
/**
 * Dynamic_Lines constructor
 */
function Dynamic_Lines(model_line, end_line, line_count)
{
	if (end_line == undefined) {
		end_line = model_line;
		model_line = end_line.previousSibling;
	}
	if (line_count == undefined) {
		line_count = 1;
	}
	this.model_lines = new Array();
	for (var i = 0; i < line_count; i++) {
		this.model_lines[i] = model_line.cloneNode(true);
		model_line = model_line.nextSibling;
	}
	this.end_line  = end_line;
	this.minus     = Dynamic_Lines_minus;
	this.move      = Dynamic_Lines_move;
	this.plus      = Dynamic_Lines_plus;
	this.plusAuto  = Dynamic_Lines_plusAuto;
	this.plusMulti = Dynamic_Lines_plusMulti;
	return this;
}

//---------------------------------------------------------------------------------- function minus
/**
 * Delete line
 */
function Dynamic_Lines_minus(line)
{
	for (var i = 1; i < this.model_lines.length; i ++) {
		line.parentNode.removeChild(line.nextSibling);
	}
	line.parentNode.removeChild(line);
}

//----------------------------------------------------------------------------------- function move
/**
 * Move line
 * @param line line node (type is TR)
 * @param down 0 to move line up, or 1 to move line down
 */
function Dynamic_Lines_move(line, down)
{
	// auto-calculate down parameter from mouse position
	if (down == undefined) {
		var middle_y = layerPosY(line) + layerHeight(line) / 2;
		down = mouse_y > middle_y;
	}
	// search line to insert moved line before of
	var line_insert_before = line;
	if (down) {
		// next ligne down
		for (var i = 0; (i < this.model_lines.length * 2) && line_insert_before; i++) {
			line_insert_before = line_insert_before.nextSibling;
		}
		if (!line_insert_before) {
			line_insert_before = this.end_line;
		}
	} else {
		// next ligne up
		for (var i =0; (i < this.model_lines.length) && line_insert_before; i++) {
			line_insert_before = line_insert_before.previousSibling;
		}
	}
	//  modif 2008-06-25 EC : ajout du test innerHTML pour ne pas intervertir 1ère ligne avec les titres
	// if (line_insert_before) {
	if (line_insert_before.innerHTML) {
		// move each line
		for (var i = 0; i < this.model_lines.length; i++) {
			line.parentNode.insertBefore(line.cloneNode(true), line_insert_before);
			line = line.nextSibling;
			line.parentNode.removeChild(line.previousSibling);
		}
	}
}

//----------------------------------------------------------------------------------- function plus
/**
 * Add a line, duplicating the model_line content
 *
 * @param before_node node to insert line before (default : before this.end_line)
 * @result inserted node, or first inserted node if multiple model lines
 */
function Dynamic_Lines_plus(before_node)
{
	var result;
	for (var i = 0 ; i < this.model_lines.length; i++) {
		var new_line = this.model_lines[i].cloneNode(true);
		this.end_line.parentNode.insertBefore(
			new_line, before_node == undefined ? this.end_line : before_node
		);
		if (!result) {
			result = new_line;
		}
	}
	return new_line;
}

//------------------------------------------------------------------------------- function plusAuto
function Dynamic_Lines_plusAuto(node, parent_count)
{
	if (parent_count == undefined) {
		parent_count = 2;
	}
	while (parent_count) {
		node = node.parentNode;
		parent_count --;
	}
	if (node.nextSibling.id == this.end_line.id) {
		this.plus();
	}
}

//------------------------------------------------------------------------------ function plusMulti
/**
 * Add multiple lines, duplicating the model_line content
 * Uses txt_how_many and txt_add text  on display of "how many lines" form
 */
function Dynamic_Lines_plusMulti(txt_how_many, txt_add)
{
	if (!txt_how_many) {
		txt_how_manu = "How many lines do you want to add";
	}
	if (!txt_add) {
		txt_add = "Add lines";
	}
	var nb_new = window.prompt(txt_how_many + " ?", "10", txt_add);
	while (nb_new > 0) {
		this.plus();
		nb_new--;
	}
}

//############################################################################### class Switch_Tabs
/**
 * Transform divs into very simple switchable tabs
 * This class does not deal with presentation :
 * see Tabs for a complete tabs management control
 */

//---------------------------------------------------------------------------- function __construct
/**
 * Switch_Tabs constructor
 *
 * html divs balist must exist before creating Switch_Tabs !
 * zero or one visible tab <DIV ID=prefixvisiblesuffix>
 * one or more invisible tabs <DIV ID=prefixnamesuffix STYLE=position:absolute;left:0;top:0;visibility:hidden>
 *
 * @param string prefix for div identifiers <DIV ID=prefixnamesuffix>
 * @param string visible name of initialy visible div <DIV ID=prefixvisiblesuffix>
 * @param string suffix for div identifiers <DIV ID=prefixnamesuffix>
 */
function Switch_Tabs(prefix, visible, suffix)
{
	this.prefix  = prefix ? prefix : "";
	this.visible = prefix + visible + suffix;
	this.suffix  = suffix ? suffix : "";
	this.switchTab = Switch_Tabs_switchTab;
	return this;
}

//------------------------------------------------------------------------------ function switchTab
/**
 * Switch betwen tabs, calling its name
 *
 * @param string name part of the div id to be shown, between Switch_Tabs prefix and suffix
 */
function Switch_Tabs_switchTab(name)
{
	// search visible and hidden tabs
	var hidden_tab = layerFind(this.prefix + name + this.suffix);
	if (this.visible) {
		var visible_tab = layerFind(this.visible);
		// hide currently visible tab
		layerHide(visible_tab);
		visible_tab.style.position = "absolute";
		layerSetPosXY(visible_tab, -10000, -10000);
	}
	// show currently hidden tab
	layerSetPosXY(hidden_tab, 0, 0);
	hidden_tab.style.position = "relative";
	layerShow(hidden_tab);
	// memorize visible tab id
	this.visible = hidden_tab.id;
	// return pointer on new visible layer
	return hidden_tab;
}

//###################################################################################### class Tabs

//---------------------------------------------------------------------------- function __construct
/**
 * Tabs constructor
 *
 * Will create object from a simple table containing :
 * - tabs row
 * - content divs row
 * Tabbing presentation is not needed ! This will do it automatically
 * Example :
 * <TABLE ID=tabid>
 * <TR><TD>
 * <TABLE><TR><TD ID=tabid1>Tab 1</TD><TD ID=tabid2>Tab 2</TD></TR></TABLE>
 * </TD></TR>
 * <TR><TD>
 * <DIV ID=tabidtab1>Content of layer one</DIV>
 * <DIV ID=tabidtab2 STYLE=position:absolute;left:0;top:0;visibility:hidden>Content of layer two</DIV>
 * </TD></TR>
 * </TABLE>
 * mouse_mode can be "onmouseover" or "onmouseclick" (default)
 */
var tabs = new Object();

function Tabs(tabid, mouse_mode, img_template)
{
	// global vas, to take it back from events
	eval("tabs." + tabid + " = this;");
	// methods
	this.draw = Tabs_draw;
	this.select = Tabs_select;
	this.unselect = Tabs_unselect;
	// properties
	this.tabid = tabid;
	this.nb_selected = 1;
	this.tabs_table = layerFind(tabid);
	this.mouse_mode = mouse_mode;
	if (img_template) {
		this.img_template = img_template + "/";
	} else {
		this.img_template = "";
	}
	// sels property
	this.sels = new Array();
	var count = 1;
	var sel;
	while (sel = layerFind(tabid + count)) {
		this.sels[count] = sel;
		this.draw(count, count == 1);
		count++;
	}
	if (count == 1) {
		alert("Tabs error : missing a " + tabid + count + " identified selector TD");
	}
	// tabs property
	this.tabs = new Array();
	count = 1;
	var tab;
	while (tab = layerFind(tabid + "tab_" + count)) {
		this.tabs[count] = tab;
		count++;
	}
	if (count == 1) {
		alert("Tabs error : missing a " + tabid + "tab_" + count + " identified tab DIV");
	}
	// add top left corner left of tabs selectors
	var td = document.createElement("td");
	td.setAttribute("VALIGN", "BOTTOM");
	td.innerHTML = "<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0><TR>"
	+ "<TD><IMG SRC=img/tabs/" + this.img_template + "tlf.gif></TD>"
	+ "</TR></TABLE>";
	this.sels[1].parentNode.insertBefore(td, this.sels[1]);
	// add trailing line and right corner right of tabs selectors
	var td = document.createElement("td");
	td.setAttribute("VALIGN", "BOTTOM");
	td.setAttribute("WIDTH", "100%");
	td.innerHTML = "<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR>"
	+ "<TD STYLE=background:url('img/tabs/" + this.img_template + "b.gif') WIDTH=100%></TD>"
	+ "<TD><IMG SRC=img/tabs/" + this.img_template + "trf.gif></TD>"
	+ "</TR></TABLE>";
	this.sels[1].parentNode.appendChild(td);
	// check that tabiddivs layer exists
	var divs = layerFind(tabid + "divs");
	if (!divs) {
		alert("Tabs error : missing a " + tabid + "divs identified TD");
	} else {
		// add left bar left of tabs
		var td = document.createElement("td");
		td.style.background = "url('img/tabs/" + this.img_template + "lf.gif')";
		divs.parentNode.insertBefore(td, divs);
		// add right bar right of tabs
		var td = document.createElement("td");
		td.style.background = "url('img/tabs/" + this.img_template + "rf.gif')";
		divs.parentNode.appendChild(td);
		// add bottom bar lower of tabs
		var tr = document.createElement("tr");
		var td = document.createElement("td");
		td.innerHTML = "<IMG SRC=img/tabs/" + this.img_template + "blf.gif>";
		tr.appendChild(td);
		var td = document.createElement("td");
		td.style.background = "url('img/tabs/" + this.img_template + "bf.gif')";
		tr.appendChild(td);
		var td = document.createElement("td");
		td.innerHTML = "<IMG SRC=img/tabs/" + this.img_template + "brf.gif>";
		tr.appendChild(td);
		divs.parentNode.parentNode.appendChild(tr);
		// change divs background image
		divs.style.background = "url('img/tabs/" + this.img_template + "sc.gif')";
	}
	// switch_tabs property
	this.switch_tabs = new Switch_Tabs(tabid + "tab_", "1", "");
	// fend
	return this;
}

//----------------------------------------------------------------------------------- function draw
function Tabs_draw(nb_tab, selected)
{
	var sel = this.sels[nb_tab];
	// force sel style
	sel.style.cursor = "pointer";
	if (!sel.onclick) {
		sel.onclick = new Function("tabs." + this.tabid + ".select(" + nb_tab + ");");
		if (this.mouse_mode == "onmouseover") {
			sel.onmouseover = sel.onclick;
		}
	}
	// save tab content into "content" property of the table cell element
	if (!sel.content) {
		sel.content = sel.innerHTML;
	}
	// replace content by full-formed content (selected or not)
	if (!selected) {
		layerWrite(
			sel, "<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0>"
			+ "<TR><TD><IMG SRC=img/tabs/" + this.img_template + "tl.gif></TD><TD STYLE=background:url('img/tabs/" + this.img_template + "t.gif')></TD><TD><IMG SRC=img/tabs/" + this.img_template + "tr.gif></TD></TR>"
			+ "<TR><TD STYLE=background:url('img/tabs/" + this.img_template + "l.gif')></TD><TD STYLE=background:url('img/tabs/" + this.img_template + "c.gif') NOWRAP>"
			+ sel.content
			+ "</TD><TD STYLE=background:url('img/tabs/" + this.img_template + "r.gif')></TD></TR>"
			+ "<TR><TD><IMG SRC=img/tabs/" + this.img_template + "bl.gif></TD><TD STYLE=background:url('img/tabs/" + this.img_template + "b.gif')></TD><TD><IMG SRC=img/tabs/" + this.img_template + "br.gif></TD></TR>"
			+ "</TABLE>"
		);
	} else {
		layerWrite(
			sel, "<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0>"
			+ "<TR><TD><IMG SRC=img/tabs/" + this.img_template + "stl.gif></TD><TD STYLE=background:url('img/tabs/" + this.img_template + "st.gif')></TD><TD><IMG SRC=img/tabs/" + this.img_template + "str.gif></TD></TR>"
			+ "<TR><TD STYLE=background:url('img/tabs/" + this.img_template + "sl.gif')></TD><TD STYLE=background:url('img/tabs/" + this.img_template + "sc.gif') NOWRAP>"
			+ sel.content
			+ "</TD><TD STYLE=background:url('img/tabs/" + this.img_template + "sr.gif')></TD></TR>"
			+ "<TR><TD><IMG SRC=img/tabs/" + this.img_template + "sbl.gif></TD><TD STYLE=background:url('img/tabs/" + this.img_template + "sb.gif')></TD><TD><IMG SRC=img/tabs/" + this.img_template + "sbr.gif></TD></TR>"
			+ "</TABLE>"
		);
	}
}

//--------------------------------------------------------------------------------- function select
function Tabs_select(nb_tab)
{
	if (this.nb_selected != nb_tab) {
		if (this.nb_selected) {
			this.unselect(this.nb_selected);
		}
		this.draw(nb_tab, true);
		this.switch_tabs.switchTab(nb_tab);
		this.nb_selected = nb_tab;
	}
}

//------------------------------------------------------------------------------- function unselect
function Tabs_unselect(nb_tab)
{
	this.draw(nb_tab, false);
	this.nb_selected = false;
}

//##################################################################### N° DE VERSION DU MODULE IHM
var ihm_version = '2.5.0000';

