/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * 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 IETab. Modified In Coral IE Tab.
 *
 * The Initial Developer of the Original Code is yuoo2k <yuoo2k@gmail.com>.
 * Modified by quaful <quaful@msn.com>.
 *
 * Portions created by the Initial Developer are Copyright (C) 2006-2008
 * the Initial Developer. All Rights Reserved.
 *
 * ***** END LICENSE BLOCK ***** */

/**
 * @namespace
 */
if (typeof(COBA) == "undefined") {
  var COBA = {};
}
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://coba/cobaUtils.jsm");
let Strings = cobaUtils.Strings;

/** 将URL转换为IE Tab URL */
COBA.getCOBAURL = function(url) {
  if (COBA.startsWith(url, COBA.containerUrl)) return url;
  if (/^file:\/\/.*/.test(url)) try {
    url = decodeURI(url).replace(/\|/g, ":");
  } catch (e) {}
  return COBA.containerUrl + encodeURI(url);
}


/** 获取Firefox页面内嵌的plugin对象 */
COBA.getPluginObject = function(aTab) {
  var aBrowser = (aTab ? aTab.linkedBrowser : gBrowser);
  if (aBrowser && aBrowser.currentURI && COBA.startsWith(aBrowser.currentURI.spec, COBA.containerUrl)) {
    if (aBrowser.contentDocument) {
      var obj = aBrowser.contentDocument.getElementById(COBA.objectID);
      if (obj) {
        return (obj.wrappedJSObject ? obj.wrappedJSObject : obj); // Ref: Safely accessing content DOM from chrome
      }
    }
  }
  return null;
}

/** 获取IE Tab实际访问的URL*/
COBA.getPluginObjectURL = function(aTab) {
  var tab = aTab || null;
  var aBrowser = (tab ? tab.linkedBrowser : gBrowser);
  var url = COBA.getActualUrl(aBrowser.currentURI.spec);
  var pluginObject = COBA.getPluginObject(tab);
  if (pluginObject && pluginObject.URL && pluginObject.URL != "") {
    url = (/^file:\/\/.*/.test(url) ? encodeURI(COBA.convertToUTF8(pluginObject.URL)) : pluginObject.URL);
  }
  return COBA.getActualUrl(url);
}

/** 获取当前Tab的IE Tab URI
 *  与COBA.getPluginObjectURL功能相同
 */
COBA.getCurrentIeTabURI = function(aBrowser) {
  try {
    var docShell = aBrowser.boxObject.QueryInterface(Ci.nsIBrowserBoxObject).docShell;
    var wNav = docShell.QueryInterface(Ci.nsIWebNavigation);
    if (wNav.currentURI && COBA.startsWith(wNav.currentURI.spec, COBA.containerUrl)) {
      var pluginObject = wNav.document.getElementById(COBA.objectID);
      if (pluginObject) {
        if (pluginObject.wrappedJSObject) pluginObject = pluginObject.wrappedJSObject;
        var url = pluginObject.URL;
        if (url) {
          return Services.io.newURI(COBA.containerUrl + encodeURI(url), null, null);
        }
      }
    }
  } catch (e) {
    cobaUtils.LOG('COBA.getCurrentIeTabURI: ' + ex);
  }
  return null;
}

/** 是否是IE内核*/
COBA.isIEEngine = function(aTab) {
  var tab = aTab || gBrowser.mCurrentTab;
  var aBrowser = (aTab ? aTab.linkedBrowser : gBrowser);
  if (aBrowser && aBrowser.currentURI && COBA.startsWith(aBrowser.currentURI.spec, COBA.containerUrl)) {
    return true;
  }
  return false;
}

/** 切换某个Tab的内核
 *  通过设置不同的URL实现切换内核的功能。
 *  使用IE内核时，将URL转换为ie tab URL再访问；
 *  使用Firefox内核时，不需转换直接访问。
 */
