/*
 * This file is part of Adblock Plus <http://adblockplus.org/>,
 * Copyright (C) 2006-2013 Eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

window.OPTIONS_INITIALIZED = false;
window.SLIDERS_DONE = false;

const TOOLTIP_CONF = {
  maxWidth: 400
};
const USER_DATA_EXPORT_KEYS = ["action_map", "snitch_map", "settings_map"];

let i18n = chrome.i18n;

let constants = require("constants");
let { getOriginsArray } = require("optionslib");
let htmlUtils = require("htmlutils").htmlUtils;
let utils = require("utils");

let OPTIONS_DATA = {};

/*
 * Loads options from pb storage and sets UI elements accordingly.
 */
function loadOptions() {
  // Set page title to i18n version of "Privacy Badger Options"
  document.title = i18n.getMessage("options_title");

  // Add event listeners
  $("#allowlist-form").on("submit", addDisabledSite);
  $("#remove-disabled-site").on("click", removeDisabledSite);
  $("#cloud-upload").on("click", uploadCloud);
  $("#cloud-download").on("click", downloadCloud);
  $('#importTrackerButton').on("click", loadFileChooser);
  $('#importTrackers').on("change", importTrackerList);
  $('#exportTrackers').on("click", exportUserData);
  $('#resetData').on("click", resetData);
  $('#removeAllData').on("click", removeAllData);

  if (OPTIONS_DATA.settings.showTrackingDomains) {
    $('#tracking-domains-overlay').hide();
  } else {
    $('#blockedResourcesContainer').hide();

    $('#show-tracking-domains-checkbox').on("click", () => {
      $('#tracking-domains-overlay').hide();
      $('#blockedResourcesContainer').show();
      chrome.runtime.sendMessage({
        type: "updateSettings",
        data: {
          showTrackingDomains: true
        }
      });
    });
  }

  // Set up input for searching through tracking domains.
  $("#trackingDomainSearch").on("input", filterTrackingDomains);
  $("#tracking-domains-type-filter").on("change", filterTrackingDomains);
  $("#tracking-domains-status-filter").on("change", filterTrackingDomains);
  $("#tracking-domains-show-not-yet-blocked").on("change", filterTrackingDomains);

  // Add event listeners for origins container.
  $('#blockedResourcesContainer').on('change', 'input:radio', function () {
    let $radio = $(this),
      $clicker = $radio.parents('.clicker').first(),
      origin = $clicker.data('origin'),
      action = $radio.val();

    // update domain slider row tooltip/status indicators
    updateOrigin(origin, action, true);

    // persist the change
    saveToggle(origin, action);
  });
  $('#blockedResourcesContainer').on('click', '.userset .honeybadgerPowered', revertDomainControl);
  $('#blockedResourcesContainer').on('click', '.removeOrigin', removeOrigin);

  // Display jQuery UI elements
  $("#tabs").tabs({
    activate: function (event, ui) {
      // update options page URL fragment identifier
      // to preserve selected tab on page reload
      history.replaceState(null, null, "#" + ui.newPanel.attr('id'));
    }
  });
  $("button").button();
  $("#add-disabled-site").button("option", "icons", {primary: "ui-icon-plus"});
  $("#remove-disabled-site").button("option", "icons", {primary: "ui-icon-minus"});
  $("#cloud-upload").button("option", "icons", {primary: "ui-icon-arrowreturnthick-1-n"});
  $("#cloud-download").button("option", "icons", {primary: "ui-icon-arrowreturnthick-1-s"});
  $(".importButton").button("option", "icons", {primary: "ui-icon-plus"});
  $("#exportTrackers").button("option", "icons", {primary: "ui-icon-extlink"});
  $("#resetData").button("option", "icons", {primary: "ui-icon-arrowrefresh-1-w"});
  $("#removeAllData").button("option", "icons", {primary: "ui-icon-closethick"});
  $("#show_counter_checkbox").on("click", updateShowCounter);
  $("#show_counter_checkbox").prop("checked", OPTIONS_DATA.settings.showCounter);
  $("#replace-widgets-checkbox")
    .on("click", updateWidgetReplacement)
    .prop("checked", OPTIONS_DATA.isWidgetReplacementEnabled);
  $("#enable_dnt_checkbox").on("click", updateDNTCheckboxClicked);
  $("#enable_dnt_checkbox").prop("checked", OPTIONS_DATA.settings.sendDNTSignal);
  $("#check_dnt_policy_checkbox").on("click", updateCheckingDNTPolicy);
  $("#check_dnt_policy_checkbox").prop("checked", OPTIONS_DATA.settings.checkForDNTPolicy).prop("disabled", !OPTIONS_DATA.settings.sendDNTSignal);

  // only show the alternateErrorPagesEnabled override if browser supports it
  if (chrome.privacy && chrome.privacy.services && chrome.privacy.services.alternateErrorPagesEnabled) {
    $("#privacy-settings-header").show();
    $("#disable-google-nav-error-service").show();
    $('#disable-google-nav-error-service-checkbox')
      .prop("checked", OPTIONS_DATA.settings.disableGoogleNavErrorService)
      .on("click", overrideAlternateErrorPagesSetting);
  }

  // only show the hyperlinkAuditingEnabled override if browser supports it
  if (chrome.privacy && chrome.privacy.websites && chrome.privacy.websites.hyperlinkAuditingEnabled) {
    $("#privacy-settings-header").show();
    $("#disable-hyperlink-auditing").show();
    $("#disable-hyperlink-auditing-checkbox")
      .prop("checked", OPTIONS_DATA.settings.disableHyperlinkAuditing)
      .on("click", overrideHyperlinkAuditingSetting);
  }

  if (OPTIONS_DATA.webRTCAvailable) {
    $("#webRTCToggle").show();
    $("#toggle_webrtc_mode").on("click", toggleWebRTCIPProtection);

    chrome.privacy.network.webRTCIPHandlingPolicy.get({}, result => {
      // auto check the option box if ip leak is already protected at diff levels, via pb or another extension
      if (result.value == "default_public_interface_only" || result.value == "disable_non_proxied_udp") {
        $("#toggle_webrtc_mode").prop("checked", true);
      }
    });
  }

  $('#local-learning-checkbox')
    .prop("checked", OPTIONS_DATA.settings.learnLocally)
    .on("click", (event) => {
      const enabled = $(event.currentTarget).prop("checked");
      chrome.runtime.sendMessage({
        type: "updateSettings",
        data: {
          learnLocally: enabled
        }
      }, function () {
        $("#learn-in-incognito-checkbox")
          .prop("disabled", (enabled ? false : "disabled"))
          .prop("checked", (enabled ? OPTIONS_DATA.settings.learnInIncognito : false));
        $("#show-nontracking-domains-checkbox")
          .prop("disabled", (enabled ? false : "disabled"))
          .prop("checked", (enabled ? OPTIONS_DATA.settings.showNonTrackingDomains : false));

        $("#learning-setting-divs").slideToggle(enabled);
        $("#not-yet-blocked-filter").toggle(enabled);
      });
    });
  if (OPTIONS_DATA.settings.learnLocally) {
    $("#learning-setting-divs").show();
    $("#not-yet-blocked-filter").show();
  }

  $("#learn-in-incognito-checkbox")
    .prop("disabled", OPTIONS_DATA.settings.learnLocally ? false : "disabled")
    .prop("checked", (
      OPTIONS_DATA.settings.learnLocally ?
        OPTIONS_DATA.settings.learnInIncognito : false
    ))
    .on("click", (event) => {
      const enabled = $(event.currentTarget).prop("checked");
      chrome.runtime.sendMessage({
        type: "updateSettings",
        data: {
          learnInIncognito: enabled
        }
      }, function () {
        OPTIONS_DATA.settings.learnInIncognito = enabled;
      });
    });

  $('#show-nontracking-domains-checkbox')
    .prop("disabled", OPTIONS_DATA.settings.learnLocally ? false : "disabled")
    .prop("checked", (
      OPTIONS_DATA.settings.learnLocally ?
        OPTIONS_DATA.settings.showNonTrackingDomains : false
    ))
    .on("click", (event) => {
      const enabled = $(event.currentTarget).prop("checked");
      chrome.runtime.sendMessage({
        type: "updateSettings",
        data: {
          showNonTrackingDomains: enabled
        }
      }, function () {
        OPTIONS_DATA.settings.showNonTrackingDomains = enabled;
      });
    });

  const widgetSelector = $("#hide-widgets-select");
  widgetSelector.prop("disabled",
    OPTIONS_DATA.isWidgetReplacementEnabled ? false : "disabled");

  $("#replace-widgets-checkbox").change(function () {
    if ($(this).is(":checked")) {
      widgetSelector.prop("disabled", false);
    } else {
      widgetSelector.prop("disabled", "disabled");
    }
  });

  // Initialize Select2 and populate options
  widgetSelector.select2();
  OPTIONS_DATA.widgets.forEach(function (key) {
    const isSelected = OPTIONS_DATA.settings.widgetReplacementExceptions.includes(key);
    const option = new Option(key, key, false, isSelected);
    widgetSelector.append(option).trigger("change");
  });

  widgetSelector.on('select2:select', updateWidgetReplacementExceptions);
  widgetSelector.on('select2:unselect', updateWidgetReplacementExceptions);
  widgetSelector.on('select2:clear', updateWidgetReplacementExceptions);

  reloadDisabledSites();
  reloadTrackingDomainsTab();

  $('html').css({
    overflow: 'visible',
    visibility: 'visible'
  });

  window.OPTIONS_INITIALIZED = true;
}

