/* 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/. */

var AboutTabCrashed = {
  /**
   * This can be set to true once this page receives a message from the
   * parent saying whether or not a crash report is available.
   */
  hasReport: false,

  /**
   * The messages that we might receive from the parent.
   */
  MESSAGES: [
    "SetCrashReportAvailable",
    "CrashReportSent",
    "UpdateCount",
  ],

  /**
   * Items for which we will listen for click events.
   */
  CLICK_TARGETS: [
    "closeTab",
    "restoreTab",
    "restoreAll",
    "sendReport",
  ],

  /**
   * Returns information about this crashed tab.
   *
   * @return (Object) An object with the following properties:
   *           title (String):
   *             The title of the page that crashed.
   *           URL (String):
   *             The URL of the page that crashed.
   */
  get pageData() {
    delete this.pageData;

    let URL = document.documentURI;
    let queryString = URL.replace(/^about:tabcrashed?e=tabcrashed/, "");

    let titleMatch = queryString.match(/d=([^&]*)/);
    let URLMatch = queryString.match(/u=([^&]*)/);

    return this.pageData = {
      title: titleMatch && titleMatch[1] ? decodeURIComponent(titleMatch[1]) : "",
      URL: URLMatch && URLMatch[1] ? decodeURIComponent(URLMatch[1]) : "",
    };
  },

  init() {
    this.MESSAGES.forEach((msg) => addMessageListener(msg, this.receiveMessage.bind(this)));
    addEventListener("DOMContentLoaded", this);

    document.title = this.pageData.title;
  },

  receiveMessage(message) {
    switch(message.name) {
      case "UpdateCount": {
        this.showRestoreAll(message.data.count > 1);
        break;
      }
      case "SetCrashReportAvailable": {
        this.onSetCrashReportAvailable(message);
        break;
      }
      case "CrashReportSent": {
        this.onCrashReportSent();
        break;
      }
    }
  },

  handleEvent(event) {
    switch (event.type) {
      case "DOMContentLoaded": {
        this.onDOMContentLoaded();
        break;
      }
      case "click": {
        this.onClick(event);
        break;
      }
    }
  },

  onDOMContentLoaded() {
    this.CLICK_TARGETS.forEach((targetID) => {
      let el = document.getElementById(targetID);
      el.addEventListener("click", this);
    });

    // Error pages are loaded as LOAD_BACKGROUND, so they don't get load events.
    let event = new CustomEvent("AboutTabCrashedLoad", {bubbles:true});
    document.dispatchEvent(event);

    sendAsyncMessage("Load");
  },

  onClick(event) {
    switch(event.target.id) {
      case "closeTab": {
        this.sendMessage("closeTab");
        break;
      }

      case "restoreTab": {
        this.sendMessage("restoreTab");
        break;
      }

      case "restoreAll": {
        this.sendMessage("restoreAll");
        break;
      }

      case "sendReport": {
        this.showCrashReportUI(event.target.checked);
        break;
      }
    }
  },

  /**
   * After this page tells the parent that it has loaded, the parent
   * will respond with whether or not a crash report is available. This
   * method handles that message.
   *
   * @param message
   *        The message from the parent, which should contain a data
   *        Object property with the following properties:
   *
   *        hasReport (bool):
   *          Whether or not there is a crash report
   *
   *        sendReport (bool):
   *          Whether or not the the user prefers to send the report
   *          by default
   *
   *        includeURL (bool):
   *          Whether or not the user prefers to send the URL of
   *          the tab that crashed.
   *
   *        emailMe (bool):
   *          Whether or not to send the email address of the user
   *          in the report.
   *
   *        email (String):
   *          The email address of the user (empty if emailMe is false)
   *
   */
  onSetCrashReportAvailable(message) {
    if (message.data.hasReport) {
      this.hasReport = true;
      document.documentElement.classList.add("crashDumpAvailable");

      let data = message.data;
      document.getElementById("sendReport").checked = data.sendReport;
      document.getElementById("includeURL").checked = data.includeURL;
      document.getElementById("emailMe").checked = data.emailMe;
      if (data.emailMe) {
        document.getElementById("email").value = data.email;
      }
    }

    let event = new CustomEvent("AboutTabCrashedReady", {bubbles:true});
    document.dispatchEvent(event);
  },

  /**
   * Handler for when the parent reports that the crash report associated
   * with this about:tabcrashed page has been sent.
   */
  onCrashReportSent() {
    document.documentElement.classList.remove("crashDumpAvailable");
    document.documentElement.classList.add("crashDumpSubmitted");
  },

  /**
   * Toggles the display of the crash report form.
   *
   * @param shouldShow (bool)
   *        True if the crash report form should be shown
   */
  showCrashReportUI(shouldShow) {
    let container = document.getElementById("crash-reporter-container");
    container.hidden = !shouldShow;
  },

  /**
   * Toggles the display of the "Restore All" button.
   *
   * @param shouldShow (bool)
   *        True if the "Restore All" button should be shown
   */
  showRestoreAll(shouldShow) {
    let restoreAll = document.getElementById("restoreAll");
    let restoreTab = document.getElementById("restoreTab");
    if (shouldShow) {
      restoreAll.removeAttribute("hidden");
      restoreTab.classList.remove("primary");
    } else {
      restoreAll.setAttribute("hidden", true);
      restoreTab.classList.add("primary");
    }
  },

  /**
   * Sends a message to the parent in response to the user choosing
   * one of the actions available on the page. This might also send up
   * crash report information if the user has chosen to submit a crash
   * report.
   *
   * @param messageName (String)
   *        The message to send to the parent
   */
  sendMessage(messageName) {
    let comments = "";
    let email = "";
    let URL = "";
    let sendReport = false;
    let emailMe = false;
    let includeURL = false;

    if (this.hasReport) {
      sendReport = document.getElementById("sendReport").checked;
      if (sendReport) {
        comments = document.getElementById("comments").value.trim();

        includeURL = document.getElementById("includeURL").checked;
        if (includeURL) {
          URL = this.pageData.URL.trim();
        }

        emailMe = document.getElementById("emailMe").checked;
        if (emailMe) {
          email = document.getElementById("email").value.trim();
        }
      }
    }

    sendAsyncMessage(messageName, {
      sendReport,
      comments,
      email,
      emailMe,
      includeURL,
      URL,
    });
  },
};

AboutTabCrashed.init();
