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;
});

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) {    
                var newWidth = parseInt(self.args.widgetArgs.width) * zoom + 9;
                var newHeight = parseInt(self.args.widgetArgs.height) * zoom + 7 + document.getElementById('chrome-title-box').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 doc = this.target.ownerDocument;
            if (doc.documentElement.clientHeight == this.args.widgetArgs.browserHeight &&
                doc.documentElement.clientWidth == this.args.widgetArgs.browserWidth) {
                if (this.args.widgetArgs.scrollTop) {
                    doc.documentElement.scrollTop = this.args.widgetArgs.scrollTop;
                }
                if (this.args.widgetArgs.scrollLeft) {
                    doc.documentElement.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
                contentBrowser.docShell.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 
            this.target.width = gStack.boxObject.width / this.args.widgetArgs.zoom + "px";
            this.target.height = gStack.boxObject.height / this.args.widgetArgs.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);
