function Global ()
{
}

Global.DEBUG = true;
Global._contexte = this;

Global.assert = function (test)
{
	if (Global.DEBUG && !test)
		alert ('assertion failed in ' + Global.assert.caller);
}

Global.publier = function (nom, valeur)
{
	Global.assert (nom);
	Global.assert (valeur);
//	Global.assert (!Global._contexte[nom]);

	Global._contexte[nom] = valeur;
}

Global.publierContexte = function (contexte)
{
	Global.Global.assert (contexte);
	
	for (var nom in contexte) {
		/* correctif surcharge prototype Object de vcXMLRPC
		 * importe par Epoz */
		if (nom == 'toXMLRPC')
			continue;

		if (nom.indexOf ('_') != 0)
			Global._contexte[nom] = contexte[nom];
	}
}

/**
 * Enrobe un appel de methode pour contourner l'acces impossible a this lors
 * d'un rappel d'evenement
 * @param objet   l'objet sur lequel appliquer la methode
 * @param methode la methode a appeler
 */
Global.associer = function (objet, methode) 
{
	Global.assert (objet);
	Global.assert (methode);

	return function () {
		return methode.apply (objet, arguments);
	};
}

/**
 * Affiche un message de deboggage horodate dans une fenetre de deboggage.
 * @param message le message a afficher
 */
Global.journal = function (message)
{
	var fenetre = window.open ('', 'journal');
	if (!fenetre)
		alert ('Echec d\'ouverture de la fenetre '
		       + 'du journal de deboggage');

	var date = new Date().toLocaleTimeString ();
	fenetre.document.write (date + ' ' + message + '<br />');
}

Global._est_definition = false;
Global.estDefinition = function () 
{
	return Global._est_definition;
}

Global.heriter = function (classe_fille, classe_mere)
{
	Global.assert (!Global.estDefinition ());
	Global.assert (classe_fille);
	Global.assert (classe_mere);

	Global._est_definition = true;
	classe_fille.prototype = new classe_mere;
	Global._est_definition = false;
}

function Module (nom, dependances, styles, definition)
{
	/* passer l'initialisation pour les prototypes des sous classes
	 */
	if (Global.estDefinition ()) return;

	Global.assert (nom);
	Global.assert (dependances);
	Global.assert (styles);
	Global.assert (definition);

	this._nom = nom;
	this._dependances = dependances;
	this._definition = definition;

	Module._ajouter (this);

	Module._prechargerDependancesModules (nom);

	for (var i = 0; i < dependances.length; i++)
		Module.charger (Module._url (dependances[i]));

	for (var i = 0; i < styles.length; i++)
		Module.chargerStyle (styles[i]);

	if (this._estPret ())
		this._interpreter ();
}

/* FIXME : optimisation */
Module._prechargerDependancesModules = function (nom_module)
{
	Global.assert (nom_module);

	for (var i = 0; i < liste_dependances_modules[nom_module].length;i++) {
		var nom_sous_module = liste_dependances_modules[nom_module][i];
		
/* 		Module._prechargerDependancesModules (nom_sous_module); */
		Module.charger (Module._url(nom_sous_module));
	}
}

Module.prototype._valNom = function () 
{
	Global.assert (this._nom);
	
	return this._nom;
}

Module.prototype._valDependances = function ()
{
	Global.assert (this._dependances);
	
	return this._dependances;
}

Module.prototype._valDefinition = function () 
{
	Global.assert (this._definition);
	
	return this._definition;
}

Module.prototype._dependDe = function (nom)
{
	Global.assert (nom);
	
	return this._valDependances ().find (nom) != -1;
}

Module.prototype._estInterprete = function () 
{
	return !this._definition;
}

Module.prototype._estPret = function ()
{
	var dependances = this._valDependances ();
	for (var i = 0; i < dependances.length; i++) {
		var nom = dependances[i];

		if (!Module._estCharge (nom))
			return false;

		var module = Module._valModule (nom);
		if (!module._estInterprete ())
			return false;
	}

	return true;
}

Module.prototype._interpreter = function ()
{
	if (this._definition == null)
		return;

	var definition = this._valDefinition ();
	definition ();
	this._definition = null;

	this._interpreterDependants ();

	var nom = this._valNom ();
	Module._notifierFinChargement (Module._url (nom));	
}

