/*
 * LICENCE[[
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1/CeCILL 2.O 
 *
 * The contents of this file are subject to the Mozilla Public License Version 
 * 1.1 (the "License"); you may not use this file except in compliance with 
 * the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ 
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the 
 * License. 
 * 
 * The Original Code is utc.fr code. 
 * 
 * The Initial Developer of the Original Code is 
 * Universite de Technologie de Compiegne. 
 * 
 * Portions created by the Initial Developer are Copyright (C) 2005 
 * the Initial Developer. All Rights Reserved. 
 * 
 * Contributor(s): 
 * 
 * 
 * Alternatively, the contents of this file may be used under the terms of 
 * either of the GNU General Public License Version 2 or later (the "GPL"), 
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 
 * or the CeCILL Licence Version 2.0 (http://www.cecill.info/licences.en.html), 
 * in which case the provisions of the GPL, the LGPL or the CeCILL are applicable 
 * instead of those above. If you wish to allow use of your version of this file 
 * only under the terms of either the GPL or the LGPL, and not to allow others 
 * to use your version of this file under the terms of the MPL, indicate your 
 * decision by deleting the provisions above and replace them with the notice 
 * and other provisions required by the GPL or the LGPL. If you do not delete 
 * the provisions above, a recipient may use your version of this file under 
 * the terms of any one of the MPL, the GPL, the LGPL or the CeCILL.
 * ]]LICENCE
 */
const HTTPDATAPROVIDER_CONTRACTID 	= '@scenari.com/httpdataprovider;1';
const HTTPDATAPROVIDER_CID 			= Components.ID('{98C2A73F-E9A7-4EAA-94C7-4771E5C359EF}');
const HTTPDATAPROVIDER_IID 			= Components.interfaces.scIDataProvider;

/* The Http data server. */
function scHttpDataProvider() {
}

/* The OS 
	affecte dans gOS une string contenant le nom de l'OS :
	Win, Mac, UNIX
*/
var gOS="";
function getOS() {
	try{
		if(gOS) return gOS;
		
		var platform = Components.classes["@mozilla.org/network/protocol;1?name=http"].getService(Components.interfaces.nsIHttpProtocolHandler);
		platform = platform.oscpu.toLowerCase();
		if(platform.indexOf("win") != -1)
			gOS = "Win";
		else if(platform.indexOf("mac") != -1)
			gOS = "Mac";
		else if(platform.indexOf("unix") != -1 || platform.indexOf("linux") != -1 || platform.indexOf("sun") != -1)
			gOS = "UNIX";
		else
			gOS = "";
		//debug("OS = "+gOS+" ("+platform+")");
	}catch(e){
		debug("OS unknown: "+e);
	}	
			
}

