/*
 * 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 HTTPDATASERVER_CONTRACTID = '@scenari.com/httpdataserver;1';
const HTTPDATASERVER_CID = Components.ID('{98C2A73F-E9A7-4EAA-94C7-4771E5C359EF}');
const HTTPDATASERVER_IID = Components.interfaces.scIDataServer;

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

/* 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. */
scHttpDataServer.prototype = {

	/**
	 *
	 */
	init : function(pUrlServer, pCdUniverse, pAccount, pPassword) {
		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);
	
		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.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.fConnectionStatus = "undefined";//[undefined|connected|unauthorized]
		
		this.fUser = {fAccount:pAccount, fPassword:pPassword};
		//debug("this.fUser :: "+listProperties(this.fUser));
		this.fUrlServerLocal = null;
		this.fIsOwnerServerLocal = false;
		
		// Propriétés du serveur local
		this.fIsServerLocal = (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.fIsServerLocal = 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.fIsServerLocal){
			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.fIsServerLocal) {
			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.fIsServerLocal && ! 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("scHttpDataServer.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);
				var vFile = vFolderService.get("ARes", Components.interfaces.nsIFile).parent.parent;//répertoire bin
				var vAppDirPath = vFile.path;
				var vOpts = [];
				var vIdxOpt = 0;
				
				getOS();
				
				if(gOS=="Win" || gOS=="UNIX" || gOS=="Mac"){ 
					var vSeparator = gOS=="Win" ? "\\" : "/";
					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";
					
					// Utilisé pour Mac car encore en jre 1.4
					var vJavaEndorsedPath 	= vAppDirPath + vSeparator + "scServer" + vSeparator + "jre" + vSeparator + "lib" + vSeparator + "endorsed";
					
					var vScConfPath 		= vAppDirPath + vSeparator + "scServer" + vSeparator + "conf";

					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("vFile:: "+vFile);

					vOpts[vIdxOpt++] = "-Duser.dir=" + vAppDirPath;
					vOpts[vIdxOpt++] = "-classpath";
					//vOpts[vIdxOpt++] = "";
					vOpts[vIdxOpt] = vScLibPath + vSeparator + "scenari_bdp.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_bdp_fs.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_client.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_co.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_ext.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_fw.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_ge.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_servletengine.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_ihmcms.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_xsldom.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_jing.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_updt.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_audio.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vScLibPath + vSeparator + "scenari_XPComs.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "ant.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "apacheFtp.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "beanshell.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "bsf.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "fileupload.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "jing.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "oro.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "piccolo.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "servlet.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "unofinder.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "webmacro.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "xerces.jar" + vClassPathSeparator;
					vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "xmlapi.jar" + vClassPathSeparator;
					if (gOS != "Mac"){ // Sous mac xalan.jar doit être dans le dossier endorced car encore en JRE 1.4
						vOpts[vIdxOpt] += vJavaLibPath + vSeparator + "xalan.jar" + vClassPathSeparator;
					}
					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";
						vOpts[vIdxOpt++] = "-Djava.endorsed.dirs="+vJavaEndorsedPath;
					}
					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 vWinWatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].getService(Components.interfaces.nsIWindowWatcher);
					var vActiveWindow = vWinWatch.activeWindow.alert("Des éléments de l'application sont manquants.\nVeuillez redémarrer votre ordinateur et réinstaller l'application.");
					throw {toString:function(){return "Fichier introuvable : '" + vFile.path + "'. Réinstaller l'application aprés un redémarrage de l'ordinateur."}};
				}
				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.fIsServerLocal = 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), 25000, Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
		
		this.fUrlService = this.fUrlServer+this.fPathService+"/"+this.fCdUnivers;
		this.fUrlAgent = this.fUrlServer+this.fPathAgent+"/"+this.fCdUnivers+"/";
		
		this.fItemsListeners = null;
	},
	
	isServerReady : function (){
		try{
			if(this.fConnectionStatus!="unauthorized"){
				var vReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
				var vUrl = this.fUrlServer+this.fPathService+"/"+this.fCdUnivers+"/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){
					this.fConnectionStatus = "connected";
					return true;
					}
				if(vReq.status == 401){
					this.fConnectionStatus = "unauthorized";
					return false;
				}
			}
		} catch(e){}
		return false;
	},
	isServerLocal : function (){
		return this.fIsServerLocal;
	},
	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.fUrlServer + this.fPathService + "/" + this.fCdUnivers + "/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 + 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;
	}, 
	
	getDomFromService : function (pUrlDialogAndParams) {
		if(this.fConnectionStatus!="unauthorized"){
			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);
			if(vReq.status != 401){
				this.fConnectionStatus = "connected";
				this.xGetRespHeadersAsynch(vReq);
				var vResp = vReq.responseXML;
				return vResp;
			}else{
				this.fConnectionStatus = "unauthorized";
				return null;
			}
		}else{// non autorisé. En attente d'un changement de login/password
			return null;
		}
	},

	getTextFromService : function (pUrlDialogAndParams) {
		if(this.fConnectionStatus!="unauthorized"){
			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);
			if(vReq.status != 401){
				this.fConnectionStatus = "connected";
				this.xGetRespHeadersAsynch(vReq);
				var vResp = vReq.responseText;
				return vResp;
			}else{
				this.fConnectionStatus = "unauthorized";
				return null;
			}
		}else{// non autorisé. En attente d'un changement de login/password
			return null;
		}
	},
	
	setUser : function(pAccount, pPassword){
		this.fUser = {fAccount:pAccount, fPassword:pPassword};
		this.fConnectionStatus = "undefined";
	},

	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(this.fConnectionStatus!="unauthorized"){
			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);
			}
			if(vReq && vReq.status != 401){
				this.fConnectionStatus = "connected";
				this.xGetRespHeadersAsynch(vReq);
				return vReq;
			}else{
				this.fConnectionStatus = "unauthorized";
				return vReq;
			}
		}else{// non autorisé. En attente d'un changement de login/password
			return new XMLHttpRequestWrapper("unauthorized", 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);
			if(this.fConnectionStatus!="unauthorized"){
				var vWReq = new XMLHttpRequestWrapper("checkRights", vReq, this);
				vWReq.send(null);
			}else{// non autorisé. En attente d'un changement de login/password
				if(pFctCallBackError) pFctCallBackError.handleEvent(new nsIDOMEventUnauthorized());
			}
		} catch(e){
			debug("scHttpDataServer.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);
			if(this.fConnectionStatus!="unauthorized"){
				var vWReq = new XMLHttpRequestWrapper("checkRights", vReq, this);
				vWReq.send(pBody);
			}else{// non autorisé. En attente d'un changement de login/password
				if(pFctCallBackError) pFctCallBackError.handleEvent(new nsIDOMEventUnauthorized());
			}
		} catch(e){
			debug("scHttpDataServer.dialogAsynchWithService "+pMethod+" - "+pUrlDialogAndParams+" : "+e);
			throw e;
		}
	},
	
	loadFromAgent : function (pIdInstance, pUrlDialogAndParams, pFctCallBack, pFctCallBackError) {
		try {
			//debug("loadFromAgent="+pUrlDialogAndParams);
			var vUrl = this.fUrlAgent + 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);
			if(this.fConnectionStatus!="unauthorized"){
				var vWReq = new XMLHttpRequestWrapper("checkRights", vReq, this);
				vWReq.send(null);
			}else{// non autorisé. En attente d'un changement de login/password
				if(pFctCallBackError) pFctCallBackError.handleEvent(new nsIDOMEventUnauthorized());
			}
		} catch(e){
			debug("scHttpDataServer.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:"+pCdWsp+" - "+pUri+" - pEventType:::"+pEventType+" pAuthor:::"+pAuthor+" this:::"+this+" this.fItemsListeners:::"+this.fItemsListeners);
		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);
	},
	
	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);
				if(vUptds) {
					vEventType = 1;
					vUptds.split(",").forEach(dispatchUri, this);
				}
				var vRm = pReq.getResponseHeader("scRm_"+pCdWsp);
				if(vRm) {
					vEventType = 2;
					vRm.split(",").forEach(dispatchUri, this);
				}
				var vSt = pReq.getResponseHeader("scSt_"+pCdWsp);
				if(vSt) {
					vEventType = 3;
					vSt.split(",").forEach(dispatchUri, this);
				}
				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);
				}
			}
			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.fWspReg.getServerWsps(this.fUrlServer);
		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, pUrlServer, pWsp) {
		if(pUrlServer == this.fUrlServer) this.xBuildWspList();
	},
	
	observe: function(pSubject, pTopic, pData){
		if(pTopic=="quit-application") this.quit();
	},

    QueryInterface : function(pIId) {
        if (!pIId.equals(Components.interfaces.nsISupports) &&
            !pIId.equals(HTTPDATASERVER_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 de XMLHttpRequest */
function nsIDOMEventUnauthorized(){
	
}
nsIDOMEventUnauthorized.prototype = {
 	/** nsIRequest **/
	get target() {
		return new XMLHttpRequestWrapper("unauthorized");
	},
	
    QueryInterface: function(pIId) {
        if (!pIId.equals(Components.interfaces.nsISupports) &&
            !pIId.equals(Components.interfaces.nsIDOMEvent))
            throw Components.results.NS_ERROR_NO_INTERFACE;
        return this;
    }
}

/* Wrapper de XMLHttpRequest */
function XMLHttpRequestWrapper(pMode, pXMLHttpRequest, pHttpDataServer){
	this.fMode = pMode;// [null|unauthorized|checkRights]
	this.fXMLHttpRequest = pXMLHttpRequest ? pXMLHttpRequest : Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);;
	this.fServer = pHttpDataServer;
	try{
		if(pMode=="checkRights"){
			var vXmlHttpRequest = this;
			this.fXMLHttpRequest.addEventListener(
					"load", 
					function(pEvent){
						//debug("load!!!"+pEvent.target.status);
						switch(pEvent.target.status) {
							case 401 : vXmlHttpRequest.fServer.fConnectionStatus = "unauthorized"; break;
							case 200 : vXmlHttpRequest.fServer.fConnectionStatus = "connected"; break;
							default : vXmlHttpRequest.fServer.fConnectionStatus = "undefined";
						}
					}, 
					false);
			this.fXMLHttpRequest.addEventListener(
						"error", 
						function(pEvent){
							//debug("error!!!"+pEvent.type);
							if(pEvent && pEvent.type!="error"  && pEvent.target && pEvent.target.status==401) vXmlHttpRequest.fServer.fConnectionStatus = "unauthorized";
						}, 
						false);
		}
		
		if(pMode=="unauthorized"){
			/*
			debug("non autorisé::::");
			var vDocument = Components.classes["@mozilla.org/xml/xml-document;1"].createInstance(Components.interfaces.nsIDOMDocumentEvent);
			var vEvent = vDocument.createEvent('Events');
			vEvent.initEvent("error", false, true);			
			this.fXMLHttpRequest.abort();
			this.fXMLHttpRequest.QueryInterface(Components.interfaces.nsIDOMEventTarget).dispatchEvent(vEvent);// anp TODO. marche pas...
			//debug("eeeeeeeee"+this.fXMLHttpRequest.onerror);
			*/
		}
	}catch(e){
		debug("scHttpDataServer.XMLHttpRequestWrapper : " + e);
	}
	
}
XMLHttpRequestWrapper.prototype = {
 	/** nsIRequest **/
	get channel() {return this.fXMLHttpRequest.channel;},
	get multipart() {return this.fXMLHttpRequest.multipart;},
	set multipart(value) {this.fXMLHttpRequest.multipart = value;},
	get readyState() {return this.fXMLHttpRequest.readyState;},
	get responseText() {return this.fXMLHttpRequest.responseText;},
	get responseXML() {return this.fXMLHttpRequest.responseXML;},
	get status() {return this.fMode!="unauthorized" ? this.fXMLHttpRequest.status : 401},
	get statusText() {return this.fMode!="unauthorized" ? this.fXMLHttpRequest.statusText : "Vous ne disposez pas des droits suffisants";},
	abort  					: function(){this.fXMLHttpRequest.abort();},
	getAllResponseHeaders  	: function(){return this.fXMLHttpRequest.getAllResponseHeaders();},
	getResponseHeader  		: function(pHeader){return this.fXMLHttpRequest.getResponseHeader(pHeader);},
	open  					: function(pMethod, pUrl){this.fXMLHttpRequest.open(pMethod, pUrl);},
	overrideMimeType  		: function(pMime){this.fXMLHttpRequest.overrideMimeType(pMime);},
	send   					: function(pBody){this.fXMLHttpRequest.send(pBody);},
	setRequestHeader  		: function(pHeader, pValue){this.fXMLHttpRequest.setRequestHeader(pHeader, pValue);},
	onload					: function(pEvent){return this.fXMLHttpRequest.onload(pEvent);},
	onerror					: function(pEvent){return this.fXMLHttpRequest.onerror(pEvent);},
	
	/** nsIDOMEventTarget **/
	addEventListener 		: function(pType, pListener, pUseCapture){this.fXMLHttpRequest.addEventListener(pType, pListener, pUseCapture);},
	dispatchEvent 	 		: function(pEvent){return this.fXMLHttpRequest.dispatchEvent(pEvent);},
	removeEventListener		: function(pType, pListener, pUseCapture){this.fXMLHttpRequest.removeEventListener(pType, pListener, pUseCapture);},
    QueryInterface: function(pIId) {
        if (!pIId.equals(Components.interfaces.nsISupports) &&
        	!pIId.equals(Components.interfaces. nsIDOMEventTarget) &&
            !pIId.equals(Components.interfaces.nsIXMLHttpRequest))
            throw Components.results.NS_ERROR_NO_INTERFACE;
        return this;
    }
}

/* Wrapper du callback pour traiter le header de la response. */
function CallbackWrapper(pDataServer, pCb){
	this.fDataServer = pDataServer;
	this.fCb = pCb;
}
CallbackWrapper.prototype = {
	handleEvent : function(pEvent){
				try {
					this.fCb.handleEvent(pEvent);
				} catch(e){
					debug(e);
				}
				this.fDataServer.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);
	},
    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;
}




/* scHttpDataServer Module (for XPCOM registration) */
var scHttpDataServerModule = {
    registerSelf: function(compMgr, fileSpec, location, type) {
        compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
        compMgr.registerFactoryLocation(HTTPDATASERVER_CID, 
                                        "scHttpDataServer JS component", 
                                        HTTPDATASERVER_CONTRACTID, 
                                        fileSpec, 
                                        location,
                                        type);
    },

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

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

        return scHttpDataServerFactory;
    },

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

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

        return new scHttpDataServer();
    }
}

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