Module.prototype._interpreterDependants = function ()
{
	for (var nom in Module._modules) {
		/* correctif surcharge prototype Object de vcXMLRPC
		 * importe par Epoz */
		if (nom == 'toXMLRPC')
			continue;

		var module = Module._valModule (nom);

		if (module._dependDe (this._valNom ()) && module._estPret ())
			module._interpreter ()
	}
}

Module._en_attente = new Array ();
Module._modules = new Object ();

Module._ajouter = function (module)
{
	Global.assert (module);
	Global.assert (Module._modules);

	var nom = module._valNom ();

	Global.assert (!Module._estCharge (nom));

	Module._modules[nom] = module;
}

Module._estCharge = function (nom) 
{
	Global.assert (nom);
	Global.assert (Module._modules);
	
	return Boolean (Module._modules[nom]);
}

Module._valModule = function (nom)
{
	Global.assert (nom);
	Global.assert (Module._modules);
	Global.assert (Module._estCharge (nom));
	
	return Module._modules[nom];
}

Module.chargementsSontTermines = function ()
{
	Global.assert (Module._en_attente);

	return Module._en_attente.length == 0;
}

Module._notifierAttente = function (adresse)
{
	Global.assert (Module._en_attente);
	
	Module._en_attente.push (adresse);
}

Module._estEnAttente = function (adresse) 
{
	Global.assert (adresse);
	Global.assert (Module._en_attente);

	return Module._en_attente.find (adresse) != -1;
}

Module._notifierFinChargement = function (adresse)
{
	Global.assert (adresse);
	Global.assert (Module._en_attente);
//	Global.assert (!Module.chargementsSontTermines ());

	if (!Module._estEnAttente (adresse))
		return;

	Module._en_attente.remove (adresse);
	if (Module.chargementsSontTermines ())
		Init.lancerTemporisation ();
}

Module._estEnChargement = function (adresse)
{
	Global.assert (adresse);

	var scripts = document.getElementsByTagName ('script');
	var regexp = new RegExp (adresse + '$');
	for (var i = 0; i < scripts.length; i++) {
		if (regexp.test (scripts[i].src))
			return true;
	}

	return false;
}

function serialiser (elt)
{
	var serialisation_fils = '';
	for (var i=0; i < elt.childNodes.length; i++)
		serialisation_fils += serialiser (elt.childNodes[i]);

	var serialisation_attributs = '';
	for (var i=0; elt.attributes && i < elt.attributes.length; i++) {
		if (!/^on/.test (elt.attributes[i].name)
		    && elt.attributes[i].value)
			serialisation_attributs += ' ' + elt.attributes[i].name
				+ '=' + elt.attributes[i].value;
	}

	return '<' + elt.tagName + ' (' + elt.nodeName  + ')'
		+ serialisation_attributs + '>\n'
		+ (elt.data ? elt.data : '')
		+ serialisation_fils
		+ '</' + elt.tagName + '>\n';
}

Module.charger = function (adresse)
{
	Global.assert (adresse);

	if (Module._estEnChargement (adresse))
		return;

	Init.arreterTemporisation ();
	Module._notifierAttente (adresse);

	if (adresse.indexOf ('jeu') == -1
	    && adresse.indexOf ('base') == -1)
		adresse = ('http://ressources' + (adresse.length % 4)
			   + '.nutsy.net'
			   + adresse);

	if (/MSIE/.test (navigator.userAgent)
	    && document.getElementById ('correctif_ie_ajout_entete')) { /* correctif ie */
		var head = document.getElementsByTagName ('head')[0];
		document.write ('<script src="' + adresse + '" language="javascript" type="text/javascript"></script>');
	} else {
		var elt = document.createElement ('script');
		elt.src = adresse;
		elt.language = 'javascript';
		elt.type = 'text/javascript';
		var head = document.getElementsByTagName ('head')[0];
		head.appendChild (elt);
	}
}

Module.chargerStyle = function (adresse)
{
	Global.assert (adresse);

	if (/MSIE/.test (navigator.userAgent)
	    && document.getElementById ('correctif_ie_ajout_entete')) { /* correctif ie */
		var head = document.getElementsByTagName ('head')[0];
		document.write ('<link href="' + adresse + '" rel="stylesheet" type="text/css" />');
	} else {
		var elt = document.createElement ('link');
		elt.href = adresse;
		elt.rel = 'stylesheet';
		elt.type = 'text/css';
		var entete = document.getElementsByTagName ('head')[0];
		entete.appendChild (elt);
	}
}

