
Components.utils.import("resource://yoono/yoonoYEXTIF.js");
Components.utils.import("resource://yoono/yoonoPrefs.js");
Components.utils.import("resource://yoono/yoonoCookies.js");

var nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;

var screenManager = Components.classes["@mozilla.org/gfx/screenmanager;1"].getService(Components.interfaces.nsIScreenManager);



var ynWebPanel = {};

ynWebPanel._domWin = null;
ynWebPanel._baseWin = null;
ynWebPanel._panel = null;
ynWebPanel._iframe = null;
ynWebPanel._progress = null;
ynWebPanel._status = null;
ynWebPanel._title = null;

// YOONO_YEXTIF.notifyTabActivity(windowId, iframeWebsite.contentDocument, iframeWebsite.contentDocument.location.href, 'tabclosed');

ynWebPanel.init = function (onReadyCallback) {
  var attributes = "chrome=yes,titlebar=no";
  if (navigator.platform.indexOf("Win")==-1)
    attributes += "popup=yes";
  // Open a popup which will display website and immediatly hide it
  this._domWin = window.open("chrome://yoonorunner/content/website-panel.xul","wnd-login",attributes);
  
  this._domWin.QueryInterface(Components.interfaces.nsIDOMChromeWindow).browserDOMWindow = {
    QueryInterface : function(aIID)
    {
      if (aIID.equals(Components.interfaces.nsIBrowserDOMWindow) ||
          aIID.equals(Components.interfaces.nsISupports))
        return this;
      throw Components.results.NS_NOINTERFACE;
    },
    openURI : function(aURI, aOpener, aWhere, aContext)
    {
      return ynWebPanel._iframe.contentWindow;
    },

    isTabContentWindow : function(aWindow)
    {
      // Shouldn't ever get called
      throw Components.results.NS_ERROR_UNEXPECTED;
    }

  };
  
  this._baseWin = this._domWin.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                                        .getInterface(Components.interfaces.nsIWebNavigation)
                                        .QueryInterface(Components.interfaces.nsIDocShell)
                                        .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                                        .treeOwner
                                        .QueryInterface(Components.interfaces.nsIBaseWindow);
  this._baseWin.visibility = false;
  this._baseWin.enabled = false;
  
  this._domWin.addEventListener("load",function () {
    
    ynWebPanel._domWin.removeEventListener("load",arguments.callee,true);
    ynWebPanel._onMainDOMLoaded();
    
    if (typeof onReadyCallback=="function") {
      window.setTimeout(onReadyCallback,0);
    }
    
  }, false);
  
  this._domWin.addEventListener("keypress",function (e) {
    if (e.target.tagName=="INPUT" || e.target.tagName=="TEXTAREA") return;
    if (e.keyCode == 8)
      return ynWebPanel.goBack();
    
  },false);
}

