/* global e */
/* global hide */
/* global show */
/* global sendMessage */
/* global getOption_ */
/* global setOption_ */

"use strict";

/**
 * Handles rule (de)activation in the popup
 */
function toggleRuleLine(event) {
  getTab(activeTab => {
    const set_ruleset = {
      active: event.target.parentNode.firstChild.checked,
      name: event.target.innerText,
      tab_id: activeTab.id,
    };

    sendMessage("set_ruleset_active_status", set_ruleset, () => {
      // purge the name from the cache so that this unchecking is persistent.
      sendMessage("delete_from_ruleset_cache", set_ruleset.name, () => {
        // Now reload the selected tab of the current window.
        chrome.tabs.reload(set_ruleset.tab_id);
      });
    });
  });
}

/**
 * @param {object} event
 * @description Toggles content for user to view rules and explanations for different modes
 */
function toggleSeeMore(event) {
  let target = event.target;
  let content;

  if (target !== this) {
    content = document.querySelector('.see_more__content');
  } else {
    content = target.parentNode.querySelector('.see_more__content');
  }

  let arrow  = target.parentNode.querySelector('.see_more__arrow');
  let text = target.parentNode.querySelector('.see_more__text');

  if(arrow.classList.contains('down')) {
    arrow.classList.replace('down', 'up');
    text.innerText = 'See less';
  } else if (arrow.classList.contains('up')) {
    arrow.classList.replace('up', 'down');
    text.innerText = 'See more';
  }

  if (content.classList.contains('hide')) {
    content.classList.replace('hide', 'show');
  } else if (content.classList.contains('show')) {
    content.classList.replace('show', 'hide');
  }
}

/**
 * Creates rule lines (including checkbox and icon) for the popup
 * @param rulesets
 * @param list_div
 * @param {string} ruleType
 * @returns {*}
 */
function appendRulesToListDiv(rulesets, list_div, ruleType) {
  if (rulesets && rulesets.length) {
    let counter = rulesets.length;
    let counterElement = document.querySelector("#RuleManagement--counter");
    counterElement.innerText = counter;
    // template parent block for each ruleset
    let templateLine = document.createElement("div");
    templateLine.className = "rule checkbox";

    // label "container"
    let templateLabel = document.createElement("label");

    // checkbox
    let templateCheckbox = document.createElement("input");
    templateCheckbox.type = "checkbox";

    // label text
    let templateLabelText = document.createElement("span");

    // img "remove" button
    let templateRemove = document.createElement("img");
    templateRemove.src = chrome.runtime.getURL("images/remove.png");
    templateRemove.className = "remove";

    templateLine.appendChild(templateCheckbox);
    templateLabel.appendChild(templateLabelText);
    templateLine.appendChild(templateLabel);

    let increment = 0;

    for (const ruleset of rulesets) {
      increment++;
      let line = templateLine.cloneNode(true);
      let checkbox = line.querySelector("input[type=checkbox]");
      let label = line.querySelector("label");
      let text = line.querySelector("span");

      // For each "id" attribute in each checkbox input and "for" attribute in label
      checkbox.setAttribute("id", `${ruleType}_ruleset_${increment}`);
      label.setAttribute("for", `${ruleType}_ruleset_${increment}`);

      checkbox.checked = ruleset.active;
      text.innerText = ruleset.name;

      if (ruleset.note && ruleset.note.length) {
        line.title = ruleset.note;

        if (ruleset.note === "user rule") {
          let remove = templateRemove.cloneNode(true);
          line.appendChild(remove);

          remove.addEventListener("click", () => {
            sendMessage("remove_rule", { ruleset, src: 'popup' }, () => {
              list_div.removeChild(line);
            });
          });
        }
      }
      list_div.appendChild(line);
    }
    show(list_div);
  }
}

function showHttpNowhereUI() {
  // Set up checkbox for HTTP nowhere mode
  getOption_('httpNowhere', false, function(item) {
    if (item.httpNowhere) {
      e('http-nowhere-checkbox').checked = true;
      e('HttpNowhere__header').innerText = 'Encrypt All Sites Eligible is ON';
      e('HttpNowhere__explained').innerText = 'Unencrypted requests are currently blocked';
    }
    e('HttpNowhere').style.visibility = "visible";
  });
};