COBA.switchTabEngine = function(aTab) {
  if (aTab && aTab.localName == "tab") {
    // 实际浏览的URL
    var url = COBA.getPluginObjectURL(aTab);

    var isIEEngineAfterSwitch = !COBA.isIEEngine(aTab);
    var domain = COBA.getUrlDomain(url).toLowerCase();
    if (isIEEngineAfterSwitch && aTab.getAttribute("skipDomain") == domain) {
      aTab.setAttribute("skipDomain","");
    }
    if (!isIEEngineAfterSwitch) {
      // Now it is IE engine, call me means users want to switch to Firefox engine.
      // We have to tell watcher that this is manual switching, do not switch back to IE engine
      aTab.setAttribute("skipDomain",domain);
    }
    let zoomLevel = COBA.getZoomLevel();
    COBA.setTabAttributeJSON(aTab, 'zoom', {zoomLevel: zoomLevel});


    // firefox特有地址只允许使用Firefox内核
    if (isIEEngineAfterSwitch && !COBA.isFirefoxOnly(url)){
      // ie tab URL
      url = COBA.getCOBAURL(url);
    }
    if (aTab.linkedBrowser && aTab.linkedBrowser.currentURI.spec != url) aTab.linkedBrowser.loadURI(url);
  }
}

COBA.setUrlBarSwitchButtonStatus = function(isIEEngine) {
  // Firefox特有页面禁止内核切换
  let url = COBA.getPluginObjectURL();
  let btn = document.getElementById("coba-current-engine");
  if (btn) {
    btn.disabled = COBA.isFirefoxOnly(url);
    btn.style.visibility = "visible";
    btn.setAttribute("engine", (isIEEngine ? "ie" : "fx"));
  }

  // 更新内核切换按钮文字
  let label = document.getElementById("coba-urlbar-switch-label");
  if (label) {
    let labelId = isIEEngine ? "coba.urlbar.switch.label.ie" : "coba.urlbar.switch.label.fx";
    label.value = Strings.global.GetStringFromName(labelId);
  }
  // 更新内核切换按钮tooltip文字
  let tooltip = document.getElementById("coba-urlbar-switch-tooltip2");
  if (tooltip) {
    let tooltipId = isIEEngine ? "coba.urlbar.switch.tooltip2.ie" : "coba.urlbar.switch.tooltip2.fx";
    tooltip.value = Strings.global.GetStringFromName(tooltipId);
  }
  var btn_urlbar_icon = document.getElementById("coba-urlbar-icon");
  btn_urlbar_icon.setAttribute("hidden", (isIEEngine ? "false" : "true"));
}

// 工具栏按钮的状态与地址栏状态相同
COBA.updateToolBar = function() {
  let urlbarButton = document.getElementById("coba-urlbar-switch");
  let toolbarButton = document.getElementById("coba-toolbar-palette-button");
  if (urlbarButton && toolbarButton) {
    toolbarButton.disabled = urlbarButton.disabled;
    toolbarButton.setAttribute("engine", urlbarButton.getAttribute("engine"));
  }
}
// Tab popmenu状态与地址栏状态相同
COBA.updateTabMenu = function() {
  let urlbarButton = document.getElementById("coba-urlbar-switch");
  let menu = document.getElementById("coba-tab-switch");
  if (urlbarButton && menu) {
    menu.setAttribute("checked", (COBA.isIEEngine(COBA.getContextTab()) ? "true" : "false"));
  }
}

/** 切换当前页面内核*/
COBA.switchEngine = function() {
  COBA.switchTabEngine(gBrowser.mCurrentTab);
}

/** 打开配置对话框 */
COBA.openOptionsDialog = function(url) {
  if (!url) url = COBA.getPluginObjectURL();
  var icon = document.getElementById('ietab-status');
  window.openDialog('chrome://coba/content/setting.xul', "cobaOptionsDialog", 'chrome,centerscreen', COBA.getUrlDomain(url), icon);
}

/** 新建一个ie标签*/
COBA.addIeTab = function(url) {
  let newTab = gBrowser.addTab(COBA.getCOBAURL(url));
  gBrowser.selectedTab = newTab;
  if (gURLBar && (url == 'about:blank')) window.setTimeout(function() {
    gURLBar.focus();
  }, 0);
  return newTab;
}

COBA.getHandledURL = function(url, isModeIE) {
  url = url.trim();

  // 访问firefox特有地址时, 只允许使用firefox内核
  if (COBA.isFirefoxOnly(url)) {
    return url;
  }

  if (isModeIE) return COBA.getCOBAURL(url);

  if (COBA.isIEEngine() && (!COBA.startsWith(url, "about:")) && (!COBA.startsWith(url, "view-source:"))) {
    if (COBA.isValidURL(url) || COBA.isValidDomainName(url)) {
      var isBlank = (COBA.getActualUrl(gBrowser.currentURI.spec) == "about:blank");
      var handleUrlBar = Services.prefs.getBoolPref("extensions.coba.handleUrlBar", false);
      var isSimilar = (COBA.getUrlDomain(COBA.getPluginObjectURL()) == COBA.getUrlDomain(url));
      if (isBlank || handleUrlBar || isSimilar) return COBA.getCOBAURL(url);
    }
  }

  return url;
}