ynWebPanel._onMainDOMLoaded = function () {
  this._doc = this._domWin.document;
  this._sideChangeBox = this._doc.getElementById("side-change-box");
  this._panel = this._doc.getElementById("website-panel");
  this._iframe = this._doc.getElementById("website-iframe");
  this._progress = this._doc.getElementById("website-progress");
  this._status = this._doc.getElementById("website-status");
  this._title = this._doc.getElementById("website-title");
  this._openInBrowserButton = this._doc.getElementById("website-open-in-browser");
  
  if (navigator.platform.indexOf("Mac")!=-1)
    this._doc.documentElement.className+=" desktop-mac";
  else if (navigator.platform.indexOf("Linux")!=-1)
    this._doc.documentElement.className+=" linux";
  
  //
  // Register all DOM listeners
  //ynWindowHandlers.addWindowDragElement(this._title);

  this._previousBtn = this._doc.getElementById("website-go-previous");
  this._previousBtn.addEventListener("click", function () {
    ynWebPanel.goBack();
  },true);
  
  this._nextBtn = this._doc.getElementById("website-go-next");
  this._nextBtn.addEventListener("click", function () {
    ynWebPanel.goNext();
  },true);
  
  var shareBtn = this._doc.getElementById("website-share-button");
  shareBtn.addEventListener("click", function () {
    var iframe = document.getElementById("main-iframe");
    var iframeWin = iframe.contentWindow;
    if (iframeWin.wrappedJSObject)
      iframeWin = iframeWin.wrappedJSObject;
    var sidebar = iframeWin.ynSidebar;
    sidebar.shortcutClick();
  },true);
  
  var header = this._doc.getElementById("website-header");
  header.addEventListener("dblclick", function () {
    ynWebPanel.maximize();
  },false);
  
  var maximizeButton = this._doc.getElementById("website-maximize-button");
  maximizeButton.addEventListener("click", function () {
    ynWebPanel.maximize();
  },true);
  
  var closeButton = this._doc.getElementById("website-close");
  closeButton.addEventListener("click", function () {
    ynWebPanel.close();
  },true);
  
  var openInBrowserBtn = this._doc.getElementById("website-open-in-browser");
  openInBrowserBtn.addEventListener("click", function () {
    ynWebPanel.close();
    ynWebPanel.openCurrentInSystemBrowser();
  },false);
  
  function updatePref(newValue) {
    YOONO_PREFS.set("open-in-system-browser",newValue);
    prefCheckbox.checked = newValue;
    prefRadioYoono.setAttribute("selected",!newValue?"true":"false");
    prefRadioSystem.setAttribute("selected",newValue?"true":"false");
  }
  var prefRadioYoono = this._doc.getElementById("website-open-in-browser-pref-yoono");
  var prefRadioSystem = this._doc.getElementById("website-open-in-browser-pref-system");
  var prefCheckbox = document.getElementById("open-in-browser-pref");
  prefRadioYoono.addEventListener("command", function () {
    updatePref(false);
  },true);
  prefRadioSystem.addEventListener("command", function () {
    updatePref(true);
  },true);
  prefCheckbox.addEventListener("command", function () {
    updatePref(prefCheckbox.checked);
  },true);

  
  updatePref(YOONO_PREFS.get("open-in-system-browser"));
  
  //
  // Setup all listener needed to watch website events
  this._iframe.addEventListener("load",function (event) {
    if (event.originalTarget!=ynWebPanel._iframe.contentDocument) return;
    YOONO_YEXTIF.notifyTabActivity(windowId, event.originalTarget, ynWebPanel._iframe.contentDocument.location.href, 'loaded');
    ynWebPanel._progress.hidden = true;
    ynWebPanel._status.hidden = true;
    ynWebPanel._status.value = "";
  },true);
  
  this._iframe.addEventListener("DOMContentLoaded",function (event) {
    if (event.originalTarget!=ynWebPanel._iframe.contentDocument) return;
    YOONO_YEXTIF.notifyTabActivity(windowId, ynWebPanel._iframe.contentDocument, ynWebPanel._iframe.contentDocument.location.href, 'domcontentloaded');
  },true);
  
  this._iframe.addEventListener("DOMTitleChanged",function (event) {
      if (event.originalTarget!=ynWebPanel._iframe.contentDocument) return;
      ynWebPanel._title.value = ynWebPanel._iframe.contentDocument.title;
  },false);
  
  var req = this._iframe.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  var prog = req.getInterface(Components.interfaces.nsIWebProgress);
  
  prog.addProgressListener(this._browserProgressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
  
  CookiesService.registerBrowser(this._iframe);
}

/* /!\ Take care : this!=ynWebPanel /!\ */
ynWebPanel._domClick = function(aEvent) {
  var link = aEvent.target;

  if (link instanceof HTMLAnchorElement /*&& 
      link.target != "" &&
      link.target != "_self" &&
      link.target != "_top"*/) {
    //aEvent.stopPropagation();
  }
}

/* /!\ Take care : this!=ynWebPanel /!\ */
ynWebPanel._domActivate = function(aEvent) {
  var link = aEvent.target;
  
  if (link instanceof HTMLAnchorElement /*&& 
      link.target != "" &&
      link.target != "_self" &&
      link.target != "_top"*/) {
    
    //aEvent.preventDefault();
    //aEvent.stopPropagation();
    
    //ynWebPanel.openUrl(link.href);
    //ynWebPanel.openUrlInSystemBrowser(link.href);
  }
}

/* /!\ Take care : this!=ynWebPanel /!\ */
ynWebPanel._domUnload = function(aEvent) {
  //aEvent.target.ownerDocument.removeEventListener("click", this._domClick, true);
  aEvent.target.ownerDocument.removeEventListener("DOMActivate", this._domActivate, true);
  aEvent.target.ownerDocument.removeEventListener("unload", this._domUnload, false);
}

ynWebPanel._browserProgressListener = {
  QueryInterface: function(iid) {
    if (iid.equals(Components.interfaces.nsIWebProgressListener) ||
        iid.equals(Components.interfaces.nsISupportsWeakReference) ||
        iid.equals(Components.interfaces.nsISupports))
      return this;
    
    throw Components.results.NS_ERROR_NO_INTERFACE;
  },
  _requestsStarted : 0,
  _requestsFinished : 0,
  onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
    if (aStateFlags & nsIWebProgressListener.STATE_IS_REQUEST) {
      if (aStateFlags & nsIWebProgressListener.STATE_START) {
        this._requestsStarted++;
      }
      else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
        this._requestsFinished++;
      }
      
      if (this._requestsStarted > 1) {
        var value = (100 * this._requestsFinished) / this._requestsStarted;
        ynWebPanel._progress.setAttribute("mode", "determined");
        ynWebPanel._progress.setAttribute("value", value + "%");
      }
    }

    if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
      if (aStateFlags & nsIWebProgressListener.STATE_START) {
        ynWebPanel._progress.hidden = false;
        ynWebPanel._status.hidden = false;
        ynWebPanel._status.value = "";
      }
      else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
        ynWebPanel._progress.hidden = true;
        ynWebPanel._status.hidden = true;
        ynWebPanel._status.value = "";
        this.onStatusChange(aWebProgress, aRequest, 0, "Done");
        this._requestsStarted = this._requestsFinished = 0;
      }      
    }
    
    if (aStateFlags & nsIWebProgressListener.STATE_IS_DOCUMENT) {
      if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
        var domDocument = aWebProgress.DOMWindow.document;
        domDocument.addEventListener("click", ynWebPanel._domClick, true);
        domDocument.addEventListener("DOMActivate", ynWebPanel._domActivate, true);
        domDocument.addEventListener("unload", ynWebPanel._domUnload, false);
      }
    }
  },

  // This method is called to indicate progress changes for the currently
  // loading page.
  onProgressChange: function(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) {
    if (this._requestsStarted == 1) {
      if (aMaxSelf == -1) {
        ynWebPanel._progress.setAttribute("mode", "undetermined");
      }
      else {
        ynWebPanel._progress.setAttribute("mode", "determined");
        ynWebPanel._progress.setAttribute("value", ((100 * aCurSelf) / aMaxSelf) + "%");
      }
    }
  },

  // This method is called to indicate a change to the current location.
  onLocationChange: function(aWebProgress, aRequest, aLocation) {
    ynWebPanel._previousBtn.className=ynWebPanel._iframe.canGoBack?"active":"";
    ynWebPanel._nextBtn.className=ynWebPanel._iframe.canGoForward?"active":"";
  },

  // This method is called to indicate a status changes for the currently
  // loading page.  The message is already formatted for display.
  onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {
    ynWebPanel._status.setAttribute("value", aMessage);
  },

  // This method is called when the security state of the browser changes.
  onSecurityChange: function(aWebProgress, aRequest, aState) {
    return;
    var security = document.getElementById("security");

    var level = "unknown";
    switch (aState) {
      case nsIWebProgressListener.STATE_IS_SECURE | nsIWebProgressListener.STATE_SECURE_HIGH:
        security.setAttribute("level", "high");
        break;
      case nsIWebProgressListener.STATE_IS_SECURE | nsIWebProgressListener.STATE_SECURE_MEDIUM:
        security.setAttribute("level", "med");
        break;
      case nsIWebProgressListener.STATE_IS_SECURE | nsIWebProgressListener.STATE_SECURE_LOW:
        security.setAttribute("level", "low");
        break;
      case nsIWebProgressListener.STATE_IS_BROKEN:
        security.setAttribute("level", "broken");
        break;
      case nsIWebProgressListener.STATE_IS_INSECURE:
      default:
        security.removeAttribute("level");
        break;
    }
  }

}; // end of ynWebPanel._browserProgressListener