Module._url = function (nom)
{
	Global.assert (nom);
	
	return '/scripts/' + nom.replace ('.', '/') + '.js';
}

/*
 * Initialisation
 */

function Init () 
{
}

Init._rappels = new Array ();
Init._rappels_fixes = new Array ();
Init._temporisation = null;
Init._page_est_chargee = false;

Init._pageEstChargee = function ()
{
	return Init._page_est_chargee;
}

Init.ajouterRappel = function (rappel, fixe)
{
	Global.assert (Init._rappels);
	Global.assert (Init._rappels_fixes);

	if (fixe)
		Init._rappels_fixes.push (rappel);
	else
		Init._rappels.push (rappel);
}

Init._init = function ()
{
	Global.assert (Init._rappels);
	Global.assert (Init._rappels_fixes);
	Global.assert (Init._pageEstChargee ());
	Global.assert (Module.chargementsSontTermines ());
	
	for (var i = 0; i < Init._rappels.length; i++) {
//		Global.journal ('Debut : ' + Init._rappels[i]);
		Init._rappels[i]();
//		Global.journal ('--> Fin');
	}
	Init._rappels = new Array ();

	for (var i = 0; i < Init._rappels_fixes.length; i++) {
//		Global.journal ('Debut Fixe : ' + Init._rappels_fixes[i]);
		Init._rappels_fixes[i]();
//		Global.journal ('--> Fin');
	}

	Init._page_est_chargee = false;
}


Init.lancerTemporisation = function () 
{
	if (!Init._pageEstChargee ()
	    || !Module.chargementsSontTermines ())
		return;

	if (Init._temporisation)
		Init.arreterTemporisation ();
	
	Init._temporisation = setTimeout (Init._init, 0);
}

Init.arreterTemporisation = function ()
{
	if (Init._temporisation)
		clearTimeout (Init._temporisation);
	
	Init._temporisation = null;
}

Init.finChargementPage = function ()
{
	/* FIXME - balise script interpretee 2 fois en xml */
//	Global.assert (!Init._pageEstChargee ());
	
	Init._page_est_chargee = true;
	Init.lancerTemporisation ();
}


/*
 * Ajout de fonctionalites aux objets de base
 */

Array.prototype.find_cmp = function (val, cmp)
{
	Global.assert (val);
	Global.assert (cmp);

	for (var i = 0; i < this.length; i++) {
		if (cmp (val, this[i]))
			return i;
	}
	
	return -1
}

Array.prototype.find = function (val) 
{
	Global.assert (val);

	return this.find_cmp (val,
			      function (val, elt) { return val == elt });
}

Array.prototype.remove = function (val) 
{
	Global.assert (val);

	this.splice (this.find (val), 1);
}

String.prototype.capitalize = function ()
{
	if (this == '')
		return '';
	else
		return this.substring (0, 1).toUpperCase () + this.slice (1);
}

function search_cmp (obj, val, cmp)
{
	Global.assert (obj);
	Global.assert (val);
	Global.assert (cmp);

	for (var clef in obj) {
		/* correctif surcharge prototype Object de vcXMLRPC
		 * importe par Epoz */
		if (clef == 'toXMLRPC')
			continue;

		if (cmp (val, obj[clef]))
			return clef;
	}

	return null;
}

function clamp (val, min, max) 
{
	return Math.max (Math.min (val, max), min);
}

var _topDocument = null;
function topDocument ()
{
	if (!_topDocument)
		_topDocument = window.top.document || document;

	return _topDocument;
}

/*
 * Manipulation calque
 */

/**
 * Retourn la valeur associee au style donne.
 * cf http://www.faqts.com/knowledge_base/view.phtml/aid/1780
 * @param elt l'element sur lequel recuperer le style
 * @param nom le nom du style, attention celui-ci ne doit pas etre compose
 * @return la valeur
 */
function style (elt, nom) 
{
	Global.assert (elt);
	Global.assert (nom);
	Global.assert (nom.indexOf ('-') == -1);

	if (elt.style[nom]) {
		return elt.style[nom];
	} else if (document.defaultView) {
		var style = document.defaultView.getComputedStyle (elt, '');
		return style.getPropertyValue (nom);
	} else if (elt.currentStyle) {
		return elt.currentStyle[nom];
	}
}