/**
 * Opens the file chooser to allow a user to select
 * a file to import.
 */
function loadFileChooser() {
  var fileChooser = document.getElementById('importTrackers');
  fileChooser.click();
}

/**
 * Import a list of trackers supplied by the user
 * NOTE: list must be in JSON format to be parsable
 */
function importTrackerList() {
  var file = this.files[0];

  if (file) {
    var reader = new FileReader();
    reader.readAsText(file);
    reader.onload = function(e) {
      parseUserDataFile(e.target.result);
    };
  } else {
    var selectFile = i18n.getMessage("import_select_file");
    confirm(selectFile);
  }

  document.getElementById("importTrackers").value = '';
}

/**
 * Parses Privacy Badger data uploaded by the user.
 *
 * @param {String} storageMapsList data from JSON file that user provided
 */
function parseUserDataFile(storageMapsList) {
  let lists;

  try {
    lists = JSON.parse(storageMapsList);
  } catch (e) {
    return confirm(i18n.getMessage("invalid_json"));
  }

  // validate by checking we have the same keys in the import as in the export
  if (!_.isEqual(
    Object.keys(lists).sort(),
    USER_DATA_EXPORT_KEYS.sort()
  )) {
    return confirm(i18n.getMessage("invalid_json"));
  }

  // check for webrtc setting in the imported settings map
  if (lists.settings_map.preventWebRTCIPLeak) {
    // verify that the user hasn't already enabled this option
    if (!$("#toggle_webrtc_mode").prop("checked")) {
      toggleWebRTCIPProtection();
    }
    // this browser-controlled setting doesn't belong in Badger's settings object
    delete lists.settings_map.preventWebRTCIPLeak;
  }

  chrome.runtime.sendMessage({
    type: "mergeUserData",
    data: lists
  }, (response) => {
    OPTIONS_DATA.settings.disabledSites = response.disabledSites;
    OPTIONS_DATA.origins = response.origins;

    reloadDisabledSites();
    reloadTrackingDomainsTab();
    // TODO general settings are not updated

    confirm(i18n.getMessage("import_successful"));
  });
}