/* Définition du Http data server. */
scHttpDataProvider.prototype = {

	/**
	 *
	 */
	init : function(pUrlServer, pCdUniverse, pAccount, pPassword, pOwnerWspServer) {
		var vPrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
		var vObsSvc = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
		
		//Suppression du management offline de Xulrunner.
		var vIoService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService2);
		vIoService.manageOfflineStatus = false;
		vIoService.offline = false;

		var vPrefixLocal = "serverlocal:";
		
		if(this.fUrlServerLocal) {
			//serveur local privé initialisé -> on le quitte.
			this.quit();
		}
		
		this.fDebugComm = false;
		try {
			this.fDebugComm = (vPrefs.getCharPref("scenari.debug.serverCommunication")=="all");
		} catch(e){};
		
		this.fWspServer = pOwnerWspServer;
		this.fTitle="";
		this.fUrlServer = (pUrlServer.charAt(pUrlServer.length - 1)!='/') ? pUrlServer : pUrlServer.substring(0, pUrlServer.length - 1);
		this.fUrlIni = pUrlServer;
		this.fPathService = "/s";
		this.fPathAgent = "/a";
		
		
		
		this.fUrlServerLocal = null;
		this.fIsOwnerServerLocal = false;
		
		this.fUser = {fAccount:pAccount, fPassword:pPassword};
		
		// Propriétés du serveur local
		this.fIsLocal = (this.fUrlServer.substring(0, vPrefixLocal.length) == vPrefixLocal);
		try {
			var vDefaultUrlServerLocal = vPrefs.getCharPref("scenari.urlServerLocal");
			if(vDefaultUrlServerLocal && this.fUrlServer.substring(0, vDefaultUrlServerLocal.length) == vDefaultUrlServerLocal) {
				//on simule un serveur local sans avoir à lancer de jvm.
				this.fIsLocal = true;
			}
		} catch(e){
			// pref scenari.urlServerLocal non-disponible.
		}
		this.fCanLaunchLocalServer = false;
		try {
			this.fCanLaunchLocalServer = vPrefs.getBoolPref("scenari.canLaunchLocalServer");
		} catch(e){
			debug("pref 'scenari.canLaunchLocalServer' undefined. "+e);
		}
		
		// détermination du code de l'univers
		if(this.fIsLocal){
			try {
				this.fCdUnivers = pCdUniverse ? pCdUniverse : vPrefs.getCharPref("scenari.defaultUniversCode");
			} catch(e){
				debug("pref 'scenari.defaultUniversCode' undefined. "+e);
				this.fCdUnivers = "cms";
			}
		}else{
			try {
				this.fCdUnivers = pCdUniverse ? pCdUniverse : vPrefs.getCharPref("scenari.defaultDistantUniversCode");
			} catch(e){
				debug("pref 'scenari.defaultDistantUniversCode' undefined. "+e);
				this.fCdUnivers = "chain";
			}
		}

		//Abonnement à la liste des wsp actifs
		this.fWspReg = Components.classes["@scenari.com/wspregistryservice;1"].getService(Components.interfaces.scIWspRegistryService);
		this.xBuildWspList();
		this.fWspReg.addWspRegListener(this);
		
		//Gestion du reload de l'ihm avec préservation du serveur local.
		if(this.fCanLaunchLocalServer && this.fIsLocal) {
			var vReloadLocalUrl = null;
			try {
				vReloadLocalUrl = vPrefs.getCharPref("scenari.ui.reloadLocalUrlServer");
				//Pas d'exception : on est en mode rechargement de l'ihm avec un serveur local dont on était le owner.
				this.fUrlServerLocal = this.fUrlServer;
				this.fUrlServer = vReloadLocalUrl;
				this.fIsOwnerServerLocal = true;
				//On s'abonne pour la fermeture de l'appli Moz pour forcer le kill de la JVM.
				vObsSvc.addObserver(this, "quit-application", false);	
				vPrefs.clearUserPref("scenari.ui.reloadLocalUrlServer");
			} catch(e){
				debug();
				// pref non présente, on n'est pas en mode reload
			}
		}
		
		// Lancement du serveur
		if(this.fCanLaunchLocalServer && this.fIsLocal && ! this.fIsOwnerServerLocal) {
			//On demande un serveur local, et on n'en référence pas déjà un en tant que propriétaire -> on va créer un serveur local.
			
			//On memorise l'url initiale.
			this.fUrlServerLocal = this.fUrlServer;
			
			//Recherche du port
			var vEndIdx = this.fUrlServer.indexOf("/", vPrefixLocal.length-1);
			if( (vEndIdx<0 && this.fUrlServer.length==vPrefixLocal.length) || vEndIdx==vPrefixLocal.length) {
				//Pas de port, recherche d'un port disponible.
				var vServerSocket = Components.classes['@mozilla.org/network/server-socket;1'].createInstance(Components.interfaces.nsIServerSocket);
				try {
					vServerSocket.init(-1, true, 1);
					vPort = vServerSocket.port;
					vServerSocket.close();
				} catch(e){
					debug("scHttpDataProvider.init dynamic port search failed : "+e);
					vPort = "8017"; //Port par defaut
				}
			} else if(vEndIdx<0) {
				vPort = this.fUrlServer.substring(vPrefixLocal.length);
			} else {
				vPort = this.fUrlServer.substring(vPrefixLocal.length, vEndIdx);
			}
			this.fUrlServer = "http://127.0.0.1:"+vPort;
			if(vEndIdx>=0) this.fUrlServer += this.fUrlServerLocal.substring(vEndIdx);
			
			try{
				debug("Lancement du serveur local : "+this.fUrlServer+" - "+this.fCdUnivers+ " @"+this.fUser.fAccount);
				var vFolderService = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
				this.fLocalServer = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
				getOS();
				var vSeparator = gOS=="Win" ? "\\" : "/";
				
				// Calcul du path de AppDirPath...
				var vFile = null;
				var vAppDirPath = null;
				try {
					vAppDirPath = vPrefs.getCharPref("scenari.app.path");
				} catch(e){ // AppDirPath n'est pas dans les prefs => fallback par défaut
					vFile = vFolderService.get("ARes", Components.interfaces.nsIFile).parent.parent;//répertoire bin
					vAppDirPath = vFile.path;
				}
				
				// Calcul du path d'OO
				var vOoPath = null;
				var vOoDirMode = 0;
				try{vOoDirMode = vPrefs.getIntPref("scenari.tools.oo.dirMode");} catch(e){};
				if(vOoDirMode==1){//OO embarqué
					var vOoEmbedPath = null;
					try{vOoEmbedPath = vPrefs.getCharPref("scenari.tools.oo.embed.path");} catch(e){};
					if(vOoEmbedPath) vOoPath = vAppDirPath + vSeparator + vOoEmbedPath;
				}else if(vOoDirMode==2){//OO sur le DD
					var vOoCustomPath = null;
					try{vOoCustomPath = vPrefs.getComplexValue("scenari.tools.oo.path", Components.interfaces.nsILocalFile);} catch(e){};
					if(vOoCustomPath) vOoPath = vOoCustomPath.path;
				}
				
				var vOpts = [];
				var vIdxOpt = 0;
				
				
				if(gOS=="Win" || gOS=="UNIX" || gOS=="Mac"){ 
					var vClassPathSeparator = gOS=="Win" ? ";" : ":";
					
					var vScLibPath 		= vAppDirPath + vSeparator + "scServer" + vSeparator + "sclib";
					var vJavaLibPath 	= vAppDirPath + vSeparator + "scServer" + vSeparator + "javalib";
					var httpPublicPath	= vAppDirPath + vSeparator + "scServer" + vSeparator + "httppublic";
					
					var vScConfPath 		= vAppDirPath + vSeparator + "scServer" + vSeparator + "conf";
	
					// Calcul du path de la JVM...
					try {
						var vJvmPathPref = vPrefs.getCharPref("scenari.jvm.path");
						vFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
						var vJvmPaths = vJvmPathPref.split(vClassPathSeparator); 
 						for(var i=0;i<vJvmPaths.length;i++){ 
 							vFile.initWithPath(vJvmPaths[i]); 
							if (vFile.exists()) break; 
						} 
					} catch(e){ // Path de la JVM n'est pas dans les prefs
						if (gOS == "Mac"){
							vFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
							vFile.initWithPath("/usr/bin/java");
						} else {
							vFile.append("scServer");
							vFile.append("jre");
							vFile.append("bin");
							gOS=="Win" ? vFile.append("javaw.exe") : vFile.append("java");
						}
					}
					// debug("JVM vFile.path:: "+vFile.path); 

					vOpts[vIdxOpt++] = "-Duser.dir=" + vAppDirPath;
					vOpts[vIdxOpt++] = "-classpath";
					
					// Déclaration des librairies scenari
					vOpts[vIdxOpt] = "";
					var vScJars;
					try {
						var vList = vPrefs.getCharPref("scenari.jar.sc.list");
						vScJars = vList.split(";");
						for (var ii=0; ii<vScJars.length; ii++) {
							if(vScJars[ii]!="") vOpts[vIdxOpt] += vScLibPath + vSeparator + vScJars[ii] + vClassPathSeparator;
						}
					} catch(e){debug("pref 'scenari.jar.sc.list' undefined. "+e);}
					// Déclaration des librairies ext
					var vExtJars;
					try {
						var vList = vPrefs.getCharPref("scenari.jar.ext.list");
						vExtJars = vList.split(";");
						for (var ii=0; ii<vExtJars.length; ii++) {
							if(vExtJars[ii]!="") vOpts[vIdxOpt] += vJavaLibPath + vSeparator + vExtJars[ii] + vClassPathSeparator;
						}
					} catch(e){debug("pref 'scenari.jar.ext.list' undefined. "+e);}
					vOpts[vIdxOpt] += httpPublicPath + vSeparator + "applets" + vSeparator + "classes" + vClassPathSeparator;
					vIdxOpt++;
					//vOpts[vIdxOpt++] = "-verbose:gc";
					if(vPrefs.getIntPref("network.proxy.type") > 0){
						vOpts[vIdxOpt++] = "-DproxySet=true";
						vOpts[vIdxOpt++] = "-Dhttp.proxyHost="+vPrefs.getCharPref("network.proxy.ftp");
						vOpts[vIdxOpt++] = "-Dhttp.proxyPort="+vPrefs.getIntPref("network.proxy.ftp_port");
						vOpts[vIdxOpt++] = "-Dhttp.nonProxyHosts"+vPrefs.getCharPref("network.proxy.no_proxies_on").replace(",","|").replace(" ","");
					}
					if (gOS == "Mac"){
						vOpts[vIdxOpt++] = "-Xdock:name=SCENARIserver";
						vOpts[vIdxOpt++] = "-Dcom.apple.macos.useScreenMenuBar=false";
						vOpts[vIdxOpt++] = "-Dcom.apple.macosx.useScreenMenuBar=false";
					}
					if(vOoPath){
						vOpts[vIdxOpt++] = "-Dcom.sun.star.lib.loader.unopath="+vOoPath;
					}
					vOpts[vIdxOpt++] = "-Xms"+vPrefs.getCharPref("scenari.jvm.xms");
					vOpts[vIdxOpt++] = "-Xmx"+vPrefs.getCharPref("scenari.jvm.xmx");
					vOpts[vIdxOpt++] = "com.scenari.c.chain2.EChain2Main";
					if (gOS == "Mac"){
						vOpts[vIdxOpt++] = "file:" + vScConfPath + vSeparator + "init.xml";
					} else {
						vOpts[vIdxOpt++] = "file:scServer" + vSeparator + "conf" + vSeparator + "init.xml";
					}
					vOpts[vIdxOpt++] = vPort;
				} //Fin cas os==Win, Mac, Unix
				else {
					// TODO : traitement si os ni Mac ni Win in unix ?
				}
				if(!vFile.exists()){
					var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
					ps.alert(null, "Erreur de d\u00E9marrage", "Des \u00E9l\u00E9ments de l\'application sont manquants.\nVeuillez red\u00E9marrer votre ordinateur et r\u00E9installer l\'application.");
					throw ("Fichier introuvable : '" + vFile.path + "'.");
				}
				this.fLocalServer.init(vFile);
				this.fLocalServer.run(false, vOpts, vIdxOpt);
				
				this.fIsOwnerServerLocal = true;
				
				//On s'abonne pour la fermeture de l'appli Moz pour forcer le kill de la JVM.
				vObsSvc.addObserver(this, "quit-application", false);		
			} catch (e){
				debug("Connection on server failed. Port : "+vPort+".\n("+e+")");
			}
		} else {
			try {
				var vDefaultUrlServerLocal = vPrefs.getCharPref("scenari.urlServerLocal");
				if(vDefaultUrlServerLocal && this.fUrlServer.substring(0, vDefaultUrlServerLocal.length) == vDefaultUrlServerLocal) {
					//on simule un serveur local sans avoir lancer de jvm.
					this.fIsLocal = true;
				}
			} catch(e){
				// pref scenari.urlServerLocal non-disponible.
			}
		}
		
		//Creation du timer qui maintient la connection régulièrement.
		this.fTimerKeepAlive = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
		this.fTimerKeepAlive.initWithCallback(new KeepAliveServer(this), this.fIsLocal ? 5000 : 25000, Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
		
		this.fUrlService = this.fUrlServer+this.fPathService+"/"+this.fCdUnivers;
		if(pAccount) this.fUrlService += ("/~"+encodeURIComponent(pAccount));
		this.fUrlAgent = this.fUrlServer+this.fPathAgent+"/"+this.fCdUnivers+"/";
		if(pAccount) this.fUrlAgent += ("~"+encodeURIComponent(pAccount)+"/");
		
		debug(this.fUrlService + " - " + this.fUrlAgent);
		
		if(!this.fIsLocal){// si serveur distant : affectation du user
			this.xSetAuth(pAccount, pPassword);
		}
		
		this.fItemsListeners = null;
	},
	
	isProviderReady : function (){
		try{
			var vReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
			var vUrl = this.fUrlService+"/u/ping";
			vReq.open("GET", vUrl, false, this.fUser.fAccount, this.fUser.fPassword);
			this.xSetReqHeaders(vReq);
			vReq.send(null);
			this.xGetRespHeadersAsynch(vReq);
			if(vReq.status == 200) return true;
		} catch(e){
			debug("scHttpDataProvider.isProviderReady : " + e);
		}
		return false;
	},
	isLocal : function (){
		return this.fIsLocal;
	},
	getCurrentUser : function (){
		return this.fUser.fAccount;
	},
	quit : function (){
		try{
			if(this.fTimerKeepAlive) this.fTimerKeepAlive.cancel();
		} catch(e){
			debug("kill server.fTimerKeepAlive failed : "+e);
		}
		if(this.fCanLaunchLocalServer && this.fUrlServerLocal && this.fIsOwnerServerLocal) {
			var vUiReloadMode = false;
			var vPrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
			try{vUiReloadMode = vPrefs.getBoolPref("scenari.ui.reload"); } catch(e){}
			if(vUiReloadMode) {
				vPrefs.setCharPref("scenari.ui.reloadLocalUrlServer", this.fUrlServer);
			} else {
				try{
					var vObsSvc = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
					vObsSvc.removeObserver(this, "quit-application");
				
					var vReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
					var vUrl = this.fUrlService + "/u/quitter";
					vReq.open("GET", vUrl, false, this.fUser.fAccount, this.fUser.fPassword);
					this.xSetReqHeaders(vReq);
					vReq.send(null);
					//this.xGetRespHeaders(vReq);
				} catch(e){
					debug("kill server failed : "+e);
				}
			}
		}
		this.fUrlServer = null;
		this.fCdUnivers = null;
		this.fUser = null;
		this.fUrlServerLocal = null;
		this.fIsOwnerServerLocal = false;
		this.fUrlService = null;
		this.fUrlAgent = null;
		this.fItemsListeners = null;
	},
	
	getAgentUrl : function(pIdInstance, pUrlDialogAndParams){
		return this.fUrlAgent + encodeURIComponent(pIdInstance) + pUrlDialogAndParams;
	},

	getServiceUrl : function(pUrlDialogAndParams){
		return this.fUrlService + pUrlDialogAndParams;
	},
	
	getSourceUrl : function(pCdSource){
		if(pCdSource == "publichtml") {
			return this.fUrlServer;
		} else {
			return this.fUrlService + "/u/" + pCdSource;
		}
	},
	
	getIniUrl : function(){
		return this.fUrlIni;
	}, 
	
	getWspServer : function(){
		return this.fWspServer;
	},
	
	getDomFromService : function (pUrlDialogAndParams) {
		try{
			var vUrl = this.fUrlService+pUrlDialogAndParams;
			var vReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
			//vReq.open("GET", vUrl, false, this.fUser.fAccount, this.fUser.fPassword);
			vReq.open("GET", vUrl, false, this.fUser.fAccount, this.fUser.fPassword);
			this.xSetReqHeaders(vReq);
			vReq.send(null);
			this.xGetRespHeadersAsynch(vReq);
			var vResp = vReq.responseXML;
			return vResp;
		} catch(e){
			debug("scHttpDataProvider.getDomFromService '"+this.fUrlServer+"': "+pUrlDialogAndParams+" : " + e);
			throw e;
		}
	},

	getTextFromService : function (pUrlDialogAndParams) {
		var vUrl = this.fUrlService+pUrlDialogAndParams;
		var vReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
		vReq.open("GET", vUrl, false, this.fUser.fAccount, this.fUser.fPassword);
		this.xSetReqHeaders(vReq);
		vReq.send(null);
		this.xGetRespHeadersAsynch(vReq);
		var vResp = vReq.responseText;
		return vResp;
	},
	
	setPassword : function(pPassword){
		try{
			this.xSetAuth(this.fUser.fAccount, pPassword);
			var vIsReady = this.isProviderReady();
			// if(!vIsReady) this.isProviderReady();// Note : utile car la première requete envoyée aprés un changement de password ne possède pas le tag "Authorization" dans son entête
		} catch(e){
			debug("scHttpDataProvider.setPassword " + e);
			throw e;
		}
	},
	
	xSetAuth : function(pAccount, pPassword){
		try{
			//Supp des entrées pour ce login
			var vCookieManager = Components.classes["@mozilla.org/cookiemanager;1"].getService(Components.interfaces.nsICookieManager2);
			var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
			var vAuth = Base64.encode(pAccount+":"+pPassword);
			var vExpiry	= (new Date("Jan 1, 2030")).getTime() / 1000; // Le parametre aIsSession=true devrait faire en sorte que vExpiry n'est pas pris en compte, mais ça n'est pas le cas. Bug Gecko1.9
			
			var vUrlService = ioService.newURI(this.fUrlService, null, null);
			vCookieManager.add(vUrlService.host ,vUrlService.path , "scAuth" , vAuth, false , false , true, vExpiry);// On ne peut mettre le port dans l'attribut domaine; Bug Gecko1.9
			
			var vUrlAgent = ioService.newURI(this.fUrlAgent, null, null);
			vCookieManager.add(vUrlAgent.host ,vUrlAgent.path , "scAuth" , vAuth, false , false , true, vExpiry );
			this.fUser = {fAccount:pAccount, fPassword:pPassword};
		} catch(e){
			debug("scHttpDataProvider.xSetAuth " + e);
			throw e;
		}
	},

	dialogSynchWithService : function (pUrlDialogAndParams, pMethod, pBody, pContentType) {
		var vUrl = this.fUrlService+pUrlDialogAndParams;
		var vReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
		//debug("dialogSynchWithService="+vUrl);
		vReq.open(pMethod, vUrl, false, this.fUser.fAccount, this.fUser.fPassword);
		this.xSetReqHeaders(vReq);
		if(pBody!=null) {
			var vFile;
			try{vFile = (pBody.QueryInterface) ? pBody.QueryInterface(Components.interfaces.nsIFile) : null;}catch(e){}
			if(vFile) {
				//nsIUri source
				//var vUriFrom = null;
				//nsIUri destination
				//var vUriTo = null;				
				//var vPersist = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Components.interfaces.nsIWebBrowserPersist);
				//vPersist.saveURI(vUriFrom, null, null, null, null, vUriTo);
				//vReq.setRequestHeader("Content-Type", "application/octet-stream");
				vReq.setRequestHeader("Content-Length", vFile.fileSize);
				var vStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
				vStream.init(vFile, 1, 0, 0);
				try {
					//var vReader =  Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
					//vReader.init(vStream);
					//var vText = vReader.read(1000);
					//debug("dialogSynchWithService with file = "+vText);
					//vReq.send(vText);
					//vReader.close();
					vReq.send(vStream);
					
					//vReq.send("testcontenu");
				} finally{
					//vReader.close();
					vStream.close();
				}
			} else {
				//debug("Content-Type = "+pContentType+"  - Body = "+pBody);
				if(pContentType) vReq.setRequestHeader("Content-Type", pContentType);
				//vReq.setRequestHeader("Content-Type", pContentType || "text; charset=ISO-8859-1");//
				vReq.send(pBody);//pBody
			}
		} else {
			//debug("NoBody");
			vReq.send(null);
		}
		this.xGetRespHeadersAsynch(vReq);
		return vReq;
	},
		
	loadFromService : function (pUrlDialogAndParams, pFctCallBack, pFctCallBackError) {
		try {
			//debug("loadFromService="+pUrlDialogAndParams);
			var vUrl = this.fUrlService+pUrlDialogAndParams;
			var vReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
			vReq.open("GET", vUrl, true, this.fUser.fAccount, this.fUser.fPassword);
			this.xSetReqHeaders(vReq);
			//debug("this.fUser.fAccount:: "+this.fUser.fAccount+", this.fUser.fPassword:: "+this.fUser.fPassword);
			this.xSetCallBacks(vReq, pFctCallBack, pFctCallBackError);
			vReq.send(null);
		} catch(e){
			debug("scHttpDataProvider.loadFromService '"+this.fUrlServer+"': "+pUrlDialogAndParams+" : "+e);
			throw e;
		}
	},

	dialogAsynchWithService : function (pUrlDialogAndParams, pMethod, pBody, pContentType, pFctCallBack, pFctCallBackError) {
		try {
			//debug("dialogAsynchWithService="+pUrlDialogAndParams);
			var vUrl = this.fUrlService+pUrlDialogAndParams;
			var vReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
			vReq.open(pMethod, vUrl, true, this.fUser.fAccount, this.fUser.fPassword);
			this.xSetReqHeaders(vReq);
			this.xSetCallBacks(vReq, pFctCallBack, pFctCallBackError);
			if(pContentType) vReq.setRequestHeader("Content-Type", pContentType);
			vReq.send(pBody);
		} catch(e){
			debug("scHttpDataProvider.dialogAsynchWithService "+pMethod+" - "+pUrlDialogAndParams+" : "+e);
			throw e;
		}
	},
	
	loadFromAgent : function (pIdInstance, pUrlDialogAndParams, pFctCallBack, pFctCallBackError) {
		try {
			//debug("loadFromAgent="+pUrlDialogAndParams);
			var vUrl = this.fUrlAgent + encodeURIComponent(pIdInstance) + pUrlDialogAndParams;
			var vReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
			vReq.open("GET", vUrl, true, this.fUser.fAccount, this.fUser.fPassword);
			this.xSetReqHeaders(vReq);
			this.xSetCallBacks(vReq, pFctCallBack, pFctCallBackError);
			vReq.send(null);
		} catch(e){
			debug("scHttpDataProvider.loadFromAgent "+pIdInstance+" - "+pUrlDialogAndParams+" : "+e);
			throw e;
		}
	},
	
	
	dispatchUpdateUri : function (pCdWsp, pUri, pEventType, pAuthor, pSynch){
		if(pSynch) {
			this.xDispatchUpdate(pCdWsp, pUri, pEventType, pAuthor);
		} else {
			var vTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
			vTimer.initWithCallback(new ServerHttpDispatchUpdt(this, pCdWsp, pUri, pEventType, pAuthor), 20, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
		}
	},
	
	addItemsListener : function (pListener){
		var vListener = this.fItemsListeners;
		if(vListener){
			while(vListener.next) vListener = vListener.next;
			vListener.next = {lstn:pListener};
		} else {
			this.fItemsListeners = {lstn:pListener};
		}
	},
	
	removeItemsListener : function (pListener){
		var vListener = this.fItemsListeners;
		var vPrevious = null;
		while(vListener && vListener.lstn != pListener) {
			vPrevious = vListener;
			vListener = vListener.next;
		}
		if(vListener) {
			if(vPrevious) {
				vPrevious.next = vListener.next;
			} else {
				this.fItemsListeners = vListener.next;
			}
		}
	},
	
	fIdAuthor : 0,
	
	newIdAuthor : function(){
		this.fIdAuthor++;
		return this.fIdAuthor;
	},
	
	
	xDispatchUpdate : function(pCdWsp, pUri, pEventType, pAuthor){
		if(this.fDebugComm) debug("debug.ServerCommunication:::xDispatchUpdate local:"+pUri+" - pEventType:::"+pEventType+" pAuthor:::"+pAuthor);
		var vItemsListener = this.fItemsListeners;
		while(vItemsListener) {
			try{vItemsListener.lstn.handleUriUpdate(this, pCdWsp, pUri, pEventType, pAuthor);}catch(e){debug("Listener items:"+e);}
			vItemsListener = vItemsListener.next;
		}
	},
	
	fClientId : "?",
	fWspsList : null,
	fWspsListStr : "",
	
	xSetReqHeaders : function(pReq){
		pReq.setRequestHeader("scClientId", this.fClientId);
		pReq.setRequestHeader("scWsps", this.fWspsListStr);
		//var vAuthorization = pReq.getRequestHeader("Authorization");
		//debug("vAuthorization ::::"+vAuthorization);
		//pReq.setRequestHeader("Authorization", "Basic xxxfffff");
	},
	
	xGetRespHeadersAsynch : function(pReq){
		var vClientId = pReq.getResponseHeader("scClientId");
		if(vClientId) {
			this.fClientId = vClientId;
			if(this.fWspsList) {
				var vTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
				vTimer.initWithCallback(new ServerHttpTreatRespHeader(this, pReq), 0, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
			}
		}
	},
	xGetRespHeaders : function(pReq){
		var vClientId = pReq.getResponseHeader("scClientId");
		if(vClientId) {
			this.fClientId = vClientId;
			this.xTreatRespHeaders(pReq);
		}
	},
	xTreatRespHeaders : function(pReq){
		if(this.fWspsList) {
			function checkWsp(pCdWsp) {
				var vEventType;
				function dispatchUri(pUri){
					this.xDispatchUpdate(pCdWsp, pCdWsp+pUri, vEventType, -1);
				}
				var vUptds = pReq.getResponseHeader("scUpdts_"+pCdWsp);
				var vRm = pReq.getResponseHeader("scRm_"+pCdWsp);
				var vSt = pReq.getResponseHeader("scSt_"+pCdWsp);
				if(this.fDebugComm) {
					if(vUptds) debug("debug.ServerCommunication:::scUpdts_"+pCdWsp+":::::"+vUptds+":::clientid="+this.fClientId);
					if(vRm) debug("debug.ServerCommunication:::scRm_"+pCdWsp+":::::"+vRm+":::clientid="+this.fClientId);
					if(vSt) debug("debug.ServerCommunication:::scSt_"+pCdWsp+":::::"+vSt+":::clientid="+this.fClientId);
				}
				if(vUptds) {
					vEventType = 1;
					vUptds.split(";").forEach(dispatchUri, this);
				}
				if(vRm) {
					vEventType = 2;
					vRm.split(";").forEach(dispatchUri, this);
				}
				if(vSt) {
					vEventType = 3;
					vSt.split(";").forEach(dispatchUri, this);
				}
			}
			this.fWspsList.forEach(checkWsp, this);
		}
	},
	
	xSetCallBacks : function(pReq, pFctCallBack, pFctCallBackError) {
		if(pFctCallBack!=null) pReq.onload = new CallbackWrapper(this, pFctCallBack);
		if(pFctCallBackError != null) {
			var vCbErr = pFctCallBackError;
			if(pFctCallBackError == pFctCallBack) pReq.onerror = pReq.onload;
			else pReq.onerror = new CallbackWrapper(this, pFctCallBackError);
		}
	},
	
	xBuildWspList : function(){	
		this.fWspsList = [];
		this.fWspsListStr = "";
		var vWspList = this.getWspServer().getWsps();
		var vLen = vWspList.Count();
		for(var i = 0; i < vLen; i++) {
			var vWsp = vWspList.GetElementAt(i).QueryInterface(Components.interfaces.scIWsp);
			if(vWsp.isActive()) this.fWspsList.push(vWsp.getCode());
		}
		this.fWspsListStr = this.fWspsList.join();
	},
	
	handleWspRegUpdated : function(pTypeEvent, pIdServer, pWsp) {
		try{
			if(pIdServer == this.getWspServer().getId()) this.xBuildWspList();
			return true;
		} catch (e){
			debug("scHttpDataServer > handleWspRegUpdated : " + e);
			return false;
		}
	},
	
	observe: function(pSubject, pTopic, pData){
		if(pTopic=="quit-application") this.quit();
	},

    QueryInterface : function(pIId) {
        if (!pIId.equals(Components.interfaces.nsISupports) &&
            !pIId.equals(HTTPDATAPROVIDER_IID) &&
            !pIId.equals(Components.interfaces.nsIObserver) &&
            !pIId.equals(Components.interfaces.scIWspRegListener))
            throw Components.results.NS_ERROR_NO_INTERFACE;
        return this;
    }
};



/* Dispatch asynchrone de l'event de modif d'une URI*/
function ServerHttpDispatchUpdt(pServer, pWspCd, pUri, pEventType, pAuthor){
	this.fServer = pServer;
	this.fWspCd = pWspCd;
	this.fUri = pUri;
	this.fEventType = pEventType;
	this.pAuthor = pAuthor;
}
ServerHttpDispatchUpdt.prototype = {
	notify : function(pTimer){
		this.fServer.xDispatchUpdate(this.fWspCd, this.fUri, this.fEventType, this.pAuthor);
	},

    QueryInterface: function(pIId) {
        if (!pIId.equals(Components.interfaces.nsISupports) &&
            !pIId.equals(Components.interfaces.nsITimerCallback))
            throw Components.results.NS_ERROR_NO_INTERFACE;
        return this;
    }
}

/* Traitement asynchrone d'un retour serveur. */
function ServerHttpTreatRespHeader(pServer, pRequest) {
	this.fServer = pServer;
	this.fRequest = pRequest;
}
ServerHttpTreatRespHeader.prototype = {
	notify : function(pTimer){
		this.fServer.xTreatRespHeaders(this.fRequest);
	},

    QueryInterface: function(pIId) {
        if (!pIId.equals(Components.interfaces.nsISupports) &&
            !pIId.equals(Components.interfaces.nsITimerCallback))
            throw Components.results.NS_ERROR_NO_INTERFACE;
        return this;
    }
}

/* Wrapper du callback pour traiter le header de la response. */
function CallbackWrapper(pDataProvider, pCb){
	this.fDataProvider = pDataProvider;
	this.fCb = pCb;
}
CallbackWrapper.prototype = {
	handleEvent : function(pEvent){
				try {
					this.fCb.handleEvent(pEvent);
				} catch(e){
					debug(e);
				}
				this.fDataProvider.xGetRespHeaders(pEvent.target);
	},
    QueryInterface: function(pIId) {
        if (!pIId.equals(Components.interfaces.nsISupports) &&
            !pIId.equals(Components.interfaces.nsIDOMEventListener))
            throw Components.results.NS_ERROR_NO_INTERFACE;
        return this;
    }
}

/* Ping régulièrement la JVM locale pour empêcher qu'elle s'arrette. */
function KeepAliveServer(pServer){
	this.fServer = pServer;
}
KeepAliveServer.prototype = {
	notify : function(pTimer){
		try{
			if(this.fServer.fIsOwnerServerLocal) {
				this.fServer.dialogAsynchWithService("/u/quitter?cdaction=KeepAlive", "GET", null, null, this, this);
			} else {
				this.fServer.dialogAsynchWithService("/u/ping", "GET", null, null, this, this);
			}
		} catch (e){
			debug("KeepAliveServer.notify : "+e);
		}
	},

	handleEvent : function(pEvent){
		//this.fServer.xGetRespHeaders(pEvent.target); Fait dans le CallbackWrapper.
	},
    QueryInterface: function(pIId) {
        if (!pIId.equals(Components.interfaces.nsISupports) &&
        	!pIId.equals(Components.interfaces.nsIDOMEventListener) &&
            !pIId.equals(Components.interfaces.nsITimerCallback))
            throw Components.results.NS_ERROR_NO_INTERFACE;
        return this;
    }
}




function debug(pText){
	var vConsoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
	vConsoleService.logStringMessage(pText);
}

function listProperties (pObj){
	var vRes = "";
	var vProp = null;
	for (vProp in pObj) {
		try {
			vRes += vProp +'(' + pObj[vProp]+ ')'+ "\n";
		} catch(e){
			vRes += vProp +' -> toString in error\n';
		}
	}
	return vRes;
}

/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info/
*
**/

var Base64 = {
    // private property
    _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
    // public method for encoding
    encode : function (input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;

        input = Base64._utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output +
            this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
            this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

        }

        return output;
    },

    // private method for UTF-8 encoding
    _utf8_encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    }
}

