Components.utils['import']('resource://livemargins/utils.jsm');

/**** Emulating context for tabbrowser ****/
[
  ["gBrowser", "player_browser"],
  ["gURLBar", "urlbar"],
  ["gStack", "content-stack"],
].forEach(function (elementGlobal) {
  var [name, id] = elementGlobal;
  window.__defineGetter__(name, function () {
  var element = document.getElementById(id);
  if (!element)
  return null;
  delete window[name];
  return window[name] = element;
  });
  window.__defineSetter__(name, function (val) {
  delete window[name];
  return window[name] = val;
  });
});

if (typeof XPCOMUtils == "undefined") {
  Cu.import("resource://gre/modules/XPCOMUtils.jsm");
}

XPCOMUtils.defineLazyGetter(this, "BROWSER_NEW_TAB_URL", function () {
  return "about:blank";
});

XPCOMUtils.defineLazyGetter(this, "goSetCommandEnabled", function() {
  return function() { };
});

XPCOMUtils.defineLazyGetter(this, "TabsOnTop", function() {
  return {
    syncUI: function() { }
  };
});

XPCOMUtils.defineLazyGetter(this, "TabsInTitlebar", function() {
  return {
    allowedBy: function() { }
  };
});

XPCOMUtils.defineLazyGetter(this, "Services", function() {
  let jsm = { };
  Components.utils.import("resource://gre/modules/Services.jsm", jsm);
  return jsm.Services;
});

// gBrowserNewTabPreloader is defined since FF17
XPCOMUtils.defineLazyGetter(this, "gBrowserNewTabPreloader", function() {
  let tmp = {};
  Cu.import("resource://gre/modules/BrowserNewTabPreloader.jsm", tmp);
  return new tmp.BrowserNewTabPreloader();
});

function closeWindow() { }

window.handleDroppedLink = function() { };

var gFindBarInitialized = false;

window.isBlankPageURL = function(aURL) {
  return aURL == "about:blank"
};
/*** end ***/

XPCOMUtils.defineLazyGetter(this, "AppCenter", function() {
  let jsm = { };
  Components.utils.import("resource://livemargins/appcenter.jsm", jsm);
  return jsm.AppCenter;
});

XPCOMUtils.defineLazyGetter(this, "AppCenterDAO", function() {
  let jsm = { };
  Components.utils.import("resource://livemargins/dao.jsm", jsm);
  return jsm.AppCenterDAO;
});