/** 检查URL地址是否是火狐浏览器特有
 *  例如 about:config chrome://xxx
 */
COBA.isFirefoxOnly = function(url) {
   return(url && (url.length>0) &&
             ((COBA.startsWith(url, 'about:') && url != "about:blank") ||
              COBA.startsWith(url, 'chrome://')
             )
         );
}

/** 更新地址栏显示*/
COBA.updateUrlBar = function() {
  COBA.setUrlBarSwitchButtonStatus(COBA.isIEEngine());

  if (!gURLBar || !COBA.isIEEngine())
    return;
  if (gBrowser.userTypedValue) {
    if (gURLBar.selectionEnd != gURLBar.selectionStart) window.setTimeout(function() {
      gURLBar.focus();
    }, 0);
  } else {
    var url = COBA.getPluginObjectURL();
    if (url == "about:blank")
      url = "";
    if (gURLBar.value != url)
      gURLBar.value = url;
  }

  // 更新收藏状态(星星按钮黄色时表示该页面已收藏)
  if(window.PlacesStarButton)
    PlacesStarButton.updateState();
  else
    BookmarkingUI.updateStarState();
}

/** 改变页面元素启用状态*/
COBA.updateObjectDisabledStatus = function(objId, isEnabled) {
  var obj = (typeof(objId) == "object" ? objId : document.getElementById(objId));
  if (obj) {
    var d = obj.hasAttribute("disabled");
    if (d == isEnabled) {
      if (d) obj.removeAttribute("disabled");
      else obj.setAttribute("disabled", true);
    }
  }
}

/** 更新前进、后退铵钮状态*/
COBA.updateBackForwardButtons = function() {
  var pluginObject = COBA.getPluginObject();
  var canBack = (pluginObject ? pluginObject.CanBack : false) || gBrowser.webNavigation.canGoBack;
  var canForward = (pluginObject ? pluginObject.CanForward : false) || gBrowser.webNavigation.canGoForward;
  COBA.updateObjectDisabledStatus("Browser:Back", canBack);
  COBA.updateObjectDisabledStatus("Browser:Forward", canForward);
}

/** 更新停止和刷新按钮状态*/
COBA.updateStopReloadButtons = function() {
  try {
    var pluginObject = COBA.getPluginObject();
    var isBlank = (gBrowser.currentURI.spec == "about:blank");
    var isLoading = gBrowser.mIsBusy;
    COBA.updateObjectDisabledStatus("Browser:Reload", pluginObject ? pluginObject.CanRefresh : !isBlank);
    COBA.updateObjectDisabledStatus("Browser:Stop", pluginObject ? pluginObject.CanStop : isLoading);
  } catch (e) {}
}

// 更新编辑菜单中cmd_cut、cmd_copy、cmd_paste状态
COBA.updateEditMenuItems = function(e) {
  if (e.originalTarget != document.getElementById("menu_EditPopup")) return;
  var pluginObject = COBA.getPluginObject();
  if (pluginObject) {
    COBA.updateObjectDisabledStatus("cmd_cut", pluginObject.CanCut);
    COBA.updateObjectDisabledStatus("cmd_copy", pluginObject.CanCopy);
    COBA.updateObjectDisabledStatus("cmd_paste", pluginObject.CanPaste);
  }
}

// @todo 这是哪个按钮？
COBA.updateSecureLockIcon = function() {
  var pluginObject = COBA.getPluginObject();
  if (pluginObject) {
    var securityButton = document.getElementById("security-button");
    if (securityButton) {
      var url = pluginObject.URL;
      const wpl = Ci.nsIWebProgressListener;
      var state = (COBA.startsWith(url, "https://") ? wpl.STATE_IS_SECURE | wpl.STATE_SECURE_HIGH : wpl.STATE_IS_INSECURE);
      window.XULBrowserWindow.onSecurityChange(null, null, state);
      securityButton.setAttribute("label", COBA.getUrlHost(pluginObject.URL));
    }
  }
}