///////////////////////////////////////
// Public methods

ynWebPanel.openUrlInSystemBrowser = function (url) {
  // Open in system web browser
  var ioService = Components.classes["@mozilla.org/network/io-service;1"]
                            .getService(Components.interfaces.nsIIOService);
  var uri = ioService.newURI(url, null, null);
  var extProtocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
                                 .getService(Components.interfaces.nsIExternalProtocolService);
  
  var protoInfo = extProtocolSvc.getProtocolHandlerInfo("http");
  if (protoInfo) {
    return protoInfo.launchWithURI(uri,null);
  }
  extProtocolSvc.loadURI(uri,null);
}

ynWebPanel.show = function () {
try {
  this._baseWin.visibility = true;
  this._baseWin.enabled = true;
  if (!Components.classes["@mozilla.org/jsctypes;1"]) {
    return;
  }
  var ua = navigator.userAgent.toLowerCase();
  if (ua.indexOf('windows')==-1)
    return;
  Components.utils.import("resource://gre/modules/ctypes.jsm");
  var lib = ctypes.open("user32.dll");
  var findWindow = lib.declare("FindWindowW",
                                 ctypes.stdcall_abi,
                                 ctypes.int32_t,
                                 ctypes.ustring,
                                 ctypes.ustring);
  var getWindowLong = lib.declare("GetWindowLongW",
                                 ctypes.stdcall_abi,
                                 ctypes.int32_t,
                                 ctypes.int32_t,
                                 ctypes.int32_t);
  var showWindow = lib.declare("ShowWindow",
                                 ctypes.stdcall_abi,
                                 ctypes.int32_t,
                                 ctypes.int32_t,
                                 ctypes.int32_t);
  var setWindowLong = lib.declare("SetWindowLongW",
                                 ctypes.stdcall_abi,
                                 ctypes.int32_t,
                                 ctypes.int32_t,
                                 ctypes.int32_t,
                                 ctypes.int32_t);
  var setWindowPos = lib.declare("SetWindowPos",
                                 ctypes.stdcall_abi,
                                 ctypes.int32_t,
                                 ctypes.int32_t,
                                 ctypes.int32_t,
                                 ctypes.int32_t,
                                 ctypes.int32_t,
                                 ctypes.int32_t,
                                 ctypes.int32_t,
                                 ctypes.int32_t);
  var GWL_EXSTYLE = -20;
  var WS_EX_APPWINDOW = 262144;
  var WS_EX_NOACTIVATE = 0x8000000;
  var WS_EX_TOOLWINDOW = 128;
  var SW_HIDE=0;
  var SW_SHOW=5;
  var SW_SHOWNORMAL = 1;
  var SWP_NOSIZE = 1;
  var SWP_NOMOVE = 2;
  var SWP_NOACTIVATE = 16;
  var HWND_NOTOPMOST = -2;
  var HWND_TOPMOST = -1;
  
  var layer_win = findWindow("MozillaUIWindowClass", "Yoono web preview");
  
  var currentstyle = getWindowLong(layer_win,GWL_EXSTYLE);
  if ( (currentstyle | WS_EX_TOOLWINDOW) != currentstyle ) {
    // Need to encapsulate setWindowLong call by hide/show, in order to just work.
    showWindow(layer_win,SW_HIDE);
    
    // remove from taskbar
    setWindowLong(layer_win,GWL_EXSTYLE, currentstyle | WS_EX_TOOLWINDOW );
    
    showWindow(layer_win,SW_SHOWNORMAL);
  }
  // Set topmost window
  //setWindowPos(layer_win, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
} catch(e) {
  Components.utils.reportError(e);
}
}

