/*
 * Copyright (c) OutWit Technologies 2007-2017.
 * All rights reserved.
 */

/*
 * @fileOverview The Firefox overlay
 * @author dmp, vn, pr
 * XXX document
 */


/*
 * Firstly load our utilities functions to manipulate outfits
 * list.
 */

var outwitOverlay_modules = new (function() {

  const kOW_DEBUGMODE = false;

  var tmp = {};
	Components.utils.import("chrome://outwit-kernel/content/ow-moz/appUtils.jsm", tmp);
	Components.utils.import("chrome://outwit-kernel/content/ow-moz/appManager.jsm", tmp);

  var appUtils = tmp.appUtils;
  var appManager = tmp.appManager;

  var gVersionChecker = Components.classes["@mozilla.org/xpcom/version-comparator;1"]
                                  .getService(Components.interfaces.nsIVersionComparator);

  var bundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
                                .getService()
                                .QueryInterface(Components.interfaces.nsIStringBundleService);
  var appUpdateLocales = bundleService.createBundle("chrome://outwit-kernel/locale/appUpdate.properties");
  var urlLocales = bundleService.createBundle("chrome://outwit-kernel/locale/urls.properties");
  var overlayLocales = bundleService.createBundle("chrome://outwit-kernel/locale/overlay.properties");


  var prefs = Components.classes["@mozilla.org/preferences-service;1"]
                        .getService(Components.interfaces.nsIPrefService)
                        .getBranch("extensions.outwit.")
                        .QueryInterface(Components.interfaces.nsIPrefBranch2);

  var modulesPref = Components.classes["@mozilla.org/preferences-service;1"]
                              .getService(Components.interfaces.nsIPrefService)
                              .getBranch("extensions.outwit.modules.")
                              .QueryInterface(Components.interfaces.nsIPrefBranch2);

	function getRealId(anId) {
		return anId + "-1305";
	}

	function getElementByRealId(anId) {
		return document.getElementById(getRealId(anId));
	}

	window.dump("[OW] OVERLAY LOADED\n");

  function getInstalledModule(aModuleId, aCallback) {
    appUtils.getKernel(function(kernel) {
      if (kernel && !kernel.userDisabled && !kernel.appDisabled) {
        if (!aModuleId) {
          aCallback(kernel);
          return;
        }
        else if (kernel.modules && kernel.modules[aModuleId]) {
          var isInstalled = false;
          try { isInstalled = modulesPref.getBoolPref(aModuleId + ".installed"); } catch(e) {}
          if (kOW_DEBUGMODE || isInstalled) {
            var module = kernel.modules[aModuleId];
            aCallback({
              moduleId: aModuleId,
              id: kernel.id,
              chromeId: module.chromeId,
              name: module.name,
              version: module.version,
              iconURL: module.iconURL
            });
            return;
          }
        }
      }
      aCallback(null);
    });
  }

  function getInstalledModules(aCallback) {
		appUtils.getKernel(function(kernel) {
      var resultArray = [];
      var nameDedup = {};
      if (kernel.modules) {
        Object.keys(kernel.modules).forEach(function(moduleId) {
          // XXX temporary, prevents running hub
          /*
          if (moduleId != "sourcer") {
            modulesPref.setBoolPref(moduleId + ".distInstall", false);
            modulesPref.setBoolPref(moduleId + ".installed", false);
          }
          */
          modulesPref.clearUserPref(moduleId + ".distInstall");

          var isDistInstalled = false;
          try { isDistInstalled = modulesPref.getBoolPref(moduleId + ".distInstall"); } catch(e) {}
          if (isDistInstalled) modulesPref.setBoolPref(moduleId + ".installed", true);

          var isInstalled = false;
          try { isInstalled = modulesPref.getBoolPref(moduleId + ".installed"); } catch(e) {}
          if (kOW_DEBUGMODE || isInstalled) {
            var module = kernel.modules[moduleId];
            nameDedup[module.name] = nameDedup[module.name] ? ++nameDedup[module.name] : 1;
            resultArray.push({
              moduleId: moduleId,
              id: kernel.id,
              chromeId: module.chromeId,
              name: module.name,
              version: module.version,
              iconURL: module.iconURL
            });
          }
        });
      }

      resultArray.forEach(function(item) {
        if (nameDedup[item.name] > 1) {
          item.name = item.name + " " + item.version;
        }
      });

      aCallback(resultArray);
    });
  }


  //========================================================
  // FIREFOX UI (TOOLBAR, MENU)
  //========================================================

	/**
	 * XXX to be cleaned, merge toolbar and menu filling
	 * Fills "Tools" > "OutWit" menu (outfit list)
	 */
	function fillToolsMenu(modules) {
    try {
      var insertionPoint = getElementByRealId('noOutfit');
      modules.forEach(function(item) {
        let menuitem = document.createElement('menuitem');
        menuitem.setAttribute('image', item.iconURL);
        menuitem.setAttribute('class', "menuitem-iconic");
        menuitem.setAttribute('label', item.name);
        menuitem.addEventListener('command', function() {
          appUtils.loadModule(item.moduleId, false, gBrowser.currentURI, null, window);
        }, false);
        insertionPoint.parentNode.insertBefore(menuitem, insertionPoint);
      });

      if (modules.length) {
        insertionPoint.setAttribute("hidden", "true");
      }
    }
    catch(e) {
      e.message = "Error filling OutWit tools menu: " + e.message;
      Components.utils.reportError(e);
    }
	}


	function installToolbarButton(forceInstall) {
		dump("[OW] Installing outwit button\n");
		try {
      Components.utils.import("resource:///modules/CustomizableUI.jsm");

      let node = document.createElement("toolbarbutton");
      node.setAttribute("id", getRealId("ow-button-navigator"));
      node.setAttribute("type", "menu-button");
      node.classList.add("ow-button-navigator");
      node.setAttribute("label", overlayLocales.GetStringFromName("outwitKernel.menuLabel"));

      let popup = document.createElement("menupopup");
      popup.setAttribute("id", getRealId("ow-menu-navigator"));
      node.appendChild(popup);

      let toolbox = document.getElementById("navigator-toolbox");
      let palette = toolbox.palette;
      palette.appendChild(node);

      let placement = window.CustomizableUI.getPlacementOfWidget(node.id);
      if (!placement && forceInstall) {
        placement = { area: 'nav-bar', position: 0 };
      }
      CustomizableUI.addWidgetToArea(node.id, placement.area, placement.position);
      CustomizableUI.ensureWidgetPlacedInWindow(node.id, window);
		}
		catch(e) {
      e.message = "Error installing OutWit toolbar button: " + e.message;
      Components.utils.reportError(e);
    }
	}


	function fillToolbarButtonMenu(modules) {
    try {
      dump(" [OW] Populating button menu " + modules.length + "\n");
  
      if (modules.length == 1) {
        var insertionPoint = getElementByRealId("ow-button-navigator");
        insertionPoint.setAttribute("type", "");
        var item = modules[0];
        insertionPoint.setAttribute('label', item.name);
        insertionPoint.addEventListener('command', function() {
          appUtils.loadModule(item.moduleId, false, gBrowser.currentURI, null, window);
        }, false);
      }
      else {
        var insertionPoint = getElementByRealId("ow-menu-navigator");
        while (insertionPoint.hasChildNodes()) {
          insertionPoint.removeChild(insertionPoint.lastChild);
        }

        modules.forEach(function(item) {
          // Populate menu entries
          let menuitem = document.createElement('menuitem');
          menuitem.setAttribute('class', "menuitem-iconic");
          menuitem.setAttribute('image', item.iconURL);
          menuitem.setAttribute('label', item.name);
          menuitem.addEventListener('command', function() {
            appUtils.loadModule(item.moduleId, false, gBrowser.currentURI, null, window);
          }, false);
          insertionPoint.appendChild(menuitem);
        });
      }
    }
    catch(e) {
      e.message = "Error filling OutWit toolbar button menu: " + e.message;
      Components.utils.reportError(e);
    }
	}


	/**
	 * add the button automaticaly to the toolbar
	 * XXX to be cleaned, merge toolbar and menu filling
	 */
	function initToolbar(modules) {
		try {
			var toolbox = document.getElementById("navigator-toolbox");
		
			var hasOutwitButton = false;
			var hasAnotherOutwitButton = false;
			var firstLoad = true;
			var prefName = getRealId("firstload");
			if (prefs.prefHasUserValue(prefName))
				firstLoad = prefs.getBoolPref(prefName);
			else
				prefs.setBoolPref(prefName, false);
		

      // XXX This is necessary on MacOS, or the first load will tak more than one minute
			if (firstLoad) {
				var profD = Components.classes["@mozilla.org/file/directory_service;1"]
                                 .getService(Components.interfaces.nsIProperties)
                                 .get("ProfD", Components.interfaces.nsIFile);
				var userGear = profD.clone();
				userGear.append("User_Gear.owg");

				var userGearBackup = profD.clone();
				userGearBackup.append("User_Gear.backup.owg");
				userGearBackup.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, parseInt("0750", 8));

				if (userGear.exists()) {
					userGear.copyTo(profD, userGearBackup.leafName);
				}
			}


			for ( var i = 0; i < toolbox.childNodes.length; ++i) {
				var toolbar = toolbox.childNodes[i];
		
				if (toolbar.localName == "toolbar" && toolbar.getAttribute("customizable") == "true") {
					if (toolbar.currentSet.indexOf(getRealId("ow-button-navigator")) != -1) {
						hasOutwitButton = true;
					}
					else if (toolbar.currentSet.indexOf("ow-button-navigator") != -1) {
						hasAnotherOutwitButton = true;
					}
				}
			}
		
			dump("[OW] outwit overlay init: isFirstLoad? " + firstLoad + ", has outwit button? " + hasOutwitButton + ", has another outwit button? " + hasAnotherOutwitButton + "\n");
			if (!hasOutwitButton && (firstLoad || hasAnotherOutwitButton || prefs.prefHasUserValue("firstload"))) // bad guy
			{
				prefs.clearUserPref("firstload");
				installToolbarButton(true);
				hasOutwitButton = true;
			}
      else {
        installToolbarButton(false);
      }
		
			dump("[OW] outwit button installed: isFirstLoad? " + firstLoad + ", has outwit button? " + hasOutwitButton + "\n");
		
      fillToolbarButtonMenu(modules);
		}
    catch(e) {
      e.message = "Error initializing OutWit toolbar button: " + e.message;
      Components.utils.reportError(e);
    }
	};


	function initOutwitAutoloader() {
		gBrowser.addEventListener("DOMContentLoaded", function(event) {
			try {
				var doc = event.target;
				if (doc.contentType.indexOf("html") != -1) {
          var wizard = doc.querySelector(".owui-wizard");
          if (wizard) {
            var outfitId, moduleId;
            var fullId = wizard.getAttribute("data-outfitid");
            if (fullId) {
              [outfitId, moduleId] = fullId.split(".");
            }
            else {
              outfitId = wizard.getAttribute("data-outfit");
              if (outfitId == "sourcer" || outfitId == "hub") {
                moduleId = outfitId;
                outfitId = "modules";
              }
            }
            if (outfitId) {
              getInstalledModule(moduleId, function(module) {
                if (module && gVersionChecker.compare(wizard.getAttribute("data-kernelVersion"), module.kernelMaxVersion) <= 0) {
                  appUtils.loadModule(moduleId, false, doc.location.href, null, window);
                }
              });
            }
          }
				}
			}
			catch(e) {
        Components.utils.reportError(e);
			}
		}, true);
	};


	/**
	 * Opens tabs for installed/updated outfits
	 */
	function openUpdateTabs() {
		dump("[OW] openTabs: Opening firstRun and whatsnew tabs\n");
		appUtils.getOutfits(function(outfits) {
			try {
				var childArray = [];

				var _loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
																.getService(Components.interfaces.mozIJSSubScriptLoader);

				var tempScope = { coreKit: {} };
				_loader.loadSubScript("chrome://outwit-kernel/content/kernel/coreKit/presetsFileService.js", tempScope);

				var presets = tempScope.coreKit.presetsFileService;
				presets.read();


				/* Oki doki, we got the child, got the outfit now */  
        //  outfits.push(appUtils.getKernel());

				var installedOutfits = [];
				var updatedOutfits = [];
				var firstRunURLs = [];

				// searching for installed / updated outfits
				for (var i = 0, outfit, URL, outfitDid, outfitDd; i < outfits.length; ++i) {
					outfitDid = outfitDd = null;
					outfit = outfits[i];

          // XXX sourcer
          var outfitRegID = outfit.chromeId.replace(/^outwit-/, "").replace("modules", "sourcer");

          var firstRunURL;
          try {
            firstRunURL = urlLocales.GetStringFromName(outfitRegID + ".newInstall.URL");
          }
          catch(e) {
            firstRunURL = urlLocales.GetStringFromName("general.newInstall.URL");
          }

					URL = firstRunURL + "?id=" + outfit.id + "&version=" + outfit.version;
					dump("[OW] openTabs: " + outfit.id + " " + prefs.prefHasUserValue("updateURL." + outfit.id) + " " + URL + "\n");
					if (prefs.prefHasUserValue("updateURL." + outfit.id)) {
						// the pref exists, it may be an update
						// I don't really know why this uses the first run URL... we could simply
						// store the version (or use the extension manager that do knows updated
						// extension)
						if (prefs.getCharPref("updateURL." + outfit.id) != URL) {
							// it is an update
							updatedOutfits.push(outfit);
							prefs.setCharPref("updateURL." + outfit.id, URL);
						}
					}
					else {
						// pref does not exists: new install
						installedOutfits.push(outfit);
						prefs.setCharPref("updateURL." + outfit.id, URL);
					}


					// put cookie stuff in presets
					var cookieMgr = Components.classes["@mozilla.org/cookiemanager;1"].getService(Components.interfaces.nsICookieManager2);
					var cookies = cookieMgr.getCookiesFromHost("www.outwit.com");
					while (cookies.hasMoreElements() && !(outfitDid && outfitDd)) {
						var cookie = cookies.getNext().QueryInterface(Components.interfaces.nsICookie);
						if (cookie.name == outfitRegID + "_did") {
							outfitDid = cookie.value;
						}
						else if (cookie.name == outfitRegID + "_fud") {
							outfitDd = cookie.value;
						}
					}
					
					//window.dump(">>>>>>>>>>>>>>>>> " + outfitDid + " " + outfitDd + "\n");
					if (outfitDid) {
						var lightReg = presets.getRegistration(outfitRegID, 1);
						if (!lightReg) {
							presets.setRegistration(outfitRegID, 1, {did: outfitDid});
						}
						else if (!lightReg.did) {
							lightReg.did = outfitDid;
							presets.setRegistration(outfitRegID, 1, lightReg);
						}
						presets.write();
					}
				}


				setTimeout(function() {
					try {
						var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
																	 .getInterface(Components.interfaces.nsIWebNavigation)
																	 .QueryInterface(Components.interfaces.nsIDocShellTreeItem).rootTreeItem
																	 .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
																	 .getInterface(Components.interfaces.nsIDOMWindow);

						dump("[OW] openTabs: now, do it. Installed: " + installedOutfits.length + ", updated: " + updatedOutfits.length + "\n");

						// reset the pref here to make the menu open
						if (updatedOutfits.length || installedOutfits.length) {
							var prefBranch  = prefService.getBranch("extensions.outwit.");
							prefBranch.setCharPref("lastUsedOutfit", "");
							prefBranch.setCharPref("lastUsedOutfitTitle", "");
						}
						
						if (installedOutfits.length) {
							// open firstRun URLs
							for (var i = 0, outfit, tab; i < installedOutfits.length; ++i) {
								tab = null;
								outfit = installedOutfits[i];
                // XXX sourcer
  				// XXXXX REG LEVELS
				// XXXXXXXXXX REGISTRATIONS TO BE CORRECTED
                var outfitRegID = outfit.chromeId.replace(/^outwit-/, "").replace("modules", "sourcer");
								try {
									for (var j = 0; j < mainWindow.gBrowser.tabs.length; ++j) {
										var brow = mainWindow.gBrowser.getBrowserForTab(mainWindow.gBrowser.tabs[j]);
										//window.dump("ZZZZZZZZZ " + new RegExp("https?://www.outwit.com/products/"+dir+"/license.php") + " " + brow.currentURI.spec + " " + new RegExp("https?://www.outwit.com/products/"+dir+"/license.php").test(brow.currentURI.spec) + "\n");
										if (new RegExp("https?://www.outwit.com/products/"+outfitRegID+"/(newInstall|firstRun|license)(\\.php)?.*").test(brow.currentURI.spec)) {
											tab = mainWindow.gBrowser.tabs[j];
											break;
										}
									}
								} catch(e) {}
								if (!tab) {
									tab = mainWindow.gBrowser.addTab("");
								}

								var pro = "";
								var registration = presets.getRegistration(outfitRegID, 5);
								if (registration && registration.key) {
									 pro = "pro";
									if (registration.expired) {
										pro = "-expired";
									}
								}
								else {
									pro = "light";
								}

								mainWindow.gBrowser
													.getBrowserForTab(tab)
													.loadURI(firstRunURL + "?id=" + outfit.id + "&version=" + outfit.version + "&registration="+pro);
								if (i == installedOutfits.length - 1) {
									mainWindow.gBrowser.selectedTab = tab;
								}
							}
						}

            /*
						if (updatedOutfits.length) {

							// build and open whatsnew URL
							var whatsNewURL = urlLocales.GetStringFromName("whatsNewURL");
							whatsNewURL += "?";

							for (var i = 0, outfit; i < updatedOutfits.length; ++i) {
								outfit = updatedOutfits[i];
								whatsNewURL += "id[" + outfit.id + "][" + outfit.version + "]=";
								var registration = presets.getRegistration(outfit.chromeId, 5);
								if (registration && registration.key) {
									whatsNewURL += "pro";
									if (registration.expired) {
										whatsNewURL += "-expired";
									}
								}
								else {
									whatsNewURL += "light";
								}
								if (i < updatedOutfits.length - 1) {
									whatsNewURL += "&";
								}
							}
							var tab = mainWindow.gBrowser.addTab("");
							mainWindow.gBrowser
												.getBrowserForTab(tab)
												.loadURI(whatsNewURL);

							mainWindow.gBrowser.selectedTab = tab;
						}
            */
					}
					catch(e) {
						dump("[OW] openTabs error (in timer) : " + e + "\n");
					}
				}, 200);
			}
			catch(e) {
				dump("[OW] openTabs global error : " + e + "\n" + e.stack);
			}
		}, true);
	};

  var self = this;

  //========================================================
  // UPDATE
  //========================================================

	/**
	 * Update status manager. Synchronizes different update systems and
	 * prevent multiple checks at the same time.
	 */
	self.updateStatus = {
		updating: false,
		toUpdateEM: -1,
		toUpdateOW: -1,
		manualUpdate: false,

		init: function(manualUpdate) {
			this.manualUpdate = Boolean(manualUpdate);
			window.dump("[OW] Update status init " + this.updating + "\n");
			if (this.updating) return false;
			this.updating = true;
			this.toUpdateEM = -1;
			this.toUpdateOW = -1;
			return true;
		},

		end: function(dontOpenEMForInstall) {
			window.dump("[OW] Update status END " + this.toUpdateOW + " " + this.toUpdateEM + " " + dontOpenEMForInstall + "\n");
			this.updating = false;
			if (this.toUpdateOW <= 0 && this.toUpdateEM <= 0) {
				if (this.manualUpdate) {
					alert(appUpdateLocales.GetStringFromName("noUpdateText"));
				}
			}
			else if (this.toUpdateEM > 0 || (this.toUpdateOW > 0 && !dontOpenEMForInstall)) {
				appUtils.openAddonsWindow((this.toUpdateEM > 0), (this.toUpdateOW > 0));
			}
		},

		updateOWEnded: function(count, dontOpenEM) {
			window.dump("[OW] Update status updateOWEnded " + count + " " + dontOpenEM + "\n");
			this.toUpdateOW = count;
			if (this.toUpdateEM != -1) {
				this.end(dontOpenEM);
			}
		},

		updateEMEnded: function(count) {
			window.dump("[OW] Update status updateEMEnded " + count + "\n");
			this.toUpdateEM = count;
			if (this.toUpdateOW != -1) {
				this.end();
			}
		}
	};


	/**
	 * Shows the update dialog
	 * 
	 * @name self.showUpdateDialog
	 * @param {outfit[]} updateList a list of outfits to update
	 * @param {Boolean} compat true if "compatibility" mode (different to simple update mode for messages text)
	 * @param {Boolean} OWonly true if an update is found only on outwit.com, should be only for compat
	 * @param {Boolean} AMOonly true if an update is found only on AMO, should be only for compat
	 */
	self.showUpdateDialog = function self_showUpdateDialog(updateList, compat, OWonly, AMOonly) {
		function getLocale(aName) {
			try {
				return appUpdateLocales.GetStringFromName(aName);
			}
			catch(e) {
				return "";
			}
		}

		var data = {outfits: updateList, OWOnly: OWonly, AMOOnly: AMOonly};
		if (compat) {
			data.title = getLocale("compatUpdateTitle");
			data.header = getLocale("compatUpdateHeader");
			data.mainMessage = getLocale("compatUpdateTopText");
			data.referer = "application-update-compat";
		}
		else {
			data.referer = "application-update-manual";
		}
		window.openDialog("chrome://outwit-kernel/content/appUpdate/dialog.xul", "OWUpdateDialog", "chrome,centerscreen,dialog,modal", data);
	};


	/**
	 * Check for updates for some outfits, and update them
	 * 
	 * @name self.updateOutfits
	 * @param {outfit[]} toUpdate a list of outfits to update
	 * @param {Boolean} compat true if "compatibility" mode (different to simple update mode for messages text)
	 * @param {Boolean} manualUpdate true if called manually (just show an alert if no updates found)
	 */
	self.updateOutfits = function self_updateOutfits(toUpdate, compat, manualUpdate) {
		window.dump("[OW] Updating " + toUpdate.length + " outfits (" + (compat ? "compat" : "update") + ")\n");
		var gApp = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULAppInfo).QueryInterface(Components.interfaces.nsIXULRuntime);

		var localeSvc = Components.classes["@mozilla.org/intl/nslocaleservice;1"].getService(Components.interfaces.nsILocaleService);
		var gLocale = localeSvc.getLocaleComponentForUserAgent();

		function getAMOReq(outfit) {
			return "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=2&id=" + appUtils.packagesMap[outfit.id].packid + "&version=" + outfit.version + "&maxAppVersion="
				+ gApp.version + "&status=userEnabled&appID=" + gApp.ID + "&appVersion=" + gApp.version + "&appOS=" + gApp.OS + "&appABI=" + gApp.XPCOMABI + "&locale=" + gLocale
				+ "&currentAppVersion=" + gApp.version + "&updateType=97";
		}

		var AMOAddonPage = "https://addons.mozilla.org/en-US/firefox/addon/";


		var updatesFound = [];
	 
		var OWonly = false;
		var AMOonly = false;
		
		function checkNextAMO() {
			if (!toUpdate.length) {
				window.dump("[OW]     Update check for " + updatesFound.length + " outfits " + OWonly + "\n");

				if (!OWonly) {
					OWonly = true;
					for (var i = 0; i < updatesFound.length; ++i) {
						if (updatesFound[i].AMOVersion) {
							OWonly = false;
						}
					}
				}

				window.dump("[OW]     Will update from " + (OWonly ? "only OW" : (AMOonly ? "only AMO" : "both OW and AMO")) + "\n");

				if (updatesFound.length) {
					self.showUpdateDialog(updatesFound, compat, OWonly, AMOonly);
				}
				else {
					self.updateStatus.updateOWEnded(0);
				}
				return;
			}
			var outfit = toUpdate.pop();

			window.dump("[OW]     Updating " + outfit.id + " " + OWonly + " " + toUpdate.length + " " + (!outfit.updateURL) + " -" + outfit.updateURL + "- " + "\n");

			if (typeof(appUtils.packagesMap[outfit.id]) != "undefined") {
				if (!OWonly && !outfit.updateURL) {
					// getting update from AMO
					var xhr = new XMLHttpRequest();
					xhr.open("GET", getAMOReq(outfit), true);

					window.dump("[OW]          Checking " + getAMOReq(outfit) + "\n");
					xhr.onload = function() {
						try {
							if (xhr.responseText) {
								var newerVersion = appUtils.getNewVersionFromUpdateRDF(xhr.channel.URI, xhr.responseText, appUtils.packagesMap[outfit.id].packid, outfit.version);
								window.dump("[OW]            Checked " + xhr.responseText.length + " " + newerVersion + "\n");
								if (newerVersion && gVersionChecker.compare(outfit.version, newVersion) > 0) {
									outfit.AMOVersion = newerVersion;
									updatesFound.push(outfit);
								}
								else if (compat) {
									OWonly = true;
									outfit.OWVersion = "";
									updatesFound.push(outfit);
								}
							}
						}
						catch(e) {
							window.dump("[OW]     Error updating " + outfit.id + " " + e + "\n");
						}
						finally {
							checkNextAMO();
						}
					};

					xhr.onerror = function() {
						checkNextAMO();
					}

					xhr.send(null);

				}
				else {
					OWonly = true;
					outfit.OWVersion = ""
					updatesFound.push(outfit);
					checkNextAMO();
				}
			}
		}

		checkNextAMO();
	};


	/**
	 * Check for compatibility between kernel and outfits, and update if necessary.
	 * 
	 * @name self.checkVersionCompatibility
	 */
	self.checkVersionCompatibility = function self_checkVersionCompatibility() {
		window.dump("[OW] Checking version compatibility\n");
    appManager.removeOldAddons();
		return true;
	};


	/**
	 * Check for update and run update if necessary.
	 * 
	 * @name self.checkVersionCompatibility
	 * @param {Boolean} manualUpdate Manual update (just show an alert if no updates found)
	 */
	self.checkVersionUpdates = function self_checkVersionUpdates(manualUpdate) {
		window.dump("[OW] Checking version updates (" + (manualUpdate ? "manual" : "auto") + ")\n");

		if (!self.updateStatus.init(manualUpdate)) return false;

		var Cc = Components.classes;
		var Ci = Components.interfaces;
		//var gEM = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager);

		var toUpdate = [];
		var toUpdateWithEM = [];

		appUtils.getKernel(function(kernel) {

			if (kernel.updateURL) {
				if (manualUpdate) {
					toUpdateWithEM.push(kernel);
				}
			}

			appUtils.getOutfits(function(outfits) {

				for (var i = 0; i < outfits.length; ++i) {
		window.dump("[OW]     " + outfits[i].id + " (URL: " + outfits[i].updateURL + ", pack: " + appUtils.packagesMap[outfits[i].id] + ")\n");
					if (outfits[i].updateURL) {
						if (manualUpdate) {
							//var updateItem = gEM.getItemForID(outfits[i].id);
							//if (updateItem) {
								toUpdateWithEM.push(outfits[i]);
							//}
						}
					}
					else if (appUtils.packagesMap[outfits[i].id]) {
						toUpdate.push(outfits[i]);
					}
				}

				if (toUpdate.length) {
					self.updateOutfits(toUpdate, false, manualUpdate);
				}
				else {
					self.updateStatus.updateOWEnded(0);
				}

				if (toUpdateWithEM.length) {
					appUtils.updateOutfitsWithFirefox(toUpdateWithEM, function(count) {
						self.updateStatus.updateEMEnded(count);
					});
				}
				else {
					self.updateStatus.updateEMEnded(0);
				}
			}, true);
		});
		return true;
	};

	self.updateOutfitsWithFirefox = function(outfits, endCallback) {
		appUtils.updateOutfitsWithFirefox(outfits, endCallback);
	};

	/**
	 * Calls on Firefox window load. Fills outwit menu and toolbar.
	 * 
	 * @name self.onWindowLoad
	 */
	self.onWindowLoad = function self_onWindowLoad() {
		try {

      // Handling old toolbar menu items
			var toolsPopup = document.getElementById("menu_ToolsPopup");
			for (var i = toolsPopup.childNodes.length -1, node; i >= 0; --i) {
				node = toolsPopup.childNodes[i];
				if (/^outwitKernelMenuItem/.test(node.id)) {
					dump(" [OW] menu item found: " + node.id + " " + node.id.split("-")[1] + " " + parseInt(node.id.split("-")[1]) + "\n");
					var menuVersion = parseInt(node.id.split("-")[1]);
					if (isNaN(menuVersion) || menuVersion < 1305) {
						try {
							dump(" [OW] removing tools menu item: " + node.id + "\n");
							toolsPopup.removeChild(node);
							var toolbarItem = document.getElementById("ow-button-navigator" + (isNaN(menuVersion) ? "" : "-" + menuVersion));
							toolbarItem.parentNode.removeChild(toolbarItem);
						}
						catch(e) {
							dump("  [OW] Error removing tools menu item: " + node.id + " " + e + "\n");
						}
					}
				}
			}

			window.dump("[OW] Filling outfits menus\n");

      // intializing toolbar, menu and open firstrun/whatsnew tabs
      getInstalledModules(function(modules) {

        initToolbar(modules);
        fillToolsMenu(modules);

        openUpdateTabs(modules);
        initOutwitAutoloader();
      });
		}
		catch(e) {
			window.dump("[OW] Error in OutWit overlay : " + e + "\n");
		}



		var disabled = false;
		try {
			disabled = prefs.getBoolPref("disableUpdateCheck");
		}
		catch(e) {}

		if (!disabled) {
			var lastUpdate;
			try {
				lastUpdate = prefs.getIntPref("lastUpdateCheck") * 1000;
			}
			catch(e) {}

			window.dump("[OW] Compatibility check : " + lastUpdate + "\n");
			setTimeout(function() {
					var update = function(version) {
						// XXX TODO update
            window.openDialog("chrome://outwit-kernel/content/appUpdate/update.xul", "OWUpdateDialog", "chrome,centerscreen", {type: "download", version: version});
					}
				try {

					appUtils.getKernel(function(aKernel) {
						if (!aKernel.updateURL && aKernel.updateDate && (aKernel.updateDate.getTime()) < Date.now() - 2629743000) {
							update(aKernel.version.split(".", 2).join("."));
						}
						appUtils.getOutfits(function(outfits) {
							for (var i = 0; i < outfits.length; ++i) {
								if (!outfits[i].updateURL && outfits[i].updateDate && (outfits[i].updateDate.getTime()) < Date.now() - 2629743000) {
									update(aKernel.version.split(".", 2).join("."));
								}
							}
						});
					});

          const Cc = Components.classes;
          const Ci = Components.interfaces;
          appUtils.getKernel(function(oldKernels) {
            oldKernels.forEach(function(oldKernel) {
              if (oldKernel.id == "outwit-kernel-1110@outwit.com"
                  && gVersionChecker.compare(oldKernel.version, "3.0") >= 0
                  && gVersionChecker.compare(oldKernel.version, "3.0.4.5") < 0) {
                try {
                  oldKernel.cancelUninstall();
                }
                catch(e) {}
                oldKernel.userDisabled = false;

                appUtils.getOutfits(function(outfits) {
                  outfits.forEach(function(outfit) {
                    try {
                      outfit.cancelUninstall();
                    }
                    catch(e) {}
                    outfit.userDisabled = false;
                  });
                  window.openDialog("chrome://outwit-kernel/content/appUpdate/update.xul", "OWUpdateDialog", "chrome,centerscreen", {type: "customDownload", version: "3.0", outfits: outfits, dontRestartOutfit: true});
                }, false, true);
              }
            });
          }, true);

          self.checkVersionCompatibility();
          if (Math.floor(Math.random() * 4) && ((lastUpdate + 259200000) < Date.now())) {
            prefs.setIntPref("lastUpdateCheck", (Date.now() / 1000));
            if (!self.checkVersionUpdates()) {
              self.checkVersionCompatibility();
            }
          }
				}
				catch(e) {
					alert("4 : " + e + "\n" + e.stack);
				}

			}, 2000);
		}

    var autorunModule;
		try {
      var kernelPref = Components.classes["@mozilla.org/preferences-service;1"]
                                  .getService(Components.interfaces.nsIPrefService)
                                  .getBranch("extensions.outwit.")
                                  .QueryInterface(Components.interfaces.nsIPrefBranch2);
			autorunModule = kernelPref.getCharPref("autoRun.oneShot");
			if (autorunModule) {
				kernelPref.clearUserPref("autoRun.oneShot");
			}
		}
		catch(e) {}
    if (prefs.getBoolPref("hubAutoRun")) {
      autorunModule = "hub";
    }
		if (autorunModule) {
      appUtils.getOutfits(function(outfits) {
        for (var i = 0; i < outfits.length; ++i) {
          if (outfits[i].chromeId == "outwit-modules") {
            let outfit = outfits[i];
            getInstalledModule(autorunModule, function(module) {
              if (module) {
                window.setTimeout(
                  function() { appUtils.loadModule(autorunModule, false, gBrowser.currentURI, null, window); }
                  , 2000);
              }
            });
          }
        }
      }, true);
		}
	}
	window.addEventListener('load', self.onWindowLoad, false);
})();