function scroll_x ()
{
	return window.pageXOffset
		|| document.documentElement.scrollLeft
		|| document.body.scrollLeft;
}

function scroll_y ()
{
	return window.pageYOffset
		|| document.documentElement.scrollTop
		|| document.body.scrollTop;
}

/* cf http://www.faqts.com/knowledge_base/view.phtml/aid/1001/fid/128
 * FIXME : bogue ie7 position fixed
 */
function min_x (elt)
{
	Global.assert (elt);
	Global.assert (elt.parentNode);

	var debut = elt;
	var left = 0;

	while (elt.offsetParent) {
		left += elt.offsetLeft - elt.scrollLeft;

		if (style (elt, 'position') == 'fixed')
			left += scroll_x ();

		elt = elt.offsetParent;
	}

	if (!document.all) {
		elt = debut;
		while (elt.parentNode
		       && elt.parentNode.tagName != 'BODY') {
			left -= elt.parentNode.scrollLeft;
			elt = elt.parentNode;
		}
	}

	return left;
}

function max_x (elt)
{
	Global.assert (elt);
	Global.assert (elt.parentNode);

	return min_x (elt) + elt.offsetWidth;
}

function min_y (elt)
{
	Global.assert (elt);
	Global.assert (elt.parentNode);

	var debut = elt;
	var top = 0;

	while (elt.offsetParent) {
		top += elt.offsetTop - elt.scrollTop;

		if (style (elt, 'position') == 'fixed')
			top += scroll_y ();

		elt = elt.offsetParent;
	}

	if (!document.all) {
		elt = debut;
		while (elt.parentNode
		       && elt.parentNode.tagName != "BODY") {
			top -= elt.parentNode.scrollTop;
			elt = elt.parentNode;
		}
	}

	return top;
}

function max_y (elt)
{
	Global.assert (elt);
	Global.assert (elt.parentNode);

	return min_y (elt) + elt.offsetHeight;
}

function survole (evt, elt)
{
	return event_x (evt) >= min_x (elt)
		&& event_y (evt) >= min_y (elt)
		&& event_x (evt) <= max_x (elt)
		&& event_y (evt) <= max_y (elt);
}

function contient (elt1, elt2)
{
	return min_x (elt1) <= min_x (elt2) && max_x (elt1) >= max_x (elt2)
	       && min_y (elt1) <= min_y (elt2) && max_y (elt1) >= max_y (elt2);
}

function chevauche (elt1, elt2)
{
	return !(max_x (elt1) <= min_x (elt2) || max_x (elt2) <= min_x (elt1)
	      || max_y (elt1) <= min_y (elt2) || max_y (elt2) <= min_y (elt1));
}

function changer_opacite (elt, opacite)
{
	elt.style.opacity = opacite;
	elt.style.MozOpacity = opacite;
	if (elt.filters)
		elt.style.filter = 'alpha(opacity=' + opacite * 100 + ')';
}

function frame_x (window)
{
	var left = 0;
	while (window.frameElement) {
		left += min_x (window.frameElement);
		window = window.parent;
	}
	return left;
}

function frame_y (window)
{
	var top = 0;
	while (window.frameElement) {
		top += min_y (window.frameElement);
		window = window.parent;
	}
	return top;
}

function zone_temporaire_ajouter (elt, doc)
{
	Global.assert (elt);

	if (!doc)
		doc = document;

	var zone_temporaire = doc.getElementById ('zone_temporaire');
	if (!zone_temporaire) {
		zone_temporaire = doc.createElement ('div');
		zone_temporaire.id = 'zone_temporaire';
		doc.body.appendChild (zone_temporaire);
	}
	
	zone_temporaire.appendChild (elt);
}

function zone_temporaire_vider ()
{
	var zone_temporaire = document.getElementById ('zone_temporaire');

	if (zone_temporaire)
		zone_temporaire.parentNode.removeChild (zone_temporaire);
}

/*
 * Gestion evenements
 */