// Change the UI to reflect extension enabled/disabled
function updateEnabledDisabledUI() {
  getOption_('globalEnabled', true, function(item) {
    e('onoffswitch').checked = item.globalEnabled;
    e('disableButton').style.visibility = "visible";
    // Hide or show the rules sections
    if (item.globalEnabled) {
      document.body.className = ""
      showHttpNowhereUI();
    } else {
      document.body.className = "disabled";
      e('onoffswitch_label').innerText = 'HTTPS Everywhere is OFF';
    }
  });
}

// Toggle extension enabled/disabled status
function toggleEnabledDisabled() {
  let extension_toggle_effect = function() {
    updateEnabledDisabledUI();
    // The extension state changed, give some time for toggle animation and reload tab
    setTimeout(function() {
      chrome.tabs.reload();
      window.close();
    }, 1500);
  }

  getOption_('globalEnabled', true, function(item) {
    setOption_('globalEnabled', !item.globalEnabled, extension_toggle_effect);
  });
}

/**
 * @description Create the list of rules for a specific tab
 * @param activeTab
 */
function listRules(activeTab) {
  sendMessage("get_active_rulesets", activeTab.id, function(rulesets) {
    if (rulesets) {
      const stableRules = rulesets.filter(ruleset => ruleset.default_state);
      const unstableRules = rulesets.filter(ruleset => !ruleset.default_state);

      appendRulesToListDiv(stableRules, e("StableRules"), 'stable');
      appendRulesToListDiv(unstableRules, e("UnstableRules"), 'unstable');

      // Add listener to capture the toggle event
      e("add-new-rule-button").addEventListener("click", toggleRuleLine);
    }

    // Only show the "Add a rule" section if we're on an HTTPS page
    if (/^https:/.test(activeTab.url)) {
      show(e("addRuleSection"));
    }
  });
}

/**
 * Fill in content into the popup on load
 */
document.addEventListener("DOMContentLoaded", function () {
  getTab(tab => {
    const url = new URL(tab.url);
    sendMessage("check_if_site_disabled", url.host, disabled => {
      if(!disabled) {
        listRules(tab);
      }
      showEnableOrDisable(url, disabled);
    });
  });

  // Set up the enabled/disabled switch & hide/show rules
  updateEnabledDisabledUI();
  e('onoffswitch').addEventListener('click', toggleEnabledDisabled);
  e('http-nowhere-checkbox').addEventListener('click', toggleHttpNowhere, false);
  e('RuleManagement__see_more--prompt').addEventListener('click', toggleSeeMore);

  e('reset-to-defaults').addEventListener('click', () => {
    sendMessage("is_firefox", null, is_firefox => {
      if (is_firefox) {
        sendMessage("reset_to_defaults", null, () => {
          window.close();
        });
      } else {
        if (confirm(chrome.i18n.getMessage("prefs_reset_defaults_message"))) {
          sendMessage("reset_to_defaults", null, () => {
            window.close();
          });
        }
      }
    });
  });

  // Print the extension's current version.
  var the_manifest = chrome.runtime.getManifest();
  var version_info = e('current-version');
  version_info.innerText = the_manifest.version;

  let rulesets_versions = e('rulesets-versions');

  rulesets_versions.addSpan = function(update_channel_name, ruleset_version_string) {
    let timestamp_span = document.createElement("span");
    timestamp_span.className = "rulesets-version";
    timestamp_span.innerText = `${chrome.i18n.getMessage("about_rulesets_version")} ${update_channel_name}: ${ruleset_version_string}`;
    this.appendChild(timestamp_span);
  }

  sendMessage("get_ruleset_timestamps", null, timestamps => {
    let replaces = timestamps.some(([update_channel, timestamp]) =>
      update_channel.replaces_default_rulesets && timestamp > 0
    );
    if(!replaces) {
      rulesets_versions.addSpan("EFF (Full, Bundled)", the_manifest.version);
    }
    for(let [update_channel, timestamp] of timestamps) {
      if(timestamp > 0) {
        let ruleset_date = new Date(timestamp * 1000);
        let ruleset_version_string = ruleset_date.getUTCFullYear() + "." + (ruleset_date.getUTCMonth() + 1) + "." + ruleset_date.getUTCDate();

        rulesets_versions.addSpan(update_channel.name, ruleset_version_string);
      }
    }
  });
  e("aboutTitle").title = chrome.i18n.getMessage("about_title");
  e("add-rule-link").addEventListener("click", addManualRule);
  e("disable-on-this-site").addEventListener("click", disableOnSite);
  e("enable-on-this-site").addEventListener("click", enableOnSite);
});

