/* eslint-disable object-shorthand */

"use strict";

// Using a closure to not leak anything but the API to the outside world.
(function (exports) {

  var ExtensionCommon;
  var ExtensionSupport;
  if (typeof ChromeUtils.import === "function") { 
    ExtensionCommon = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm").ExtensionCommon;
    ExtensionSupport = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm").ExtensionSupport;
  }
  else
  {
    // TB136+
    ExtensionCommon = ChromeUtils.importESModule("resource://gre/modules/ExtensionCommon.sys.mjs").ExtensionCommon;
    ExtensionSupport = ChromeUtils.importESModule("resource:///modules/ExtensionSupport.sys.mjs").ExtensionSupport;
  }

/*
  The old ways...

  // Get various parts of the WebExtension framework that we need.
  var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");

  // You probably already know what this does.
//  var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
//  var Services = globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services;

  // A helpful class for listening to windows opening and closing.
  var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");
*/

  /**
   * This object is just what we're using to listen for toolbar clicks. The implementation
   * isn't what this example is about, but you might be interested as it's a common pattern.
   * We count the number of callbacks waiting for events so that we're only listening if we
   * need to be.
   * 
   * An EventEmitter has the following basic functions:
   * 
   * EventEmitter.on(emitterName, callback)
   *   Registers a callback for a custom emitter.
   * 
   * EventEmitter.off(emitterName, callback)
   *   Unregisters a callback for a custom emitter.
   * 
   * EventEmitter.emit(emitterName)
   *   Emit a custom emitter, all provided parameters will be forwarded to the registered callbacks.
   */

  let windowListener;

  class WindowListener extends ExtensionCommon.EventEmitter {
    constructor(extension) {
      super();
      this.extension = extension;
      this.onNewWindowCallbackCount = 0;
      this.onCloseButtonClickCallbackCount = 0;

      this.MESSAGE_CLOSE_TYPE_DEFAULT = 0;
      this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN = 1;
      this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY = 2;
      this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN = 3;
      this.MESSAGE_CLOSE_TYPE_MIN_ALL = 4;
    
      this.closeType = this.MESSAGE_CLOSE_TYPE_DEFAULT;
      this.mainWindowId = 0;

      this.activeWindows = {};
    }

    get listenerIdNewWindow() {
      return `window_event_listener_new_window_${this.extension.uuid}_${this.extension.instanceId}`;
    }

    get listenerIdCloseButton() {
      return `window_event_listener_close_button_${this.extension.uuid}_${this.extension.instanceId}`;
    }

    resetAllListeners() {    
    }

    setCloseType(closeType) {
//      console.log("Close type change: " + closeType);

      if (closeType === 0) {
        if( this.closeType !== this.MESSAGE_CLOSE_TYPE_DEFAULT )
        {
          this.resetAllListeners();
        }

        this.closeType = this.MESSAGE_CLOSE_TYPE_DEFAULT;
      } else if (closeType === 1) {
        if( this.closeType !== this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN )
        {
          this.resetAllListeners();
        }

        this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN;
      } else if (closeType === 2) {
        if( this.closeType !== this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY )
        {
          this.resetAllListeners();
        }
        
        this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY;
      } else if (closeType === 3) {
        if( this.closeType !== this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN )
        {
          this.resetAllListeners();
        }

        this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN;
      } else if (closeType === 4) {
        if( this.closeType !== this.MESSAGE_CLOSE_TYPE_MIN_ALL )
        {
          this.resetAllListeners();
        }

        this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL;
      } else console.log("Unknown close type: " + closeType);
    }

    setMainWindowId(id) {
      this.mainWindowId = id;
    }

    forceClose(id) {
      if (this.activeWindows[id] !== undefined) {
//        console.log("Force Close clicked: " + id);

        this.activeWindows[id].window.close = this.activeWindows[id].close;
        this.activeWindows[id].window.close();
        const closeWindow = this.activeWindows[id].window;

        delete this.activeWindows[id];

        closeWindow.close();
      }
    }
 
    addOnNewWindow(callback, context) {
      // Registering the callback for "new-window".
      this.on("new-window", callback);
      this.onNewWindowCallbackCount++;

//      console.log("New window add");

      if (this.onNewWindowCallbackCount === 1) {
        ExtensionSupport.registerWindowListener(this.listenerIdNewWindow, {
          context,
          chromeURLs: [
            "chrome://messenger/content/messenger.xhtml",
            "chrome://messenger/content/messenger.xul",
          ],
          onLoadWindow: function (window) {
            // Get current window id
            const id = context.extension.windowManager.getWrapper(window).id;

            windowListener.emit("new-window", id);

//            console.log("New window added: " + id);
          }
        });
      }
    }

    removeOnNewWindow(callback, context) {
      // Un-Registering the callback for "new-window".
      this.off("new-window", callback);
      this.onNewWindowCallbackCount--;

//      console.log("New window remove");

      if (this.onNewWindowCallbackCount === 0) {
        for (let window of ExtensionSupport.openWindows) {
          if ([
            "chrome://messenger/content/messenger.xhtml",
            "chrome://messenger/content/messenger.xul",
          ].includes(window.location.href)) {
            // Get current window id
            const id = context.extension.windowManager.getWrapper(window).id;

//            console.log("New window removed: " + id);
          }
        }
        ExtensionSupport.unregisterWindowListener( this.listenerIdNewWindow );
      }
    }
  
    addOnCloseButtonClick(callback, context) {
      // Registering the callback for "close-clicked".
      this.on( "close-clicked", callback );
      this.onCloseButtonClickCallbackCount++;

//      console.log("New Close add");

      if (this.onCloseButtonClickCallbackCount === 1) {
        ExtensionSupport.registerWindowListener(this.listenerIdCloseButton, {
          context,
          chromeURLs: [
            "chrome://messenger/content/messenger.xhtml",
            "chrome://messenger/content/messenger.xul",
          ],
          onLoadWindow: function ( window ) {
            // Get current window id
            const id = context.extension.windowManager.getWrapper(window).id

            if (id === windowListener.mainWindowId ||
                windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY ||
                windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL) {

              function onCloseButton(event) {
//                console.log("Close clicked: " + event);
//                console.log("Close clicked: " + id);

                if ( event ) event.preventDefault();
                windowListener.emit("close-clicked", id, false);
                return true;
              }

              //  Store the window data
              windowListener.activeWindows[id] = {
                window,
                close : window.close,
                listener: onCloseButton
              };

              // Intercept the close event (triggered when clicking the close button)
              window.addEventListener(
                "close",
                onCloseButton,
                true
              );
  
              //  Pre TB115 close menu, now same as close button
              window.close = () => onCloseButton(null);
  
//              console.log("Close listener added for: " + id);  
            } else {

              function onCloseButton2(event) {
//                console.log("Real Close clicked: " + id);

                windowListener.emit("close-clicked", id, true);

                window.close = windowListener.activeWindows[id].close;

                window.close();
                return false;
              }

              //  Store the window data
              windowListener.activeWindows[id] = {
                window,
                close : window.close,
                listener: onCloseButton2
              };

              // Intercept the close event (triggered when clicking the close button)
              window.addEventListener(
                "close",
                onCloseButton2,
                true
              );

              //  Pre TB115 close menu, now same as close button
              window.close = () => onCloseButton2(null);

//              console.log("Real Close listener added for: " + id);  
            }
          },
        });
      }
    }

    removeOnCloseButtonClick(callback, context) {
      // Un-Registering the callback for "close-clicked".
      this.off( "close-clicked", callback );
      this.onCloseButtonClickCallbackCount--;

//      console.log("Close remove");

      if (this.onCloseButtonClickCallbackCount === 0) {
        for (let window of ExtensionSupport.openWindows) {
          if ([
            "chrome://messenger/content/messenger.xhtml",
            "chrome://messenger/content/messenger.xul",
          ].includes(window.location.href)) {
            // Get current window id
            const id = context.extension.windowManager.getWrapper(window).id

            // Release the close event (triggered when clicking the close button)
            window.removeEventListener(
              "close",
              windowListener.activeWindows[id].listener,
              true
            );

            window.close = windowListener.activeWindows[id].close;

            //  Clean the storage
            delete windowListener.activeWindows[id];

//            console.log("Close listener removed for: " + id);
          }
        }
        ExtensionSupport.unregisterWindowListener(this.listenerIdCloseButton);
      }
    }
  };

  // This is the important part. It implements the functions and events defined
  // in the schema.json. The name must match what you've been using so far,
  // "windowEvent" in this case.
  class windowEvent extends ExtensionCommon.ExtensionAPI {
    // An alternative to defining a constructor here, is to use the onStartup
    // event. However, this causes the API to be instantiated directly after the
    // add-on has been loaded, not when the API is first used. Depends on what is
    // desired.
    constructor(extension) {
      super(extension);
      windowListener = new WindowListener(extension);
    }

    getAPI(context) {
      console.log("windowEvent API started");

      return {
        // This key must match the class name.
        windowEvent: {
          setCloseType: async function (type) {
            windowListener.setCloseType(type);
          },

          setMainWindowId: async function (id) {
            windowListener.setMainWindowId(id);
          },

          forceClose: async function (id) {
            windowListener.forceClose(id);
          },

          // An event. Most of this is boilerplate you don't need to worry about, just copy it.
          onNewWindow: new ExtensionCommon.EventManager({
            context,
            name: "windowEvent.onNewWindow",
            // In this function we add listeners for any events we want to listen to, and return a
            // function that removes those listeners. To have the event fire in your extension,
            // call fire.async.
            register(fire) {
              function callback(event, id) {
                return fire.async(id);
              }

              windowListener.addOnNewWindow(callback,context);
              return function () {
                windowListener.removeOnNewWindow(callback,context);
              };
            },
          }).api(),

          // An event. Most of this is boilerplate you don't need to worry about, just copy it.
          onCloseButtonClick: new ExtensionCommon.EventManager({
            context,
            name: "windowEvent.onCloseButtonClick",
            // In this function we add listeners for any events we want to listen to, and return a
            // function that removes those listeners. To have the event fire in your extension,
            // call fire.async.
            register(fire) {
              function callback(event, id, quit) {
                return fire.async(id, quit);
              }

              windowListener.addOnCloseButtonClick(callback,context);
              return function () {
                windowListener.removeOnCloseButtonClick(callback,context);
              };
            },
          }).api(),
        },
      };
    }

    onShutdown(isAppShutdown) {
      // This function is called if the extension is disabled or removed, or Thunderbird closes.
      // We usually do not have to do any cleanup, if Thunderbird is shutting down entirely
      if (isAppShutdown) {
        return;
      }

      console.log("windowEvent API closed");
    }
  };

  // Export the api by assigning in to the exports parameter of the anonymous closure
  // function, which is the global this.
  exports.windowEvent = windowEvent;

})(this)