function evenement_attacher (elt, type, rappel)
{
	Global.assert (elt);
	Global.assert (type);
	Global.assert (rappel);

	if (elt.addEventListener) {
		elt.addEventListener (type, rappel, false);
	} else if (elt.attachEvent) {
		elt.attachEvent ('on' + type,
				 Global.associer (elt, rappel));
	} else {
		Global.assert (!elt['on' + type]);
		elt['on' + type] = rappel;
	}
}

function evenement_supprimer (elt, type, rappel) 
{
	Global.assert (elt);
	Global.assert (type);
	Global.assert (rappel);

	if (elt.removeEventListener) {
		elt.removeEventListener (type, rappel, false);
	} else if (elt.attachEvent) {
		elt.removeEvent ('on' + type, rappel);
	} else {
		Global.assert (elt['on' + type] == rappel);
		elt['on' + type] = null;
	}
}

function event_x (evt)
{
	Global.assert (evt);


	return (evt.pageX ? evt.pageX : evt.clientX + scroll_x ())
}

function event_y (evt)
{
	Global.assert (evt);

	return (evt.pageY ? evt.pageY : evt.clientY + scroll_y ())
}

function event_target (evt)
{
	Global.assert (evt);

	return evt.target || evt.srcElement;
}

function event_window (evt)
{
	Global.assert (evt);

	return evt.view
		|| event_target (evt).ownerDocument.parentWindow;
}

function event_stop_propagation (evt)
{
	if (!evt) var evt = window.event;
	evt.cancelBubble = true;
	if (evt.stopPropagation)
		evt.stopPropagation ();
}

function event_is_mouse_out (evt)
{
	if (!evt) var evt = window.event;
	var target = evt.target || evt.srcElement;
	
	if (target != ul)
		return false;
	
	var relatedTarget = evt.relatedTarget || evt.toElement;
	while (relatedTarget != target
	       && relatedTarget.parentNode) {
		relatedTarget = relatedTarget.parentNode;
	}
	if (relatedTarget == target)
		return false;

	return true;
}

/*
 * Dialogue serveur
 */

function serveur_appeler (page)
{
	Global.assert (page);
	Global.assert (arguments.length % 2 == 1);

	var url = page;

	for (var i = 1; i < arguments.length; i+=2) {
		url += (i == 1 ? '?' : '&')
			+ arguments[i] + '=' + escape(arguments[i+1]);
	}

	var iframe;
/* 	if ( !(iframe = document.getElementById ('__acces_serveur')) ) { */
		iframe = document.createElement ('iframe');
/* 		iframe.setAttribute ('id', '__acces_serveur'); */
		iframe.style.display = 'none';
		zone_temporaire_ajouter (iframe);
/* 	} */

	iframe.contentWindow.location = url;
}

/**
 * Appelle une page sur le serveur.
 * Fonction historique.
 * @param url l'adresse de base de la page a appeler
 * @param ... une liste de parametres a ajouter a l'url par paire
 *            de titre, valeur
 */
/* function serveur_appeler (url) */
/* { */
/* 	Global.assert (url); */
/* 	Global.assert (arguments.length % 2 == 1); */

/* 	var url = XML.construireURL.apply (this, arguments); */
/* 	XML.charger (url, */
/* 		     new Function ()); */
/* } */

/*
 * Actions
 */

/**
 * Execute une action du jeu.
 * @param evt             l'evenement click de souris qui declenche l'action
 * @param ref_type_action la reference du type de l'action
 * @param ...             parametres : paires composees du nom du parametre
 *                        suivi de la valeur
 *                        ceux-ci ne doivent contenir aucun espace
 * @return false, pour arreter le traitement de l'evenement
 */
function action_executer (evt, ref_type_action)
{
	Global.assert (ref_type_action > 0);
	Global.assert (arguments.length % 2 == 0);

	var params = '';
	for (var i = 2; i < arguments.length; i+=2) {
		params += (params ? ' ' : '')
			+ arguments[i] + ' ' + arguments[i+1];
	}

	var location = '/jeu/action/proc_action_executer'
		+ '?ref_type_action:int='
		+ ref_type_action
		+ '&params:tokens=' + escape (params);
	
	iframe_surgir (evt, location);

	return false;
}

Module.charger (Module._url ('ajax.ajax'));
Module.charger (Module._url ('correctifs'));
Module.charger (Module._url ('iframe'));
Module.charger (Module._url ('popup'));
