/*
Copyright (c) 2007, PMP Concept
version: 1
*/

/*****************************************************************************
 *
 * 								Objet PMP
 *
 *	Fonction
 *
 *		L'objet PMP est un objet global dont la fonction est la gestion des
 *		différentes classes JavaScript de la librairie PMP.
 *
 *****************************************************************************/

// L'objet global PMP.

if (typeof PMP == "undefined") 
{
    /***
     * 
	 *	Si l'objet PMP existe il sera écrasé de sorte que le namespace soit
     	préservé															 *
     																	     *
																		   ***/
	var PMP = {};
}



/***
 * 
 * 	Retourne le namespace spécifié et le crée s'il n'existe pas
 *
 * 	Attention aux mots réservés lors de la définition d'un espace de noms
 *
 *
 *	Paramètres
 * 		arguments : (String*) espace de nom à créer
 *	
 *	Retourne une reference (Object) sur le dernier espace de nom crée		 *
     																	     *
																		   ***/
PMP.namespace = function() 
{
    var arg = arguments;	// récupère la liste des arguments passés en paramètres
	var o=null, i, j, d;
	
    for (i=0; i<arg.length; i++)
	{
        d=arg[i].split(".");
        o=PMP;

        // PMP est implicite donc ignoré si passé en paramètre
        for (j=(d[0] == "PMP") ? 1 : 0; j<d.length; j++) 
		{
            o[d[j]]=o[d[j]] || {};
            o=o[d[j]];
        }
    }

    return o;
};



/***
 * 
 * 	Initialisation de l'objet global PMP									 *
     																	     *
																		   ***/
PMP.init = function() {
    this.namespace("util");
    if (typeof PMP_config != "undefined") 
	{
        var l=PMP_config.listener;
		var ls=PMP.env.listeners;
		var unique=true, i;
        if (l) 
		{
            // si PMP est chargé plusieurs fois on vérifie s'il s'agit d'une
            // nouvelle configuration.  
            // Si c'est le cas ajoute le nouveau composant
            for (i=0; i<ls.length; i++) 
			{
                if (ls[i]==l) 
				{
                    unique=false;
                    break;
                }
            }
            
			if (unique) 
			{
                ls.push(l);
            }
        }
    }
};



/***
 * 
 * 	Utilise PMP.widget.Logger s'il est défini pour loguer un message,
 *	sinon stocke le message dans un tableau
 *
 *
 *	Paramètres
 *		message :	(String) Le message à loguer
 * 		type :		(String) Le type de message (optionel).
 *					Ex: "info", "warning", "error". Par défaut "info".
 *     	src :		(String) La source du message (optionel)
 * 
 *	Retourne un booléen pour indique si le message a été loguer ou non.
 */
PMP.log = function(message, type, src) 
{
    var logger = PMP.widget.Logger;
    if(logger && logger.log) 
		return logger.log(message, type, src);
    else 
	{
		 // si le tableau de message n'existe pas on le crée
		 if(typeof PMP.messages == "undefined")
		 	PMP.messages = new Array();
			
		 if(PMP.messages && typeof PMP.messages == "Array")
		 {
		 	PMP.messages[PMP.messages.length]['message'] = message;
			PMP.messages[PMP.messages.length]['type'] = type;
			PMP.messages[PMP.messages.length]['src'] = src;
		 }
        return false;
    }
};



/***
 * 
 * 	Enregistre un module avec l'objet PMP
 *
 *
 * 	Paramètres
 * 		nom : 		(String) le nom du module
 * 		classe : 	(Function) référence de la class principal du module. 
 					Cette classe sera marquée avec les infos de version
 *          		afin d'identifier quelle version est utilisée dans le
 					cas ou plusieurs versions seraient chargées
 *		data :		(Object) metadata du module. 
 					Actuellement doit contenir les propriétés "version" et
 *                  "build" aus minimum. 									 *
     																	     *
																		   ***/
