/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';

module.metadata = {
  'stability': 'unstable',
  'engines': {
    'Firefox': '*'
  }
};

const { models, buttons, views, viewsFor, modelFor } = require('./namespace');
const { isBrowser, getMostRecentBrowserWindow, windows, isWindowPrivate } = require('../../window/utils');
const { setStateFor } = require('../state');
const { defer } = require('../../core/promise');
const { isPrivateBrowsingSupported, data } = require('../../self');

const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const WEB_PANEL_BROWSER_ID = 'web-panels-browser';

const resolveURL = (url) => url ? data.url(url) : url;

function create(window, details) {
  let id = makeID(details.id);
  let { document } = window;

  if (document.getElementById(id))
    throw new Error('The ID "' + details.id + '" seems already used.');

  let menuitem = document.createElementNS(XUL_NS, 'menuitem');
  menuitem.setAttribute('id', id);
  menuitem.setAttribute('label', details.title);
  menuitem.setAttribute('sidebarurl', resolveURL(details.sidebarurl));
  menuitem.setAttribute('checked', 'false');
  menuitem.setAttribute('type', 'checkbox');
  menuitem.setAttribute('group', 'sidebar');
  menuitem.setAttribute('autoCheck', 'false');

  document.getElementById('viewSidebarMenu').appendChild(menuitem);

  return menuitem;
}
exports.create = create;

function dispose(menuitem) {
  menuitem.remove();
}
exports.dispose = dispose;

function updateTitle(sidebar, title) {
  let button = buttons.get(sidebar);

  for (let window of windows(null, { includePrivate: true })) {
  	let { document } = window;

    // update the button
    if (button) {
      setStateFor(button, window, { label: title });
    }

    // update the menuitem
    let mi = document.getElementById(makeID(sidebar.id));
    if (mi) {
      mi.setAttribute('label', title)
    }

    // update sidebar, if showing
    if (isSidebarShowing(window, sidebar)) {
      document.getElementById('sidebar-title').setAttribute('value', title);
    }
  }
}
exports.updateTitle = updateTitle;

function updateURL(sidebar, url) {
  let eleID = makeID(sidebar.id);

  url = resolveURL(url);

  for (let window of windows(null, { includePrivate: true })) {
    // update the menuitem
    let mi = window.document.getElementById(eleID);
    if (mi) {
      mi.setAttribute('sidebarurl', url)
    }

    // update sidebar, if showing
    if (isSidebarShowing(window, sidebar)) {
      showSidebar(window, sidebar, url);
    }
  }
}
exports.updateURL = updateURL;

function isSidebarShowing(window, sidebar) {
  let win = window || getMostRecentBrowserWindow();

  // make sure there is a window
  if (!win) {
    return false;
  }

  // make sure there is a sidebar for the window
  let sb = win.document.getElementById('sidebar');
  let sidebarTitle = win.document.getElementById('sidebar-title');
  if (!(sb && sidebarTitle)) {
    return false;
  }

  // checks if the sidebar box is hidden
  let sbb = win.document.getElementById('sidebar-box');
  if (!sbb || sbb.hidden) {
    return false;
  }

  if (sidebarTitle.value == modelFor(sidebar).title) {
    let url = resolveURL(modelFor(sidebar).url);

    // checks if the sidebar is loading
    if (win.gWebPanelURI == url) {
      return true;
    }

    // checks if the sidebar loaded already
    let ele = sb.contentDocument && sb.contentDocument.getElementById(WEB_PANEL_BROWSER_ID);
    if (!ele) {
      return false;
    }

    if (ele.getAttribute('cachedurl') == url) {
      return true;
    }

    if (ele && ele.contentWindow && ele.contentWindow.location == url) {
      return true;
    }
  }

  // default
  return false;
}
exports.isSidebarShowing = isSidebarShowing;

function showSidebar(window, sidebar, newURL) {
  window = window || getMostRecentBrowserWindow();

  let { promise, resolve, reject } = defer();
  let model = modelFor(sidebar);

  if (!newURL && isSidebarShowing(window, sidebar)) {
    resolve({});
  }
  else if (!isPrivateBrowsingSupported && isWindowPrivate(window)) {
    reject(Error('You cannot show a sidebar on private windows'));
  }
  else {
    sidebar.once('show', resolve);

    let menuitem = window.document.getElementById(makeID(model.id));
    menuitem.setAttribute('checked', true);

    window.openWebPanel(model.title, resolveURL(newURL || model.url));
  }

  return promise;
}
exports.showSidebar = showSidebar;


function hideSidebar(window, sidebar) {
  window = window || getMostRecentBrowserWindow();

  let { promise, resolve, reject } = defer();

  if (!isSidebarShowing(window, sidebar)) {
    reject(Error('The sidebar is already hidden'));
  }
  else {
    sidebar.once('hide', resolve);

    // Below was taken from http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#4775
    // the code for window.todggleSideBar()..
    let { document } = window;
    let sidebarEle = document.getElementById('sidebar');
    let sidebarTitle = document.getElementById('sidebar-title');
    let sidebarBox = document.getElementById('sidebar-box');
    let sidebarSplitter = document.getElementById('sidebar-splitter');
    let commandID = sidebarBox.getAttribute('sidebarcommand');
    let sidebarBroadcaster = document.getElementById(commandID);

    sidebarBox.hidden = true;
    sidebarSplitter.hidden = true;

    sidebarEle.setAttribute('src', 'about:blank');
    //sidebarEle.docShell.createAboutBlankContentViewer(null);

    sidebarBroadcaster.removeAttribute('checked');
    sidebarBox.setAttribute('sidebarcommand', '');
    sidebarTitle.value = '';
    sidebarBox.hidden = true;
    sidebarSplitter.hidden = true;

    // TODO: perhaps this isn't necessary if the window is not most recent?
    window.gBrowser.selectedBrowser.focus();
  }

  return promise;
}
exports.hideSidebar = hideSidebar;

function makeID(id) {
  return 'jetpack-sidebar-' + id;
}