function resetData() {
  var resetWarn = i18n.getMessage("reset_data_confirm");
  if (confirm(resetWarn)) {
    chrome.runtime.sendMessage({type: "resetData"}, () => {
      // reload page to refresh tracker list
      location.reload();
    });
  }
}

function removeAllData() {
  var removeWarn = i18n.getMessage("remove_all_data_confirm");
  if (confirm(removeWarn)) {
    chrome.runtime.sendMessage({type: "removeAllData"}, () => {
      location.reload();
    });
  }
}

function downloadCloud() {
  chrome.runtime.sendMessage({type: "downloadCloud"},
    function (response) {
      if (response.success) {
        alert(i18n.getMessage("download_cloud_success"));
        OPTIONS_DATA.settings.disabledSites = response.disabledSites;
        reloadDisabledSites();
      } else {
        console.error("Cloud sync error:", response.message);
        if (response.message === i18n.getMessage("download_cloud_no_data")) {
          alert(response.message);
        } else {
          alert(i18n.getMessage("download_cloud_failure"));
        }
      }
    }
  );
}

function uploadCloud() {
  chrome.runtime.sendMessage({type: "uploadCloud"},
    function (status) {
      if (status.success) {
        alert(i18n.getMessage("upload_cloud_success"));
      } else {
        console.error("Cloud sync error:", status.message);
        alert(i18n.getMessage("upload_cloud_failure"));
      }
    }
  );
}