/** 更新界面显示*/
COBA.updateInterface = function() {
  COBA.updateBackForwardButtons();
  COBA.updateStopReloadButtons();
  COBA.updateSecureLockIcon();

  if(!!document.getElementById("urlbar-container")) {
    COBA.updateUrlBar();
  }
//  COBA.updateToolBar();
}

/** 更新相关的界面*/
COBA.updateAll = function() {
  if (COBA.updating) return;
  try {
    COBA.updating = true;
    COBA.updateInterface();
  } finally {
    COBA.updating = false;
  }
}

COBA.updateProgressStatus = function() {
  var mTabs = gBrowser.mTabContainer.childNodes;
  for (var i = 0; i < mTabs.length; i++) {
    if (mTabs[i].localName == "tab") {
      var pluginObject = COBA.getPluginObject(mTabs[i]);
      if (pluginObject) {
        var aCurTotalProgress = pluginObject.Progress;
        if (aCurTotalProgress != mTabs[i].mProgress) {
          const wpl = Ci.nsIWebProgressListener;
          var aMaxTotalProgress = (aCurTotalProgress == -1 ? -1 : 100);
          var aTabListener = gBrowser.mTabListeners[mTabs[i]._tPos];
          var aWebProgress = mTabs[i].linkedBrowser.webProgress;
          var aRequest = Services.io.newChannelFromURI(mTabs[i].linkedBrowser.currentURI);
          var aStateFlags = (aCurTotalProgress == -1 ? wpl.STATE_STOP : wpl.STATE_START) | wpl.STATE_IS_NETWORK;
          aTabListener.onStateChange(aWebProgress, aRequest, aStateFlags, 0);
          aTabListener.onProgressChange(aWebProgress, aRequest, 0, 0, aCurTotalProgress, aMaxTotalProgress);
          mTabs[i].mProgress = aCurTotalProgress;
        }
      }
    }
  }
}

/** 响应页面正在加载的消息*/
COBA.onIEProgressChange = function(event) {
  var progress = parseInt(event.detail);
  if (progress == 0) gBrowser.userTypedValue = null;
  COBA.updateProgressStatus();
  COBA.updateAll();
}

/** 响应新开IE标签的消息*/
COBA.onNewIETab = function(event) {
  let data = JSON.parse(event.detail);
  let url = data.url;
  let id = data.id;
  let tab = COBA.addIeTab(url);
  var param = {id: id};
  COBA.setTabAttributeJSON(tab, COBA.navigateParamsAttr, param);
}

COBA.onSecurityChange = function(security) {
  COBA.updateSecureLockIcon();
}

/** 异步调用plugin的方法*/
COBA.goDoCommand = function(cmd) {
  try {
    var pluginObject = COBA.getPluginObject();
    if (pluginObject == null) {
      return false;
    }
    var param = null;
    switch (cmd) {
    case "Back":
      if (!pluginObject.CanBack) {
        return false;
      }
      break;
    case "Forward":
      if (!pluginObject.CanForward) {
        return false;
      }
      break;
    }
    window.setTimeout(function() {
      COBA.delayedGoDoCommand(cmd);
    }, 100);
    return true;
  } catch (ex) {}
  return false;
}

/** 配合COBA.goDoCommand完成对plugin方法的调用*/
COBA.delayedGoDoCommand = function(cmd) {
  try {
    var pluginObject = COBA.getPluginObject();
    switch (cmd) {
    case "Back":
      pluginObject.Back();
      break;
    case "Forward":
      pluginObject.Forward();
      break;
    case "Stop":
      pluginObject.Stop();
      break;
    case "Refresh":
      pluginObject.Refresh();
      break;
    case "SaveAs":
      pluginObject.SaveAs();
      break;
    case "Print":
      pluginObject.Print();
      break;
    case "PrintSetup":
      pluginObject.PrintSetup();
      break;
    case "PrintPreview":
      pluginObject.PrintPreview();
      break;
    case "Find":
      pluginObject.Find();
      break;
    case "cmd_cut":
      pluginObject.Cut();
      break;
    case "cmd_copy":
      pluginObject.Copy();
      break;
    case "cmd_paste":
      pluginObject.Paste();
      break;
    case "cmd_selectAll":
      pluginObject.SelectAll();
      break;
    case "Focus":
      pluginObject.Focus();
      break;
    case "HandOverFocus":
      pluginObject.HandOverFocus();
      break;
    case "Zoom":
      var zoomLevel = COBA.getZoomLevel();
      pluginObject.Zoom(zoomLevel);
      break;
    case "DisplaySecurityInfo":
      pluginObject.DisplaySecurityInfo();
    break;
    }
  } catch (ex) {
  } finally {
    window.setTimeout(function() {
      COBA.updateAll();
    }, 0);
  }
}