var widget = {
  __proto__ : widgetbase,  //make this object 'extends' widgetbase
  isMovingContent : false,
  isMovingWindow : false,
  isResizing : false,
  moveStartPos : {x : 0,y : 0},
  defaultView : null,
  titlebarMinWidth : 160,
  target : null,
  targetInterval : null,
  LOG : function(msg) {
    this.__proto__.LOG.apply(this,["favpart video player: "+ msg]);
  },

  logger: utils.logger('LM4.FlashExtractor'),

  init : function() {
    this.LOG("init");
    var args = window.arguments[0];
    this.__proto__.init.apply(this);
    widget.showFav( args.id,
            args.widgetArgs.docX,
            args.widgetArgs.docY,
            args.screenX,
            args.screenY,
            args.widgetArgs.width,
            args.widgetArgs.height,
            args.widgetArgs.browserWidth,
            args.widgetArgs.browserHeight,
            args.widgetArgs.location,
            args.widgetArgs.tagName,
            args.widgetArgs.elementIndex,
            args.widgetArgs.elementWidth,
            args.widgetArgs.elementHeight,
            args.widgetArgs.zoom,
            args.widgetArgs.tab);
    // remove ref to xul tab
    delete args.widgetArgs.tab;

    this.args.startWithFirefox = 1;
    if (args.widgetArgs.autoReload == true) {
      this.setAutoReload(true);
    }
    this.LOG("init done");
  },

  setWidgetSize: function() {
    var self = this;
    window.setTimeout(function() {
      let zoom = self.args.widgetArgs.zoom;

      if (self.args.widgetArgs != null && self.args.widgetArgs.width != null) {
        let titleBox = document.getElementById('chrome-title-box');
        var newWidth = parseInt(self.args.widgetArgs.width) * zoom + 9;
        var newHeight = parseInt(self.args.widgetArgs.height) * zoom + 7 +
                          titleBox.boxObject.height;
        if (document.getElementById('footer-box') != null) {
          newHeight += document.getElementById('footer-box').boxObject.height;
        }

        if (navigator.appVersion.indexOf("Mac") != -1){
          // Mac removed the border for it is already shadowed
          newWidth -= 3;
          newHeight -= 3;
        }

        window.resizeTo(newWidth, newHeight);
      }
    }, 0);
  },

  openLinkInTab : function() {
    this.__proto__.openLinkInTab.apply(this,[true]);
  },

  addEventListeners: function() {
    var self = this;
    window.addEventListener("resize", function(event) {
      self.changeGBrowserSize();
      self.adjustTarget();
    }, false);

    this.addContentUnloadListener();

    gBrowser.addEventListener("DOMContentLoaded", function(event) {
      var domWin = event.originalTarget.defaultView;
      if (domWin != domWin.top) {
        return;
      }

      // Have chance to locate the target element
      if (!self.target) {
        let target = self.getWidgetTarget();
        self.adjustTarget();
        self.addContentUnloadListener();
      }
    }, false);

    // Prevent scroll page by mouse wheel
    gBrowser.addEventListener("DOMMouseScroll", function(event) {
      event.preventDefault();
    }, false);

    // Prevent page scrolling by arrow key
    gBrowser.addEventListener("keydown", function(event) {
      // Ignore non-arrow key
      if (event.keyCode > 40 || event.keyCode < 37) {
        return;
      }

      if (event.target instanceof HTMLInputElement ||
        event.target instanceof HTMLTextAreaElement) {
        return;
      }
      event.preventDefault();
    }, false);
  },

  addContentUnloadListener: function() {
    // For youku, there are pages that auto play next video which will
    // cause page reloaded.
    // Make sure target reference could be set to null if page is reloaded.
    var self = this;
    if (this.target) {
      let targetWin = this.target.ownerDocument.defaultView;
      targetWin.addEventListener("unload", function(event) {
        delete self.target;
        delete self.originHeight;
        delete self.originWidth;
        delete self.originSizeRemembered;
        targetWin.removeEventListener("unload", arguments.callee, false);
      }, false);
    }
  },

  // Make sure do not show the scrollbar
  changeGBrowserSize: function() {
    var w = gStack.clientWidth;
    var h = gStack.clientHeight;
    var width = this.args.widgetArgs.width;
    var height = this.args.widgetArgs.height;

    // Add margin to hide scrollbar
    gBrowser.setAttribute("width", (w > width ? w : width) + 30 + "px");
    gBrowser.setAttribute("height", (h > height ? h : height) + 30 + "px");
  },

  rememberOrignSize: function() {
    if (this.target && !this.originSizeRemembered) {
      this.originSizeRemembered = true;
      this.originWidth = this.target.getAttribute("width");
      this.originHeight = this.target.getAttribute("height");
    }
  },

  resetTargetSize: function() {
    if (this.target && this.originSizeRemembered) {
      this.target.setAttribute("width", this.originWidth);
      this.target.setAttribute("height", this.originHeight);
    }
  },

  resetDocScrollPos: function() {
    if (this.target) {
      let docElem = this.target.ownerDocument.documentElement;
      if (docElem.clientHeight == this.args.widgetArgs.browserHeight &&
        docElem.clientWidth == this.args.widgetArgs.browserWidth) {
        if (this.args.widgetArgs.scrollTop) {
          docElem.scrollTop = this.args.widgetArgs.scrollTop;
        }
        if (this.args.widgetArgs.scrollLeft) {
          docElem.scrollLeft = this.args.widgetArgs.scrollLeft;
        }
      }
    }
  },

  // Get target element
  getWidgetTarget: function() {
    if (this.target) {
      return this.target;
    }

    let tagName = this.args.widgetArgs.tagName;
    let elementIndex = this.args.widgetArgs.elementIndex;
    let elementWidth = this.args.widgetArgs.elementWidth;
    let elementHeight = this.args.widgetArgs.elementHeight;

    let target = this.getContentBrowser().contentDocument
                     .getElementsByTagName(tagName)[elementIndex];
    if (target && target.clientWidth == elementWidth &&
      target.clientHeight == elementHeight && target.style.display !="none") {
      this.target = target;
    }

    return this.target;
  },

  showFav : function( id, docX, docY, screenX, screenY, width,
            height, browserWidth, browserHeight, location, tagName,
            elementIndex, elementWidth, elementHeight, zoom, aOtherTab) {
    this.LOG("showFav");
    var contentBrowser = this.getContentBrowser();

    this.changeGBrowserSize();

    gBrowser.init();
    // Stop the about:blank load
    gBrowser.stop();
    // make sure it has a docshell
    gBrowser.docShell;

    var self = this;
    function _ajustBrowser() {
      // guess that the document is center aligned
      var newBrowserWidth = contentBrowser.contentWindow.scrollMaxX +
                            contentBrowser.boxObject.width;
      var newDocX = docX - (browserWidth - newBrowserWidth) / 2;
      contentBrowser.contentWindow.scrollTo(newDocX, docY);
      self.logger.trace("new browserWidth: " + newBrowserWidth);
      self.logger.trace("docXs: "+ newDocX + " " + docX);
      self.logger.trace("browserWidth changed: " +
                        (browserWidth - newBrowserWidth) / 2);

      var doc = contentBrowser.contentDocument;
      var target = self.getWidgetTarget();

      if (!target) {
        // the element is inserted afterwards, I can only guess from the position
        if (widget.targetInterval)
          window.clearInterval(widget.targetInterval);

        var count = 0;
        widget.targetInterval = window.setInterval(function() {
          target = self.getWidgetTarget();
          if (typeof(target) == "undefined"
                  || target.clientWidth != elementWidth
                  || target.clientHeight != elementHeight) {
            // the elementIndex nolonger works...
            target = doc.elementFromPoint(width / 2, height / 2);
          }
          self.logger.trace("inside interval:" + target);
          if ((target &&target.clientWidth == elementWidth) || count > 20) {
            self.target = target;
            self.addContentUnloadListener();
            window.clearInterval(widget.targetInterval);
            self.adjustTarget();
          }
          count++;
        }, 1000);
      }
    }

    if (aOtherTab) {
      var winCount = 0;
      var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"]
                             .getService(Ci.nsIWindowMediator);
      var winEnum = windowMediator.getEnumerator("navigator:browser");
      while (winEnum.hasMoreElements()) {
        var browserWin = winEnum.getNext();
        if (browserWin.closed) {
          continue;
        }
        if (winCount > 0) {
          break;
        }
        winCount++;
      }

      // If tab is the last of the last window, open an new blank tab
      // to keep window.
      var tabWin = aOtherTab.ownerDocument.defaultView;
      if (1 == winCount && tabWin.gBrowser.tabs.length == 1) {
        tabWin.BrowserOpenTab();
      }

      // Unregister open page, so the page uri can not be shown 
      // in the urlbar autocomplete list
      let remoteBrowser = aOtherTab.ownerDocument.defaultView.gBrowser;
      let rBrowser = remoteBrowser.getBrowserForTab(aOtherTab);
      if (rBrowser.registeredOpenURI) {
        let autocomplete = remoteBrowser._placesAutocomplete;
        autocomplete.unregisterOpenPage(rBrowser.registeredOpenURI);
        delete rBrowser.registeredOpenURI;
      }

      // Clear window name, make sure no more page will be opened
      // in the content browser.
      // Use "delete" does not work.
      rBrowser.contentWindow.name = "";

      gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, aOtherTab);
      _ajustBrowser();
      this.changeGBrowserSize();
    } else {
      contentBrowser.setAttribute("src", location);
      var contentDoc = contentBrowser.contentDocument;
      contentBrowser.addEventListener('DOMContentLoaded', function(ev) {
        if (! ev.originalTarget instanceof HTMLDocument ) {
          return;
        }
        // Set page zoom
        let contentViewer = contentBrowser.docShell.contentViewer;
        contentViewer.QueryInterface(Ci.nsIMarkupDocumentViewer).fullZoom =
          self.args.widgetArgs.zoom;
        window.setTimeout(_ajustBrowser, 0);
      }, false);
    }

    this.addEventListeners();
    this.startTargetAdjTimer();
    this.LOG("showFav done");
  },

  adjustTarget: function() {
    if (this.target) {
      var contentBrowser = this.getContentBrowser();
      var coords = utils.getRectTRBLWH(this.target,contentBrowser.contentWindow);
      contentBrowser.contentWindow.scrollBy(coords.left, coords.top);

      if (!this.originSizeRemembered) {
        this.rememberOrignSize();
      }

      // Change target size to fit window
      let zoom = this.args.widgetArgs.zoom;
      this.target.width = gStack.boxObject.width / zoom + "px";
      this.target.height = gStack.boxObject.height / zoom + "px";
    }
  },

  startTargetAdjTimer: function() {
    var self = this;
    window.clearInterval(this._targetAdjTimer);
    this._targetAdjTimer = window.setInterval(function() {
      self.adjustTarget();
    }, 2000);
  },

  getContentBrowser: function() {
    return gBrowser.browsers[0];
  },

  swapBack: function(ev) {
    window.clearInterval(this._targetAdjTimer);

    const wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                 .getService(Components.interfaces.nsIWindowMediator);
    var mainWin = wm.getMostRecentWindow("navigator:browser");
    if (!mainWin) {
      window.open();
      mainWin = wm.getMostRecentWindow("navigator:browser");
    }

    let remoteBrowser = mainWin.gBrowser;
    let newTab = remoteBrowser.addTab("about:blank");
    let newBrowser = remoteBrowser.getBrowserForTab(newTab);
    // Stop about:blank load
    newBrowser.stop();
    // Make sure it has a docshell
    newBrowser.docShell;
    remoteBrowser.selectedTab = newTab;

    try {
      // In the case, exception occurs:
      // 1. play video in the page:
      //    http://v.youku.com/v_playlist/f17138006o1p2.html
      // 2. Fullscreen the video by click the button in the video
      // 3. swap back video to firefox window
      remoteBrowser.swapBrowsersAndCloseOther(newTab, gBrowser.selectedTab);
    } catch (e) {
      this.logger.error(e);
    } finally {
      mainWin.focus();
      this.resetTargetSize();
      this.resetDocScrollPos();
      window.close();

      // Register open page uri
      let tabUrl = newBrowser.contentDocument.location.href;
      if (tabUrl != "about:blank") {
        let nUri = Cc['@mozilla.org/network/io-service;1']
                     .getService(Ci.nsIIOService)
                     .newURI(tabUrl, null, null);
        let autocomplete = remoteBrowser._placesAutocomplete;
        autocomplete.registerOpenPage(nUri);
        newBrowser.registeredOpenURI = nUri;
      }

      // Remove history if app is swapped back
      AppCenterDAO.resetAppOpenedTime(window.uid);
      AppCenter.appPref.updatePref('clearhistory', uid);
    }
  },

  toggleStartWithFirefox : function() {
    var startWithFirefox = document.getElementById("startWithFirefox")
                                   .getAttribute('checkState');
    if(startWithFirefox != '1') {
      this.args.startWithFirefox = 1;
    } else {
      this.args.startWithFirefox = 0;
    }
  }
};

window.addEventListener("load", function() {
  setTimeout(function() {
    widget.init();
  }, 1);
}, false);

