/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";

XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
                                  "resource://devtools/shared/event-emitter.js");

XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                  "resource://gre/modules/Services.jsm");

// Import the android PageActions module.
XPCOMUtils.defineLazyModuleGetter(this, "PageActions",
                                  "resource://gre/modules/PageActions.jsm");

Cu.import("resource://gre/modules/ExtensionUtils.jsm");

var {
  IconDetails,
  SingletonEventManager,
} = ExtensionUtils;

// WeakMap[Extension -> PageAction]
var pageActionMap = new WeakMap();

function PageAction(options, extension) {
  this.id = null;

  this.extension = extension;
  this.icons = IconDetails.normalize({path: options.default_icon}, extension);

  this.popupUrl = options.default_popup;

  this.options = {
    title: options.default_title || extension.name,
    id: `{${extension.uuid}}`,
    clickCallback: () => {
      if (this.popupUrl) {
        let win = Services.wm.getMostRecentWindow("navigator:browser");
        win.BrowserApp.addTab(this.popupUrl, {
          selected: true,
          parentId: win.BrowserApp.selectedTab.id,
        });
      } else {
        this.emit("click");
      }
    },
  };

  this.shouldShow = false;

  EventEmitter.decorate(this);
}

PageAction.prototype = {
  show(tabId, context) {
    if (this.id) {
      return Promise.resolve();
    }

    if (this.options.icon) {
      this.id = PageActions.add(this.options);
      return Promise.resolve();
    }

    this.shouldShow = true;

    let {icon} = IconDetails.getPreferredIcon(this.icons, this.extension,
                                              18 * context.contentWindow.devicePixelRatio);

    let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
    return IconDetails.convertImageURLToDataURL(icon, context, browserWindow).then(dataURI => {
      if (this.shouldShow) {
        this.options.icon = dataURI;
        this.id = PageActions.add(this.options);
      }
    }).catch(() => {
      return Promise.reject({
        message: "Failed to load PageAction icon",
      });
    });
  },

  hide(tabId) {
    this.shouldShow = false;
    if (this.id) {
      PageActions.remove(this.id);
      this.id = null;
    }
  },

  setPopup(tab, url) {
    // TODO: Only set the popup for the specified tab once we have Tabs API support.
    this.popupUrl = url;
  },

  getPopup(tab) {
    // TODO: Only return the popup for the specified tab once we have Tabs API support.
    return this.popupUrl;
  },

  shutdown() {
    this.hide();
  },
};

/* eslint-disable mozilla/balanced-listeners */
extensions.on("manifest_page_action", (type, directive, extension, manifest) => {
  let pageAction = new PageAction(manifest.page_action, extension);
  pageActionMap.set(extension, pageAction);
});

extensions.on("shutdown", (type, extension) => {
  if (pageActionMap.has(extension)) {
    pageActionMap.get(extension).shutdown();
    pageActionMap.delete(extension);
  }
});
/* eslint-enable mozilla/balanced-listeners */

extensions.registerSchemaAPI("pageAction", "addon_parent", context => {
  let {extension} = context;
  return {
    pageAction: {
      onClicked: new SingletonEventManager(context, "pageAction.onClicked", fire => {
        let listener = (event) => {
          fire();
        };
        pageActionMap.get(extension).on("click", listener);
        return () => {
          pageActionMap.get(extension).off("click", listener);
        };
      }).api(),

      show(tabId) {
        return pageActionMap.get(extension)
                            .show(tabId, context)
                            .then(() => {});
      },

      hide(tabId) {
        pageActionMap.get(extension).hide(tabId);
        return Promise.resolve();
      },

      setPopup(details) {
        // TODO: Use the Tabs API to get the tab from details.tabId.
        let tab = null;
        let url = details.popup && context.uri.resolve(details.popup);
        pageActionMap.get(extension).setPopup(tab, url);
      },

      getPopup(details) {
        // TODO: Use the Tabs API to get the tab from details.tabId.
        let tab = null;
        let popup = pageActionMap.get(extension).getPopup(tab);
        return Promise.resolve(popup);
      },
    },
  };
});
