var {
  Services
} = ChromeUtils.import("resource://gre/modules/Services.jsm");
var {
  ExtensionCommon
} = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");

var messageContentPolicy = class extends ExtensionCommon.ExtensionAPI {
  getAPI(context) {
    return {
      messageContentPolicy: {
        async getCurrent() {
          return new Promise(resolve => {

            /* currentPolicy should resolve as an object
               currentPolicy.msgBodyAs                 = plaintext || sanitized || original || allBodyParts
               currentPolicy.showAllBodyPartsMenuitem  = true || false
               currentPolicy.disableRemoteContent      = true || false
               currentPolicy.attachmentsInline         = true || false
               if needed, this could later be extended by other related values
               */

            let currentPolicy = {};

            let prefer_plaintext = Services.prefs.getBoolPref("mailnews.display.prefer_plaintext");
            let html_as = Services.prefs.getIntPref("mailnews.display.html_as");
            let disallow_classes = Services.prefs.getIntPref("mailnews.display.disallow_mime_handlers");

            if ((prefer_plaintext != true) && (html_as == 0) && (disallow_classes == 0)) {
              currentPolicy.msgBodyAs = "original";
            } else if ((prefer_plaintext != true) && (html_as == 3) && (disallow_classes > 0)) {
              currentPolicy.msgBodyAs = "sanitized";
            } else if ((prefer_plaintext == true) && (html_as == 1) && (disallow_classes > 0)) {
              currentPolicy.msgBodyAs = "plaintext";
            } else if ((prefer_plaintext != true) && (html_as == 4) && (disallow_classes == 0)) {
              currentPolicy.msgBodyAs = "allBodyParts";
            }

            currentPolicy.showAllBodyPartsMenuitem = Services.prefs.getBoolPref("mailnews.display.show_all_body_parts_menu");
            currentPolicy.disableRemoteContent = Services.prefs.getBoolPref("mailnews.message_display.disable_remote_image");
            currentPolicy.attachmentsInline = Services.prefs.getBoolPref("mail.inline_attachments");

            resolve(currentPolicy);

          });
        },

        async update(windowId, updateProperties, doNotReloadMsg) {
          return new Promise(resolve => {

            /* updateProperties must be an object with the following possible properties
               updateProperties.msgBodyAs                 = plaintext || sanitized || original || allBodyParts
               updateProperties.showAllBodyPartsMenuitem  = true || false
               updateProperties.disableRemoteContent      = true || false
               updateProperties.attachmentsInline         = true || false
               if needed, this could later be extended by other related values

               doNotReloadMsg is an optional boolean parameter
               if doNotReloadMsg is false or undefined, the message will be reloaded after prefs update (default behaviour)
               if doNotReloadMsg is true, than the message must not be reloaded, after prefs update (this is necessary for the "Allow HTML Temp" addon)
               */

            /* var gDisallow_classes_no_html is provided as a global var by mailWindowOverlay.js
               See comment in: https://searchfox.org/comm-central/source/mail/base/content/mailWindowOverlay.js#69
               */

            // console.debug("AHT: updateProperties = ", updateProperties);

            let window = context.extension.windowManager.get(windowId).window;
            let gDisallow_classes_no_html = window.gDisallow_classes_no_html;
            // console.debug("AHT: gDisallow_classes_no_html = ", gDisallow_classes_no_html);

            // Fallback to default value = 1, if we don't got the global var
            if (!gDisallow_classes_no_html) {
              gDisallow_classes_no_html = 1;
            }

            // Update the prefs for HTML mode (Menu View -> Message Body As)
            switch (updateProperties.msgBodyAs) {
              case "original":
                Services.prefs.setBoolPref("mailnews.display.prefer_plaintext", false);
                Services.prefs.setIntPref("mailnews.display.html_as", 0);
                Services.prefs.setIntPref("mailnews.display.disallow_mime_handlers", 0);
                break;
              case "sanitized":
                Services.prefs.setBoolPref("mailnews.display.prefer_plaintext", false);
                Services.prefs.setIntPref("mailnews.display.html_as", 3);
                Services.prefs.setIntPref("mailnews.display.disallow_mime_handlers",
                  gDisallow_classes_no_html);
                break;
              case "plaintext":
                Services.prefs.setBoolPref("mailnews.display.prefer_plaintext", true);
                Services.prefs.setIntPref("mailnews.display.html_as", 1);
                Services.prefs.setIntPref("mailnews.display.disallow_mime_handlers",
                  gDisallow_classes_no_html);
                break;
              case "allBodyParts":
                Services.prefs.setBoolPref("mailnews.display.prefer_plaintext", false);
                Services.prefs.setIntPref("mailnews.display.html_as", 4);
                Services.prefs.setIntPref("mailnews.display.disallow_mime_handlers", 0);
                break;
              default:
                // console.debug("AHT: updateProperties.msgBodyAs is undefined or has an invalid value");
            }

            // Update the pref for All Body Parts menu item (by default hidden 4th option in Menu View -> Message Body As)
            if (updateProperties.showAllBodyPartsMenuitem === true) {
              Services.prefs.setBoolPref("mailnews.display.show_all_body_parts_menu", true);
            } else if (updateProperties.showAllBodyPartsMenuitem === false) {
              Services.prefs.setBoolPref("mailnews.display.show_all_body_parts_menu", false);
            } else {
              // console.debug("AHT: updateProperties.showAllBodyPartsMenuitem is undefined or has an invalid value");
            }

            // Update the pref for remote content (Preferences -> Privacy & Security -> Allow remote content in messages)
            if (updateProperties.disableRemoteContent === true) {
              Services.prefs.setBoolPref("mailnews.message_display.disable_remote_image", true);
            } else if (updateProperties.disableRemoteContent === false) {
              Services.prefs.setBoolPref("mailnews.message_display.disable_remote_image", false);
            } else {
              // console.debug("AHT: updateProperties.remoteContent is undefined or has an invalid value");
            }

            // Update the pref for inline attachments (Menu View -> Display Attachments Inline)
            if (updateProperties.attachmentsInline === true) {
              Services.prefs.setBoolPref("mail.inline_attachments", true);
            } else if (updateProperties.attachmentsInline === false) {
              Services.prefs.setBoolPref("mail.inline_attachments", false);
            } else {
              // console.debug("AHT: updateProperties.attachmentsInline is undefined or has an invalid value");
            }

            if (doNotReloadMsg) {
              // console.debug("AHT: doNotReloadMsg: ", doNotReloadMsg);
              resolve(true);
              return;
            }

            // reload message only, if doNotReloadMsg = false or undefined

            /* ReloadMessage() is provided by: ************************************************************
               https://searchfox.org/comm-central/source/mail/base/content/msgMail3PaneWindow.js#1909

                function ReloadMessage() {
                  if (!gFolderDisplay.selectedMessage) {
                    return;
                  }

                  let view = gFolderDisplay.view.dbView;
                  if (view) {
                    view.reloadMessage();
                  }
                }

               https://searchfox.org/comm-central/source/mail/base/content/messageWindow.js#949

                function ReloadMessage() {
                  // If the current message was loaded from a file or attachment, so the dbView
                  // can't handle reloading it. Let's do it ourselves, instead.
                  if (window.arguments[0] instanceof Ci.nsIURI) {
                    gMessageDisplay.displayExternalMessage(window.arguments[0].spec);
                  } else {
                    gFolderDisplay.view.dbView.reloadMessage();
                  }
                }
            ******************************************************************************************** */

            // console.debug("AHT: doNotReloadMsg: ", doNotReloadMsg);
            window.ReloadMessage();
            resolve(true);

          });
        },

        onChanged: new ExtensionCommon.EventManager({
          context,
          name: "messageContentPolicy.onChanged",
          register(fire, changedProperty) {

            const prefsForAllProperties = [
              "mailnews.display.prefer_plaintext",
              "mailnews.display.html_as",
              "mailnews.display.disallow_mime_handlers",
              "mailnews.display.show_all_body_parts_menu",
              "mailnews.message_display.disable_remote_image",
              "mail.inline_attachments"
            ];
            const prefsForMsgBodyAs = [
              "mailnews.display.prefer_plaintext",
              "mailnews.display.html_as",
              "mailnews.display.disallow_mime_handlers",
            ];

            let observer = {};

            switch (changedProperty) {

              case "msgBodyAs":
                observer = {
                  observe(subject, topic, data) {
                    let callbackData = {};
                    if (topic == "nsPref:changed" && (prefsForMsgBodyAs.includes(data))) {
                      let prefer_plaintext = Services.prefs.getBoolPref("mailnews.display.prefer_plaintext");
                      let html_as = Services.prefs.getIntPref("mailnews.display.html_as");
                      let disallow_classes = Services.prefs.getIntPref("mailnews.display.disallow_mime_handlers");
                      if ((prefer_plaintext != true) && (html_as == 0) && (disallow_classes == 0)) {
                        callbackData.msgBodyAs = "original";
                      } else if ((prefer_plaintext != true) && (html_as == 3) && (disallow_classes > 0)) {
                        callbackData.msgBodyAs = "sanitized";
                      } else if ((prefer_plaintext == true) && (html_as == 1) && (disallow_classes > 0)) {
                        callbackData.msgBodyAs = "plaintext";
                      } else if ((prefer_plaintext != true) && (html_as == 4) && (disallow_classes == 0)) {
                        callbackData.msgBodyAs = "allBodyParts";
                      }
                      // Only fire, if not null
                      if (callbackData.msgBodyAs != null) {
                        fire.async(callbackData.msgBodyAs);
                      }
                    }
                  },
                };
                Services.prefs.addObserver(null, observer);
                return () => {
                  Services.prefs.removeObserver(null, observer);
                };
                break;

              case "showAllBodyPartsMenuitem":
                observer = {
                  observe(subject, topic, data) {
                    let callbackData = {};
                    if (topic == "nsPref:changed" && (data == "mailnews.display.show_all_body_parts_menu")) {
                      callbackData.showAllBodyPartsMenuitem = Services.prefs.getBoolPref("mailnews.display.show_all_body_parts_menu");
                      // Only fire, if not null
                      if (callbackData.showAllBodyPartsMenuitem != null) {
                        fire.async(callbackData.showAllBodyPartsMenuitem);
                      }
                    }
                  },
                };
                Services.prefs.addObserver(null, observer);
                return () => {
                  Services.prefs.removeObserver(null, observer);
                };
                break;

              case "disableRemoteContent":
                observer = {
                  observe(subject, topic, data) {
                    let callbackData = {};
                    if (topic == "nsPref:changed" && (data == "mailnews.message_display.disable_remote_image")) {
                      callbackData.disableRemoteContent = Services.prefs.getBoolPref("mailnews.message_display.disable_remote_image");
                      // Only fire, if not null
                      if (callbackData.disableRemoteContent != null) {
                        fire.async(callbackData.disableRemoteContent);
                      }
                    }
                  },
                };
                Services.prefs.addObserver(null, observer);
                return () => {
                  Services.prefs.removeObserver(null, observer);
                };
                break;

              case "attachmentsInline":
                observer = {
                  observe(subject, topic, data) {
                    let callbackData = {};
                    if (topic == "nsPref:changed" && (data == "mail.inline_attachments")) {
                      callbackData.attachmentsInline = Services.prefs.getBoolPref("mail.inline_attachments");
                      // Only fire, if not null
                      if (callbackData.attachmentsInline != null) {
                        fire.async(callbackData.attachmentsInline);
                      }
                    }
                  },
                };
                Services.prefs.addObserver(null, observer);
                return () => {
                  Services.prefs.removeObserver(null, observer);
                };
                break;

              case null:
                observer = {
                  observe(subject, topic, data) {
                    let callbackData = {};
                    if (topic == "nsPref:changed" && (prefsForAllProperties.includes(data))) {
                      if (prefsForMsgBodyAs.includes(data)) {
                        let prefer_plaintext = Services.prefs.getBoolPref("mailnews.display.prefer_plaintext");
                        let html_as = Services.prefs.getIntPref("mailnews.display.html_as");
                        let disallow_classes = Services.prefs.getIntPref("mailnews.display.disallow_mime_handlers");
                        if ((prefer_plaintext != true) && (html_as == 0) && (disallow_classes == 0)) {
                          callbackData.msgBodyAs = "original";
                        } else if ((prefer_plaintext != true) && (html_as == 3) && (disallow_classes > 0)) {
                          callbackData.msgBodyAs = "sanitized";
                        } else if ((prefer_plaintext == true) && (html_as == 1) && (disallow_classes > 0)) {
                          callbackData.msgBodyAs = "plaintext";
                        } else if ((prefer_plaintext != true) && (html_as == 4) && (disallow_classes == 0)) {
                          callbackData.msgBodyAs = "allBodyParts";
                        }
                      }
                      if (data == "mailnews.display.show_all_body_parts_menu") {
                        callbackData.showAllBodyPartsMenuitem = Services.prefs.getBoolPref(
                          "mailnews.display.show_all_body_parts_menu");
                      }
                      if (data == "mailnews.message_display.disable_remote_image") {
                        callbackData.disableRemoteContent = Services.prefs.getBoolPref(
                          "mailnews.message_display.disable_remote_image");
                      }
                      if (data == "mail.inline_attachments") {
                        callbackData.attachmentsInline = Services.prefs.getBoolPref("mail.inline_attachments");
                      }
                      // Fire only, if _not_ all properties are null
                      if (!((callbackData.msgBodyAs == null) && (callbackData.showAllBodyPartsMenuitem == null) && (callbackData.disableRemoteContent == null) && (callbackData.attachmentsInline == null))) {
                        // Fire and return the object as callback
                        fire.async(callbackData);
                      }
                    }
                  },
                };
                Services.prefs.addObserver(null, observer);
                return () => {
                  Services.prefs.removeObserver(null, observer);
                };
                break;

              default:
                console.error("messageContentPolicy: Invalid value for changedProperty");

            }

          },
        }).api(),

      }
    };
  }
};