/* scHttpDataProvider Module (for XPCOM registration) */
var scHttpDataProviderModule = {
    registerSelf: function(compMgr, fileSpec, location, type) {
        compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
        compMgr.registerFactoryLocation(HTTPDATAPROVIDER_CID, 
                                        "scHttpDataProvider JS component", 
                                        HTTPDATAPROVIDER_CONTRACTID, 
                                        fileSpec, 
                                        location,
                                        type);
    },

    getClassObject: function(compMgr, cid, iid) {
        if (!cid.equals(HTTPDATAPROVIDER_CID))
            throw Components.results.NS_ERROR_NO_INTERFACE;

        if (!iid.equals(Components.interfaces.nsIFactory))
            throw Components.results.NS_ERROR_NOT_IMPLEMENTED;

        return scHttpDataProviderFactory;
    },

    canUnload: function(compMgr) { return true; }
};

/* scHttpDataProvider Class Factory */
var scHttpDataProviderFactory = {
    createInstance: function(outer, iid) {
        if (outer != null)
            throw Components.results.NS_ERROR_NO_AGGREGATION;
    
        if (!iid.equals(HTTPDATAPROVIDER_IID) &&
            !iid.equals(Components.interfaces.nsISupports))
            throw Components.results.NS_ERROR_INVALID_ARG;

        return new scHttpDataProvider();
    }
}

/* Module initialisation */
function NSGetModule(comMgr, fileSpec) { return scHttpDataProviderModule; }