PMP.register = function(nom, classe, data) 
{
    var mods = PMP.env.modules;
    if (!mods[nom]) 
	{
        mods[nom] = { versions:[], builds:[] };
    }
	
    var m = mods[nom];
	var v = data.version;
	var b = data.build;
	var ls = PMP.env.listeners;
    m.nom = nom;
    m.version = v;
    m.build = b;
    m.versions.push(v);
    m.builds.push(b);
    m.classe = classe;
	
    // déclenche l'écouteur de chargement du module
    for (var i=0; i<ls.length; i++) 
	{
        ls[i](m);
    }
	
    // label the main class
    if (classe) 
	{
        classe.VERSION = v;
        classe.BUILD = b;
    } else {
        PMP.log("classe principale indéfinie pour le module " + nom, "warning");
    }
};



/***
 * 
 * 	Récupère et enregistre l'environnement de navigation ainsi que certains 
 *  paramètres de la librairie PMP 											 *
     																	     *
																		   ***/
PMP.env = PMP.env || {
    
	modules: [],
    
    listeners: [],
   
   
   /***
	* 
 	* 	Retourne les infos de version d'un module
    *	
	*	Paramètres
	*		nom :	(String) Le nom du module
    * 	
	*	Retourne les informations (Object)									 *
     																	     *
																		   ***/
    getVersion: function(nom) {
        return PMP.env.modules[nom] || null;
    }
};


/***
 * 
 * 	Fournie les fonctions les plus communément employées *
     																	     *
																		   ***/