/** 关闭Tab页
 * @param {number} i Tab页index
 */
COBA.closeTab = function(i) {
  var mTabs = gBrowser.mTabContainer.childNodes;
  gBrowser.removeTab(mTabs[i]);
}

/** 获取右键菜单关联的Tab对象*/
COBA.getContextTab = function() {
  return (gBrowser && gBrowser.mContextTab && (gBrowser.mContextTab.localName == "tab") ? gBrowser.mContextTab : null);
}

// 响应内核切换按钮点击事件
COBA.clickSwitchButton = function(e) {
  // 左键或中键点击切换内核
  if (e.button <= 1 && !e.target.disabled) {
    var aTab = gBrowser.mCurrentTab;
    if (!aTab) return;
    COBA.switchTabEngine(aTab);
  }

  // 右键点击显示选项菜单
  else if (e.button == 2) {
    document.getElementById("coba-switch-button-context-menu").openPopup(e.target, "after_start", 0, 0, true, false);
  }

  e.preventDefault();
}

/** 将焦点设置到IE窗口上*/
COBA.focusIE = function() {
  COBA.goDoCommand("Focus");
}

COBA.onTabSelected = function(e) {
  COBA.updateAll();
  COBA.focusIE();
}
COBA.switchToIEByDoc = {
  // nsISupports
  QueryInterface: function(iid) {
    if (iid.equals(Ci.nsISupports) ||
      iid.equals(Ci.nsIObserver)) {
      return this;
    }
    throw Cr.NS_ERROR_NO_INTERFACE;
  },

  // nsIObserver
  observe: function(subject, topic, data) {
    var tab = COBA.getTabByDocument(subject);
    tab && COBA.switchTabEngine(tab);
  },
}

/** 获取document对应的Tab对象*/
COBA.getTabByDocument = function(doc) {
  var mTabs = gBrowser.mTabContainer.childNodes;
  for (var i = 0; i < mTabs.length; i++) {
    var tab = mTabs[i];
    if (tab.linkedBrowser.contentDocument == doc) {
      return tab
    }
  }
  return null;
}

/** 加载或显示页面时更新界面*/
COBA.onPageShowOrLoad = function(e) {
  COBA.updateAll();

  var doc = e.originalTarget;

  var tab = COBA.getTabByDocument(doc);
  if (!tab) return;

  //
  // 检查是否需要设置ZoomLevel
  //
  let zoomLevelParams = COBA.getTabAttributeJSON(tab, 'zoom');
  if (zoomLevelParams) {
    COBA.setZoomLevel(zoomLevelParams.zoomLevel);
    tab.removeAttribute(tab, 'zoom');
  }
}

COBA.getTabAttributeJSON =  function(tab, name) {
  let attrString = tab.getAttribute(name);
  if (!attrString) {
    return null;
  }

  try {
    let json = JSON.parse(attrString);
    return json;
  } catch (ex) {
    cobaUtils.LOG('COBA.getTabAttributeJSON:' + ex);
  }

  return null;
}

COBA.setTabAttributeJSON = function(tab, name, value) {
  let attrString = JSON.stringify(value);
  tab.setAttribute(name, attrString);
}

/** 响应界面大小变化事件
 */
COBA.onResize = function(e) {
  // Zoom时会触发Resize事件
  COBA.goDoCommand("Zoom");
}

COBA.hookBrowserGetter = function(aBrowser) {
  if (aBrowser.localName != "browser") aBrowser = aBrowser.getElementsByTagNameNS(kXULNS, "browser")[0];
  // hook aBrowser.currentURI, 在IE引擎内部打开URL时, Firefox也能获取改变后的URL
  COBA.hookProp(aBrowser, "currentURI", function() {
    var uri = COBA.getCurrentIeTabURI(this);
    if (uri) return uri;
  });
  // hook aBrowser.sessionHistory
  // @todo 有什么用？
  COBA.hookProp(aBrowser, "sessionHistory", function() {
    var history = this.webNavigation.sessionHistory;
    var uri = COBA.getCurrentIeTabURI(this);
    if (uri) {
      var entry = history.getEntryAtIndex(history.index, false);
      if (entry.URI.spec != uri.spec) {
        entry.QueryInterface(Ci.nsISHEntry).setURI(uri);
        if (this.parentNode.__SS_data) delete this.parentNode.__SS_data;
      }
    }
  });
}