/**
 * Export the user's data, including their list of trackers from
 * action_map and snitch_map, along with their settings.
 * List will be in JSON format that can be edited and reimported
 * in another instance of Privacy Badger.
 */
function exportUserData() {
  chrome.storage.local.get(USER_DATA_EXPORT_KEYS, function (maps) {

    // exports the user's prevent webrtc leak setting if it's checked
    if ($("#toggle_webrtc_mode").prop("checked")) {
      maps.settings_map.preventWebRTCIPLeak = true;
    }

    let mapJSON = JSON.stringify(maps);

    // Append the formatted date to the exported file name
    let currDate = new Date().toLocaleString();
    let escapedDate = currDate
      // illegal filename charset regex from
      // https://github.com/parshap/node-sanitize-filename/blob/ef1e8ad58e95eb90f8a01f209edf55cd4176e9c8/index.js
      .replace(/[\/\?<>\\:\*\|"]/g, '_') /* eslint no-useless-escape:off */
      // also collapse-replace commas and spaces
      .replace(/[, ]+/g, '_');
    let filename = 'PrivacyBadger_user_data-' + escapedDate + '.json';

    // Download workaround taken from uBlock Origin
    // https://github.com/gorhill/uBlock/blob/40a85f8c04840ae5f5875c1e8b5fa17578c5bd1a/platform/chromium/vapi-common.js
    let a = document.createElement('a');
    a.setAttribute('download', filename || '');

    let blob = new Blob([mapJSON], { type: 'application/json' }); // pass a useful mime type here
    a.href = URL.createObjectURL(blob);

    function clickBlobLink() {
      a.dispatchEvent(new MouseEvent('click'));
      URL.revokeObjectURL(blob);
    }

    /**
     * Firefox workaround to insert the blob link in an iFrame
     * https://bugzilla.mozilla.org/show_bug.cgi?id=1420419#c18
     */
    function addBlobWorkAroundForFirefox() {
      // Create or use existing iframe for the blob 'a' element
      let iframe = document.getElementById('exportUserDataIframe');
      if (!iframe) {
        iframe = document.createElement('iframe');
        iframe.id = "exportUserDataIframe";
        iframe.setAttribute("style", "visibility: hidden; height: 0; width: 0");
        document.getElementById('export').appendChild(iframe);

        iframe.contentWindow.document.open();
        iframe.contentWindow.document.write('<html><head></head><body></body></html>');
        iframe.contentWindow.document.close();
      } else {
        // Remove the old 'a' element from the iframe
        let oldElement = iframe.contentWindow.document.body.lastChild;
        iframe.contentWindow.document.body.removeChild(oldElement);
      }
      iframe.contentWindow.document.body.appendChild(a);
    }

    // TODO remove browser check and simplify code once Firefox 58 goes away
    // https://bugzilla.mozilla.org/show_bug.cgi?id=1420419
    if (chrome.runtime.getBrowserInfo) {
      chrome.runtime.getBrowserInfo((info) => {
        if (info.name == "Firefox" || info.name == "Waterfox") {
          addBlobWorkAroundForFirefox();
        }
        clickBlobLink();
      });
    } else {
      clickBlobLink();
    }
  });
}

/**
 * Update setting for whether or not to show counter on Privacy Badger badge.
 */
function updateShowCounter() {
  const showCounter = $("#show_counter_checkbox").prop("checked");

  chrome.runtime.sendMessage({
    type: "updateSettings",
    data: { showCounter }
  }, () => {
    // Refresh display for each tab's PB badge.
    chrome.tabs.query({}, function(tabs) {
      tabs.forEach(function(tab) {
        chrome.runtime.sendMessage({
          type: "updateBadge",
          tab_id: tab.id
        });
      });
    });
  });
}

/**
 * Update setting for whether or not to replace
 * social buttons/video players/commenting widgets.
 */
function updateWidgetReplacement() {
  const socialWidgetReplacementEnabled = $("#replace-widgets-checkbox").prop("checked");

  chrome.runtime.sendMessage({
    type: "updateSettings",
    data: { socialWidgetReplacementEnabled }
  });
}

/**
 * Update DNT checkbox clicked
 */
function updateDNTCheckboxClicked() {
  const enabled = $("#enable_dnt_checkbox").prop("checked");

  chrome.runtime.sendMessage({
    type: "updateSettings",
    data: {
      sendDNTSignal: enabled
    }
  });

  $("#check_dnt_policy_checkbox").prop("checked", enabled).prop("disabled", !enabled);
  updateCheckingDNTPolicy();
}

function updateCheckingDNTPolicy() {
  const enabled = $("#check_dnt_policy_checkbox").prop("checked");

  chrome.runtime.sendMessage({
    type: "updateSettings",
    data: {
      checkForDNTPolicy: enabled
    }
  });
}

function reloadDisabledSites() {
  let sites = OPTIONS_DATA.settings.disabledSites,
    $select = $('#allowlist-select');

  // sort disabled sites the same way blocked sites are sorted
  sites = htmlUtils.sortDomains(sites);

  $select.empty();
  for (let i = 0; i < sites.length; i++) {
    $('<option>').text(sites[i]).appendTo($select);
  }
}

function addDisabledSite(event) {
  event.preventDefault();

  let domain = utils.getHostFromDomainInput(
    document.getElementById("new-disabled-site-input").value.replace(/\s/g, "")
  );

  if (!domain) {
    return confirm(i18n.getMessage("invalid_domain"));
  }

  chrome.runtime.sendMessage({
    type: "disablePrivacyBadgerForOrigin",
    domain
  }, (response) => {
    OPTIONS_DATA.settings.disabledSites = response.disabledSites;
    reloadDisabledSites();
    document.getElementById("new-disabled-site-input").value = "";
  });
}

function removeDisabledSite(event) {
  event.preventDefault();

  let domains = [];
  let $selected = $("#allowlist-select option:selected");
  for (let i = 0; i < $selected.length; i++) {
    domains.push($selected[i].text);
  }

  chrome.runtime.sendMessage({
    type: "enablePrivacyBadgerForOriginList",
    domains
  }, (response) => {
    OPTIONS_DATA.settings.disabledSites = response.disabledSites;
    reloadDisabledSites();
  });
}

// Tracking Domains slider functions

/**
 * Gets action for given origin.
 * @param {String} origin - Origin to get action for.
 */
function getOriginAction(origin) {
  return OPTIONS_DATA.origins[origin];
}

function revertDomainControl(event) {
  event.preventDefault();

  let origin = $(event.target).parent().data('origin');

  chrome.runtime.sendMessage({
    type: "revertDomainControl",
    origin
  }, (response) => {
    // update any sliders that changed as a result
    updateSliders(response.origins);
    // update cached domain data
    OPTIONS_DATA.origins = response.origins;
  });
}

/**
 * Displays list of all tracking domains along with toggle controls.
 */
function updateSummary() {
  // if there are no tracking domains
  let allTrackingDomains = Object.keys(OPTIONS_DATA.origins);
  if (!allTrackingDomains || !allTrackingDomains.length) {
    // hide the number of trackers and slider instructions message
    $("#options_domain_list_trackers").hide();

    // show "no trackers" message
    $("#options_domain_list_no_trackers").show();
    $("#blockedResources").html('');
    $("#tracking-domains-div").hide();

    // activate tooltips
    $('.tooltip:not(.tooltipstered)').tooltipster(TOOLTIP_CONF);

    return;
  }

  // reloadTrackingDomainsTab can be called multiple times, needs to be reversible
  $("#options_domain_list_no_trackers").hide();
  $("#tracking-domains-div").show();

  // count unique (cookie)blocked tracking base domains
  let blockedDomains = getOriginsArray(OPTIONS_DATA.origins, null, null, null, false);
  let baseDomains = new Set(blockedDomains.map(d => window.getBaseDomain(d)));
  $("#options_domain_list_trackers").html(i18n.getMessage(
    "options_domain_list_trackers", [
      baseDomains.size,
      "<a target='_blank' title='" + _.escape(i18n.getMessage("what_is_a_tracker")) + "' class='tooltip' href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
    ]
  )).show();
}

/**
 * Displays list of all tracking domains along with toggle controls.
 */
function reloadTrackingDomainsTab() {
  updateSummary();

  // Get containing HTML for domain list along with toggle legend icons.
  $("#blockedResources")[0].innerHTML = htmlUtils.getTrackerContainerHtml();

  // activate tooltips
  $('.tooltip:not(.tooltipstered)').tooltipster(TOOLTIP_CONF);

  // Display tracking domains.
  showTrackingDomains(
    getOriginsArray(
      OPTIONS_DATA.origins,
      $("#trackingDomainSearch").val(),
      $('#tracking-domains-type-filter').val(),
      $('#tracking-domains-status-filter').val(),
      $('#tracking-domains-show-not-yet-blocked').prop('checked')
    )
  );
}

/**
 * Displays filtered list of tracking domains based on user input.
 */
function filterTrackingDomains() {
  const $searchFilter = $('#trackingDomainSearch'),
    $typeFilter = $('#tracking-domains-type-filter'),
    $statusFilter = $('#tracking-domains-status-filter');

  if ($typeFilter.val() == "dnt") {
    $statusFilter.prop("disabled", true).val("");
  } else {
    $statusFilter.prop("disabled", false);
  }

  let search_update = (this == $searchFilter[0]),
    initial_search_text = $searchFilter.val().toLowerCase(),
    time_to_wait = 0,
    callback = function () {};

  // If we are here because the search filter got updated,
  // wait a short period of time and see if search text has changed.
  // If so it means user is still typing so hold off on filtering.
  if (search_update) {
    time_to_wait = 500;
    callback = function () {
      $searchFilter.focus();
    };
  }

  setTimeout(function () {
    // check search text
    let search_text = $searchFilter.val().toLowerCase();
    if (search_text != initial_search_text) {
      return;
    }

    // show filtered origins
    let filteredOrigins = getOriginsArray(
      OPTIONS_DATA.origins,
      search_text,
      $typeFilter.val(),
      $statusFilter.val(),
      $('#tracking-domains-show-not-yet-blocked').prop('checked')
    );
    showTrackingDomains(filteredOrigins, callback);

  }, time_to_wait);
}

/**
 * Renders the list of tracking domains.
 *
 * @param {Array} domains
 * @param {Function} cb callback
 */
function showTrackingDomains(domains, cb) {
  if (!cb) {
    cb = function () {};
  }

  window.SLIDERS_DONE = false;
  $('#tracking-domains-div').css('visibility', 'hidden');
  $('#tracking-domains-loader').show();

  domains = htmlUtils.sortDomains(domains);

  let out = [];
  for (let domain of domains) {
    let action = getOriginAction(domain);
    if (action) {
      let show_breakage_warning = (
        action == constants.USER_BLOCK &&
        OPTIONS_DATA.cookieblocked.hasOwnProperty(domain)
      );
      out.push(htmlUtils.getOriginHtml(domain, action, show_breakage_warning));
    }
  }

  function renderDomains() {
    const CHUNK = 100;

    let $printable = $(out.splice(0, CHUNK).join(""));

    $printable.appendTo('#blockedResourcesInner');

    // activate tooltips
    // TODO disabled for performance reasons
    //$('#blockedResourcesInner .tooltip:not(.tooltipstered)').tooltipster(
    //  htmlUtils.DOMAIN_TOOLTIP_CONF);

    if (out.length) {
      requestAnimationFrame(renderDomains);
    } else {
      $('#tracking-domains-loader').hide();
      $('#tracking-domains-div').css('visibility', 'visible');
      window.SLIDERS_DONE = true;
      cb();
    }
  }

  $('#blockedResourcesInner').empty();

  if (out.length) {
    requestAnimationFrame(renderDomains);
  } else {
    $('#tracking-domains-loader').hide();
    $('#tracking-domains-div').css('visibility', 'visible');
    window.SLIDERS_DONE = true;
    cb();
  }
}

/**
 * https://tools.ietf.org/html/draft-ietf-rtcweb-ip-handling-01#page-5
 *
 * Toggle WebRTC IP address leak protection setting.
 *
 * When enabled, policy is set to Mode 3 (default_public_interface_only).
 */
function toggleWebRTCIPProtection() {
  // Return early with non-supporting browsers
  if (!OPTIONS_DATA.webRTCAvailable) {
    return;
  }

  let cpn = chrome.privacy.network;

  cpn.webRTCIPHandlingPolicy.get({}, function (result) {
    // Update new value to be opposite of current browser setting
    if (result.value == 'default_public_interface_only') {
      cpn.webRTCIPHandlingPolicy.clear({});
    } else {
      cpn.webRTCIPHandlingPolicy.set({
        value: 'default_public_interface_only'
      });
    }
  });
}

// handles overriding the alternateErrorPagesEnabled setting
function overrideAlternateErrorPagesSetting() {
  const checked = $("#disable-google-nav-error-service-checkbox").prop("checked");

  // update Badger settings so that we know to reapply the browser setting on startup
  chrome.runtime.sendMessage({
    type: "updateSettings",
    data: {
      disableGoogleNavErrorService: checked
    }
  });

  // update the browser setting
  if (checked) {
    chrome.privacy.services.alternateErrorPagesEnabled.set({
      value: false
    });
  } else {
    chrome.privacy.services.alternateErrorPagesEnabled.clear({});
  }
}

// handles overriding the hyperlinkAuditingEnabled setting
function overrideHyperlinkAuditingSetting() {
  const checked = $("#disable-hyperlink-auditing-checkbox").prop("checked");

  // update Badger settings so that we know to reapply the browser setting on startup
  chrome.runtime.sendMessage({
    type: "updateSettings",
    data: {
      disableHyperlinkAuditing: checked
    }
  });

  // update the browser setting
  if (checked) {
    chrome.privacy.websites.hyperlinkAuditingEnabled.set({
      value: false
    });
  } else {
    chrome.privacy.websites.hyperlinkAuditingEnabled.clear({});
  }
}

/**
 * Updates domain tooltip, slider color.
 * Also toggles status indicators like breakage warnings.
 */
function updateOrigin(origin, action, userset) {
  let $clicker = $('#blockedResourcesInner div.clicker[data-origin="' + origin + '"]'),
    $switchContainer = $clicker.find('.switch-container').first();

  // update slider color via CSS
  $switchContainer.removeClass([
    constants.BLOCK,
    constants.COOKIEBLOCK,
    constants.ALLOW,
    constants.NO_TRACKING].join(" ")).addClass(action);

  let show_breakage_warning = (
    action == constants.BLOCK &&
    OPTIONS_DATA.cookieblocked.hasOwnProperty(origin)
  );

  htmlUtils.toggleBlockedStatus($clicker, userset, show_breakage_warning);

  // reinitialize the domain tooltip
  // TODO disabled for performance reasons
  //$clicker.find('.origin-inner').tooltipster('destroy');
  //$clicker.find('.origin-inner').attr(
  //  'title', htmlUtils.getActionDescription(action, origin));
  //$clicker.find('.origin-inner').tooltipster(htmlUtils.DOMAIN_TOOLTIP_CONF);
}

/**
 * Updates the list of tracking domains in response to user actions.
 *
 * For example, moving the slider for example.com should move the sliders
 * for www.example.com and cdn.example.com
 */
function updateSliders(updatedOriginData) {
  let updated_domains = Object.keys(updatedOriginData);

  // update any sliders that changed
  for (let domain of updated_domains) {
    let action = updatedOriginData[domain];
    if (action == OPTIONS_DATA.origins[domain]) {
      continue;
    }

    let userset = false;
    if (action.startsWith('user')) {
      userset = true;
      action = action.slice(5);
    }

    // update slider position
    let $radios = $('#blockedResourcesInner div.clicker[data-origin="' + domain + '"] input'),
      selected_val = (action == constants.DNT ? constants.ALLOW : action);
    // update the radio group without triggering a change event
    // https://stackoverflow.com/a/22635728
    $radios.val([selected_val]);

    // update domain slider row tooltip/status indicators
    updateOrigin(domain, action, userset);
  }

  // remove sliders that are no longer present
  let removed = Object.keys(OPTIONS_DATA.origins).filter(
    x => !updated_domains.includes(x));
  for (let domain of removed) {
    let $clicker = $('#blockedResourcesInner div.clicker[data-origin="' + domain + '"]');
    $clicker.remove();
  }
}

/**
 * Save the user setting for a domain by messaging the background page.
 */
function saveToggle(origin, action) {
  chrome.runtime.sendMessage({
    type: "saveOptionsToggle",
    origin,
    action
  }, (response) => {
    // first update the cache for the slider
    // that was just changed by the user
    // to avoid redundantly updating it below
    OPTIONS_DATA.origins[origin] = response.origins[origin];
    // update any sliders that changed as a result
    updateSliders(response.origins);
    // update cached domain data
    OPTIONS_DATA.origins = response.origins;
  });
}

/**
 * Remove origin from Privacy Badger.
 * @param {Event} event Click event triggered by user.
 */
function removeOrigin(event) {
  event.preventDefault();

  // confirm removal before proceeding
  if (!confirm(i18n.getMessage("options_remove_origin_confirm"))) {
    return;
  }

  let origin = $(event.target).parent().data('origin');

  chrome.runtime.sendMessage({
    type: "removeOrigin",
    origin
  }, (response) => {
    // remove rows that are no longer here
    updateSliders(response.origins);
    // update cached domain data
    OPTIONS_DATA.origins = response.origins;
    // if we removed domains, the summary text may have changed
    updateSummary();
  });
}

/**
 * Update which widgets should be blocked instead of replaced
 * @param {Event} event The DOM event triggered by selecting an option
 */
function updateWidgetReplacementExceptions() {
  const widgetReplacementExceptions = $('#hide-widgets-select').select2('data').map(({ id }) => id);
  chrome.runtime.sendMessage({
    type: "updateSettings",
    data: { widgetReplacementExceptions }
  });
}

$(function () {
  $.tooltipster.setDefaults(htmlUtils.TOOLTIPSTER_DEFAULTS);

  chrome.runtime.sendMessage({
    type: "getOptionsData",
  }, (response) => {
    OPTIONS_DATA = response;
    loadOptions();
  });
});