PMP.common = {
    
	// Détermine si l'objet envoyé en paramère est un tableau
    isArray: function(obj)
	{ 
		if (obj && obj.constructor && 
                   obj.constructor.toString().indexOf('Array') > -1) 
		{
            return true;
        } 
		else
		{
            return PMP.common.isObject(obj) && obj.constructor == Array;
        }
    },

    // Détermine si l'objet envoyé en paramère est un booléen
    isBoolean: function(obj)
	{
        return typeof obj == 'boolean';
    },
    
    // Détermine si l'objet envoyé en paramère est une fonction
    isFunction: function(obj)
	{
        return typeof obj == 'function';
    },
        
    // Détermine si l'objet envoyé en paramère est null
    isNull: function(obj)
	{
        return obj === null;
    },
        
    // Détermine si l'objet envoyé en paramère est un nombre
    isNumber: function(obj) 
	{
        if(PMP.common.isUndefined(obj))
			return false;
		
		obj = parseInt(obj);
		return typeof obj == 'number' && isFinite(obj);
    },
      
    // Détermine si l'objet envoyé en paramère est un objet ou une fonction
    isObject: function(obj)
	{
        return obj && (typeof obj == 'object' || PMP.common.isFunction(obj));
    },
        
    // Détermine si l'objet envoyé en paramère est une chaine
    isString: function(obj) 
	{
        return typeof obj == 'string';
    },
        
    // Détermine si l'objet envoyé en paramère n'est pas défini
    isUndefined: function(obj) 
	{
        return typeof obj == 'undefined';
    },
    
    // Détermine si l'objet envoyé en paramère est un evenement
    isEvent: function(obj) 
	{
        if (obj && obj.constructor && 
                   obj.constructor.toString().indexOf('Event') > -1) 
		{
            return true;
        } 
		else
		{
            //return PMP.common.isObject(obj) && obj.constructor == Event;
			return true;
        }
    },
        
    // Détermine si l'objet a une propriété ou non
    hasOwnProperty: function(obj, prop) 
	{
        if (Object.prototype.hasOwnProperty) {
            return obj.hasOwnProperty(prop);
        }
        
        return !PMP.common.isUndefined(obj[prop]) && 
                obj.constructor.prototype[prop] !== obj[prop];
    },
        
    
   /***
	* 
 	* 	Définit le prototype, le constructeur et la superclasse pour gérer
    * 	un héritage qui permet de chainer les constructeurs et methodes.
    *	
	*	Paramètres
	* 		subclass : 		(Function) L'objet à modifier
    * 		superclass :	(Function) L'objet parent
    *		overrides :		(Object) propriétés/methodes supplémentaire à 
							ajouter au proptotype.  
							Les propriétés/methodes définies ici remplace 
							les propriétés/methodes de la superclasse		 *
     																	     *
																		   ***/
    extend: function(subclass, superclass, overrides) 
	{
        if (!superclass||!subclass) 
		{
            throw new Error("PMP.common.extend : echec, vérifier les paramètres.");
        }
        
		var F = function() {};
        F.prototype = superclass.prototype;
        subclass.prototype = new F();
        subclass.prototype.constructor = subclass;
        subclass.superclass = superclass.prototype;
        if (superclass.prototype.constructor == Object.prototype.constructor) 
		{
            superclass.prototype.constructor = superclass;
        }
    
        if (overrides)
		{
            for (var i in overrides)
			{
                subclass.prototype[i] = overrides[i];
            }
        }
    },
	
	
	
	/***
	* 
 	* 	Inclut un fichier JavaScript s'il n'est pas déjà présent.
    *	
	*	Paramètres
	* 		fichier : 		(String) Le nom du ficher à inclure				 *
     																	     *
																		   ***/
    include: function (fichier) 
	{
		var head = document.getElementsByTagName('head')[[0]];
		
		// vérification de l'existance de ce fichier
		var exists = false;
		var scripts = head.getElementsByTagName('script');
		for (var i=0; i<scripts.length; i++)
		{
			if( scripts[i].src && 
				(scripts[i].src.length >= fichier.length) &&  
				scripts[i].src.substr(scripts[i].src.length - fichier.length, fichier.length) == fichier )
				exists = true;
		}
		
		if(!exists)
		{
			var head_inc = document.createElement('script');
			head_inc.setAttribute('type','text/javascript');
			head_inc.setAttribute('language','javascript');
			var path = this.common.isUndefined(this.pathlib) || this.common.isNull(this.pathlib) ? fichier : this.pathlib + fichier;
			//alert(head + ", " + path);
			head_inc.setAttribute('src',path);
			head.appendChild(head_inc);
		}
	},
	
	
	
	/***
	* 
 	* 	Retourn le body du document.
    *																		 *
     																	     *
																		   ***/
   	truebody : function ()
   	{
		//return (!window.opera && document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
		return document.documentElement ? document.documentElement : document.body;
	},
	
	
	/***
	* 
 	* 	Retourn la position top d'un élément.
    *																		 *
     																	     *
																		   ***/
   	getElementTop : function (element)
   	{
		var elemTop = 0;
		
		if(element)
		{
			elemTop = element.offsetTop;
			tempEl = element.offsetParent;
			while (tempEl != null) {
				elemTop += tempEl.offsetTop;
				tempEl = tempEl.offsetParent;
			}
		}
		
		return elemTop;
	},
	
	
	/***
	* 
 	* 	Retourn la position left d'un élément.
    *																		 *
     																	     *
																		   ***/
   getElementLeft : function (element)
   	{
		var elemLeft = 0;
			
		if(element)
		{
			elemLeft = element.offsetLeft;
			tempEl = element.offsetParent;
			while (tempEl != null) {
				elemLeft += tempEl.offsetLeft;
				tempEl = tempEl.offsetParent;
			}
		}
		
		return elemLeft;
	},
	
	
	/***
	* 
 	* 	Retourn le noeud courant lors de l'execution d'une page.
    *																		 *
     																	     *
																		   ***/
   getCurrentNode : function (node)
   	{
		if( this.isUndefined(node) )
			var node = document.lastChild;
		
		while (node && node.nodeType != 1)
		{
			if(node.previousSibling)
				node = node.previousSibling;
			else
				break;
		}
		
		if( node.nodeType == 1 )
			return this.getCurrentNode(node.lastChild) || node;
			
		return false;
	}
	
};


// ajout de fonctions aux prototypes d'objets javascript
Function.prototype.bind = function (object)
{
    var method = this;
    return function () 
	{
        method.apply(object, arguments);
    };
}


String.prototype.ltrim = function()
{
	var str = this;
	var regExpBeginning = /^\s+/;
	
	return str.replace(regExpBeginning, "");
};

String.prototype.rtrim = function()
{
	var str = this;
	var regExpEnd       = /\s+$/;
	
	return str.replace(regExpEnd, "");
};

String.prototype.trim = function()
{
	var str = this;
	
	return str.ltrim().rtrim();
};


// Initialisation de l'objet PMP
PMP.init();
       
// définit un alias de la fonction extend
PMP.extend = PMP.common.extend;

// définit un alias de la fonction include
PMP.include = PMP.common.include;

PMP.register("pmp", PMP, {version: "1", build: "001"});