ynWebPanel.getBrowser = function () {
  return this._iframe;
}

ynWebPanel.openBrowser = function (mandatoryInXulrunner) {
  this._openInBrowserButton.hidden = mandatoryInXulrunner;
  
  trayIcon.restore(function () {
  
    ynWebPanel.refreshPopupSize(true);
    ynWebPanel.refreshPopupPosition(true);
    
    ynWebPanel.show();
    
    // /!\ moz'hack in order to see scrollbars ... 
    ynWebPanel._iframe.style.overflow="auto";
    
  });
  
  return this._iframe;
}

ynWebPanel.openCurrentInSystemBrowser = function () {
  this.openUrlInSystemBrowser(this._iframe.contentDocument.location.href);
}

ynWebPanel.goBack = function () {
  return this._iframe.goBack();
}

ynWebPanel.goNext = function () {
  return this._iframe.goForward();
}

ynWebPanel.close = function () {
  var nav = this._iframe.webNavigation;
  nav.loadURI("about:blank", 0, null, null, null);
  this._baseWin.visibility = false;
  this._baseWin.enabled = false;
  YOONO_YEXTIF.notifyTabActivity(windowId, this._iframe.contentDocument, "about:blank", 'close');
}

ynWebPanel._mayDisplayLeft = function (screenLeft, screenWidth) {
  return ((window.screenX-screenLeft)+window.outerWidth/2)>(screenWidth/2);
}