var escapeForRegex = function( value ) {
  return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
};

function showEnableOrDisable(url, disabled) {
  if (["http:", "https:", "ftp:"].indexOf(url.protocol) != -1) {
    const disableLink = e("disable-on-this-site");
    const enableLink = e("enable-on-this-site");
    const addRuleSection = e("addRuleSection");
    const resetToDefaults = e('reset-to-defaults');
    if (disabled) {
      show(enableLink);
      hide(disableLink);
      hide(addRuleSection);
      hide(resetToDefaults);
    } else {
      show(disableLink);
      hide(enableLink);
    }
  } else {
    const disableEnableSection = e("disableEnableSection");
    hide(disableEnableSection);
  }
}

/**
 * Handles the manual addition of rules
 */
function addManualRule() {
  getTab(function(tab) {
    hide(e("add-rule-link"));
    show(e("add-new-rule-div"));

    const url = new URL(tab.url);

    e("new-rule-host").value = url.host;

    const escapedHost = escapeForRegex(url.host);

    e("new-rule-regex").value = `^http://${escapedHost}/`;
    e("new-rule-redirect").value = `https://${url.host}/`;
    e("new-rule-name").value = "Manual rule for " + url.host;

    e("add-new-rule-button").addEventListener("click", function() {
      const params = {
        /**
         * FIXME: the current implementation forbide users setting custom
         * ruleset names...
         */
        name: e("new-rule-host").value,
        target : [e("new-rule-host").value],
        rule: [{ to: e("new-rule-redirect").value, from: e("new-rule-regex").value }],
        default_off: "user rule"
      };
      sendMessage("add_new_rule", params, function() {
        location.reload();
      });
    });

    e("cancel-new-rule").addEventListener("click", function() {
      show(e("add-rule-link"));
      hide(e("add-new-rule-div"));
    });

    e("new-rule-show-advanced-link").addEventListener("click", function() {
      show(e("new-rule-advanced"));
      hide(e("new-rule-regular-text"));
    });

    e("new-rule-hide-advanced-link").addEventListener("click", function() {
      hide(e("new-rule-advanced"));
      show(e("new-rule-regular-text"));
    });
  });
}

/**
 * Disable HTTPS Everywhere on a particular FQDN
 */
function disableOnSite() {
  getTab(function(tab) {
    const url = new URL(tab.url);
    sendMessage("disable_on_site", url.host);
    chrome.tabs.reload(tab.id);
    window.close();
  });
}

function enableOnSite() {
  getTab(function(tab) {
    const url = new URL(tab.url);
    sendMessage("enable_on_site", url.host);
    chrome.tabs.reload(tab.id);
    window.close();
  });
}

/**
 * @description Turns EASE Mode on and off
 */
function toggleHttpNowhere() {
  getTab(tab => {
    getOption_('httpNowhere', false, item => {
      const enabled = !item.httpNowhere;
      setOption_('httpNowhere', enabled, () => {
        if (enabled) {
          chrome.tabs.reload(tab.id);
          e('HttpNowhere__header').innerText = 'Encrypt All Sites Eligible is ON';
          e('HttpNowhere__explained').innerText = 'Unencrypted requests are currently blocked';
        } else {
          e('HttpNowhere__header').innerText = 'Encrypt All Sites Eligible is OFF';
          e('HttpNowhere__explained').innerText = 'Unencrypted requests are currently allowed';
        }
      });
    });
  });
}

function getTab(callback) {
  let url = new URL(window.location.href);
  if (url.searchParams.has('tabId')) {
    let parentId = Number(url.searchParams.get('tabId'));
    return chrome.tabs.get(parentId, callback);
  }
  chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => callback(tabs[0]));
}

// This code fixes a Chromium-specific bug that causes links in extension popup
// to open in regular tab even if the popup is opened in incognito mode.

document.addEventListener('click', e => {
  const { target } = e

  if (target.matches('a[target="_blank"]')) {
    chrome.tabs.create({ url: target.href })
    e.preventDefault()
  }
})