COBA.hookURLBarSetter = function(aURLBar) {
  if (!aURLBar)
    aURLBar = document.getElementById("urlbar");
  if (!aURLBar)
    return;
  aURLBar.onclick = function(e) {
    var pluginObject = COBA.getPluginObject();
    if (pluginObject) {
      COBA.goDoCommand("HandOverFocus");
    }
  }
  COBA.hookProp(aURLBar, "value", null, function() {
    this.isModeIE = arguments[0] && (arguments[0].substr(0, COBA.containerUrl.length) == COBA.containerUrl);
    if (this.isModeIE) {
      arguments[0] = COBA.getActualUrl(arguments[0]);
      // if (arguments[0] == "about:blank") arguments[0] = "";
    }
  });
}

COBA.hookCodeAll = function() {
  //hook properties
  COBA.hookBrowserGetter(gBrowser.mTabContainer.firstChild.linkedBrowser);
  COBA.hookURLBarSetter(gURLBar);
  //hook functions
  COBA.hookCode("gFindBar._onBrowserKeypress", "this._useTypeAheadFind &&", "$& !COBA.isIEEngine() &&"); // IE内核时不使用Firefox的查找条, $&指代被替换的代码
  COBA.hookCode("PlacesCommandHook.bookmarkPage", "aBrowser.currentURI", "makeURI(COBA.getActualUrl($&.spec))"); // 添加到收藏夹时获取实际URL
  if(window.PlacesStarButton)
    COBA.hookCode("PlacesStarButton.updateState" , /(gBrowser|getBrowser\(\))\.currentURI/g, "makeURI(COBA.getActualUrl($&.spec))"); // 用IE内核浏览网站时，在地址栏中正确显示收藏状态(星星按钮黄色时表示该页面已收藏)
  else
    COBA.hookCode("BookmarkingUI.updateStarState", /(gBrowser|getBrowser\(\))\.currentURI/g, "makeURI(COBA.getActualUrl($&.spec))"); // 用IE内核浏览网站时，在地址栏中正确显示收藏状态(星星按钮黄色时表示该页面已收藏)
  COBA.hookCode("gBrowser.addTab", "return t;", "COBA.hookBrowserGetter(t.linkedBrowser); $&");
  COBA.hookCode("gBrowser.setTabTitle", "if (browser.currentURI.spec) {", "$& if (browser.currentURI.spec.indexOf(COBA.containerUrl) == 0) return;"); // 取消原有的Tab标题文字设置
  COBA.hookCode("getShortcutOrURI", /return (\S+);/g, "return COBA.getHandledURL($1);"); // 访问新的URL

  //hook Interface Commands
  COBA.hookCode("BrowserBack", /{/, "$& if(COBA.goDoCommand('Back')) return;");
  COBA.hookCode("BrowserForward", /{/, "$& if(COBA.goDoCommand('Forward')) return;");
  COBA.hookCode("BrowserStop", /{/, "$& if(COBA.goDoCommand('Stop')) return;");
  COBA.hookCode("BrowserReload", /{/, "$& if(COBA.goDoCommand('Refresh')) return;");
  COBA.hookCode("BrowserReloadSkipCache", /{/, "$& if(COBA.goDoCommand('Refresh')) return;");

  COBA.hookCode("saveDocument", /{/, "$& if(COBA.goDoCommand('SaveAs')) return;");
  COBA.hookCode("MailIntegration.sendMessage", /{/, "$& var pluginObject = COBA.getPluginObject(); if(pluginObject){ arguments[0]=pluginObject.URL; arguments[1]=pluginObject.Title; }"); // @todo 发送邮件？

  COBA.hookCode("PrintUtils.print", /{/, "$& if(COBA.goDoCommand('Print')) return;");
  COBA.hookCode("PrintUtils.showPageSetup", /{/, "$& if(COBA.goDoCommand('PrintSetup')) return;");
  COBA.hookCode("PrintUtils.printPreview", /{/, "$& if(COBA.goDoCommand('PrintPreview')) return;");

  COBA.hookCode("goDoCommand", /{/, "$& if(COBA.goDoCommand(arguments[0])) return;"); // cmd_cut, cmd_copy, cmd_paste, cmd_selectAll

  COBA.hookAttr("cmd_find", "oncommand", "if(COBA.goDoCommand('Find')) return;");
  COBA.hookAttr("cmd_findAgain", "oncommand", "if(COBA.goDoCommand('Find')) return;");
  COBA.hookAttr("cmd_findPrevious", "oncommand", "if(COBA.goDoCommand('Find')) return;");

  COBA.hookCode("displaySecurityInfo", /{/, "$& if(COBA.goDoCommand('DisplaySecurityInfo')) return;");
}


COBA.addEventAll = function() {
  Services.obs.addObserver(COBA.HttpObserver, 'http-on-modify-request', false);
  COBA.CookieObserver.register();
  COBA.Observer.register();
  COBA.addEventListener("tabContextMenu", "popupshowing", COBA.updateTabMenu);

  COBA.addEventListener(window, "DOMContentLoaded", COBA.onPageShowOrLoad);
  COBA.addEventListener(window, "pageshow", COBA.onPageShowOrLoad);
  COBA.addEventListener(window, "resize", COBA.onResize);

  COBA.addEventListener(gBrowser.tabContainer, "TabSelect", COBA.onTabSelected);

  COBA.addEventListener("menu_EditPopup", "popupshowing", COBA.updateEditMenuItems);

  COBA.addEventListener(window, "IeProgressChanged", COBA.onIEProgressChange);
  COBA.addEventListener(window, "NewIETab", COBA.onNewIETab);
  Services.obs.addObserver(COBA.switchToIEByDoc, "COBA-swith-to-ie", false);
}

COBA.removeEventAll = function() {
  Services.obs.removeObserver(COBA.HttpObserver, 'http-on-modify-request');
  COBA.CookieObserver.unregister();
  COBA.Observer.unregister();

  COBA.removeEventListener("tabContextMenu", "popupshowing", COBA.updateTabMenu);

  COBA.removeEventListener(window, "DOMContentLoaded", COBA.onPageShowOrLoad);
  COBA.removeEventListener(window, "pageshow", COBA.onPageShowOrLoad);
  COBA.removeEventListener(window, "resize", COBA.onResize);

  COBA.removeEventListener(gBrowser.tabContainer, "TabSelect", COBA.onTabSelected);

  COBA.removeEventListener("menu_EditPopup", "popupshowing", COBA.updateEditMenuItems);

  COBA.removeEventListener(window, "ProgressChanged", COBA.onIEProgressChange);
  COBA.removeEventListener(window, "NewIETab", COBA.onNewIETab);
  Services.obs.removeObserver(COBA.switchToIEByDoc, "COBA-swith-to-ie");
}
COBA.init = function() {
  COBA.removeEventListener(window, "load", COBA.init);
  if(!!document.getElementById("urlbar-container")) {
    COBA.initNow();
  } else {
    COBA.initLater();
  }
}
COBA.initDone = false;

COBA.initLater = function() {
  var self = COBA;
  self.initDone = false;
  var navbar = document.getElementById("nav-bar");
  if (!navbar)
    return;

  if (window.MutationObserver) {
    var observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        if (mutation.type != 'attributes' ||
            mutation.target != navbar ||
            mutation.attributeName != 'currentset') {
          return;
        }

        if(!!document.getElementById("urlbar-container")) {
          self.initNow();
        }

      });
    });

    var config = {
      attributes: true,
      attributeOldValue: true,
      attributeFilter: ['currentset']
    };
    observer.observe(navbar, config);
  } else {
    navbar.addEventListener("DOMAttrModified",function(evt) {
      if (evt.type == "DOMAttrModified" &&
          evt.attrName == "currentset") {
        if(!!document.getElementById("urlbar-container")) {
          self.initNow();
        }
      }
    }, false);
  }

}

COBA.initNow = function() {
  if(COBA.initDone)
    return;
  COBA.initDone = true;
  setTimeout(function() {
    if(gBrowser.currentURI.spec != "about:blank")
      return;
    gBrowser.contentDocument.documentElement.focus();
    window.focusAndSelectUrlBar()
  },800)

  /**
   * navigator.plugins方法将使得最新安装的插件可用，更新相关数组，如 plugins 数组，并可选重新装入包含插件的已打开文档。
   * 你可以使用下列语句调用该方法：
   * navigator.plugins.refresh(true)
   * navigator.plugins.refresh(false)
   * 如果你给定 true 的话，refresh 将在使得新安装的插件可用的同时，重新装入所有包含有嵌入对象(EMBED 标签)的文档。
   *如果你给定 false 的话，该方法则只会刷新 plugins 数组，而不会重新载入任何文档。
   * 当用户安装插件后，该插件将不会可用，除非调用了 refresh，或者用户关闭并重新启动了 Navigator。
   */
  navigator.plugins.refresh(false);

  // 创建同步Cookie的plugin
  let item = document.createElementNS("http://www.w3.org/1999/xhtml", "html:embed");
  item.hidden = true;
  item.setAttribute("id", "coba-cookie-object");
  item.setAttribute("type", "application/coba");
  let mainWindow = document.getElementById("main-window");
  mainWindow.appendChild(item);

  COBA.hookCodeAll();
  COBA.addEventAll();
  COBA.updateAll();

  COBA.setupShortcut();
  COBA.setupUrlBar();
}

COBA.destroy = function() {
  COBA.removeEventListener(window, "unload", COBA.destroy);

  COBA.removeEventAll();
}

// 设置内核切换快捷键
COBA.setupShortcut = function() {
  try {
    let keyItem = document.getElementById('key_cobaToggle');
    if (keyItem) {
      // Default key is "C"
      keyItem.setAttribute('key', Services.prefs.getCharPref('extensions.coba.shortcut.key', 'C'));
      // Default modifiers is "alt"
      keyItem.setAttribute('modifiers', Services.prefs.getCharPref('extensions.coba.shortcut.modifiers', 'alt'));
    }
  } catch (e) {
    cobaUtils.ERROR(e);
  }
}

// 设置地址栏按钮
COBA.setupUrlBar = function() {
  let showUrlBarLabel = Services.prefs.getBoolPref("extensions.coba.showUrlBarLabel", true);
  document.getElementById("coba-urlbar-switch-label").hidden = !showUrlBarLabel;
  var btn_identity = document.getElementById("identity-box");
  btn_identity && btn_identity.addEventListener("click", COBA.showPanel, false);
  var btn_urlbar_icon = document.getElementById("coba-urlbar-icon");
  btn_urlbar_icon && btn_urlbar_icon.addEventListener("click", COBA.showPanel, false);
}


// identity-box事件
COBA.showPanel = function (e) {
  if (e.button == 0) {
    var location = gBrowser.contentWindow.location;

   if (location.href.indexOf(COBA.containerUrl) == 0) {
      COBA.notify(e.originalTarget);
    }
  }

  e.preventDefault();
}

COBA.notify = function (ele) {
  var panel = document.getElementById("coba-identity-popup");
  panel.openPopup(ele, "after_start", 15, 0, true, false);
}

COBA.hideNotify = function () {
  var panel = document.getElementById("coba-identity-popup");
  panel.hidePopup();
}

const PREF_BRANCH = "extensions.coba.";

/**
 * Observer monitering the preferences.
 */
COBA.Observer = {
  _branch: null,

  observe: function(subject, topic, data) {
    if (topic === "nsPref:changed") {
      let prefName = PREF_BRANCH + data;
      if (prefName.indexOf("shortcut.") != -1) {
        COBA.setupShortcut();
      } else if (prefName === "extensions.coba.showUrlBarLabel") {
        COBA.setupUrlBar();
      }
    }
  },

  register: function() {
    this._branch = Services.prefs.getBranch(PREF_BRANCH);
    if (this._branch) {
      // Now we queue the interface called nsIPrefBranch2. This interface is described as:
      // "nsIPrefBranch2 allows clients to observe changes to pref values."
      this._branch.QueryInterface(Ci.nsIPrefBranch2);
      this._branch.addObserver("", this, false);
    }

  },

  unregister: function() {
    if (this._branch) {
      this._branch.removeObserver("", this);
    }
  }
};

window.addEventListener("load", COBA.init, false);
window.addEventListener("unload", COBA.destroy, false);
COBA.engineAttr = "cobaEngine";