ynWebPanel._screenBorder = 2;
ynWebPanel.refreshPopupSize = function (forceRefresh) {
  if (!forceRefresh && !this._baseWin.enabled) return;
  
  var sc = screenManager.screenForRect(window.screenX, window.screenY, window.outerWidth, window.outerHeight);
  var screenLeft = {},screenTop = {},screenWidth = {},screenHeight = {};
  sc.GetAvailRect(screenLeft, screenTop, screenWidth, screenHeight);
  
  var margin = ynWebPanel._screenBorder*2;
  var maxScreenWidth = screenWidth.value;
  if (this._mayDisplayLeft(screenLeft.value, screenWidth.value)) { // display at left
    maxScreenWidth = window.screenX-screenLeft.value-margin;
  } else { // display at right
    maxScreenWidth = screenWidth.value-window.outerWidth-(window.screenX-screenLeft.value)-margin;
  }
  var maxScreenHeight = screenHeight.value-margin;
  
  var w = Math.max(600,Math.min(maxScreenWidth,1024));
  var h = Math.max(600,maxScreenHeight);
  w = maxScreenWidth;
  h = maxScreenHeight
  this._domWin.resizeTo(w, h);
  
}
ynWebPanel.startMoving = function () {
  this._iframe.style.display="none";
  //this._iframe.parentNode.style.background="url('chrome://yoonorunner/skin/move.png') center no-repeat";
}
ynWebPanel.endMoving = function () {
  this._iframe.style.display=null;
  //this._iframe.parentNode.style.background=null;
}
ynWebPanel.refreshPopupPosition = function (forceRefresh) {
  if (!forceRefresh && !this._baseWin.enabled) return;
  
  var sc = screenManager.screenForRect(window.screenX, window.screenY, window.outerWidth, window.outerHeight);
  var screenLeft = {},screenTop = {},screenWidth = {},screenHeight = {};
  sc.GetAvailRect(screenLeft, screenTop, screenWidth, screenHeight);
  
  var x = 0;
  var y = screenTop.value+ynWebPanel._screenBorder;
  if (this._mayDisplayLeft(screenLeft.value, screenWidth.value)) { // display at left
    x = window.screenX-this._domWin.outerWidth-ynWebPanel._screenBorder;
  } else { // display at right
    x = window.screenX+window.outerWidth+ynWebPanel._screenBorder;
  }
  this._domWin.moveTo(x, y);
}

ynWebPanel.maximize = function () {
  var sc = screenManager.screenForRect(window.screenX, window.screenY, window.outerWidth, window.outerHeight);
  var screenLeft = {},screenTop = {},screenWidth = {},screenHeight = {};
  sc.GetAvailRect(screenLeft, screenTop, screenWidth, screenHeight);
  if (this._mayDisplayLeft(screenLeft.value, screenWidth.value)) {
    ynWindowHandlers.moveRight();
  } else {
    ynWindowHandlers.moveLeft();
  }
}

window.addEventListener("load",function () {
  
  ynWebPanel.init();
  
},false);
