/* 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/. */
"use strict";

/* global gTelemetry */

// React
const {
  createFactory,
  Component,
} = require("resource://devtools/client/shared/vendor/react.js");
const {
  div,
  hr,
  span,
} = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
const {
  L10N,
} = require("resource://devtools/client/accessibility/utils/l10n.js");

loader.lazyGetter(this, "MenuButton", function () {
  return createFactory(
    require("resource://devtools/client/shared/components/menu/MenuButton.js")
  );
});
loader.lazyGetter(this, "MenuItem", function () {
  return createFactory(
    require("resource://devtools/client/shared/components/menu/MenuItem.js")
  );
});
loader.lazyGetter(this, "MenuList", function () {
  return createFactory(
    require("resource://devtools/client/shared/components/menu/MenuList.js")
  );
});

const actions = require("resource://devtools/client/accessibility/actions/audit.js");

const {
  connect,
} = require("resource://devtools/client/shared/vendor/react-redux.js");
const {
  FILTERS,
} = require("resource://devtools/client/accessibility/constants.js");

const TELEMETRY_AUDIT_ACTIVATED = "devtools.accessibility.audit_activated";
const FILTER_LABELS = {
  [FILTERS.NONE]: "accessibility.filter.none",
  [FILTERS.ALL]: "accessibility.filter.all2",
  [FILTERS.CONTRAST]: "accessibility.filter.contrast",
  [FILTERS.KEYBOARD]: "accessibility.filter.keyboard",
  [FILTERS.TEXT_LABEL]: "accessibility.filter.textLabel",
};

class AccessibilityTreeFilter extends Component {
  static get propTypes() {
    return {
      auditing: PropTypes.array.isRequired,
      filters: PropTypes.object.isRequired,
      dispatch: PropTypes.func.isRequired,
      describedby: PropTypes.string,
      toolboxDoc: PropTypes.object.isRequired,
      audit: PropTypes.func.isRequired,
    };
  }

  async toggleFilter(filterKey) {
    const { audit: auditFunc, dispatch, filters } = this.props;

    if (filterKey !== FILTERS.NONE && !filters[filterKey]) {
      if (gTelemetry) {
        gTelemetry.keyedScalarAdd(TELEMETRY_AUDIT_ACTIVATED, filterKey, 1);
      }

      dispatch(actions.auditing(filterKey));
      await dispatch(actions.audit(auditFunc, filterKey));
    }

    // We wait to dispatch filter toggle until the tree is ready to be filtered
    // right after the audit. This is to make sure that we render an empty tree
    // (filtered) while the audit is running.
    dispatch(actions.filterToggle(filterKey));
  }

  onClick(filterKey) {
    this.toggleFilter(filterKey);
  }

  render() {
    const { auditing, filters, describedby, toolboxDoc } = this.props;
    const toolbarLabelID = "accessibility-tree-filters-label";
    const filterNoneChecked = !Object.values(filters).includes(true);
    const items = [
      MenuItem({
        key: FILTERS.NONE,
        checked: filterNoneChecked,
        className: `filter ${FILTERS.NONE}`,
        label: L10N.getStr(FILTER_LABELS[FILTERS.NONE]),
        onClick: this.onClick.bind(this, FILTERS.NONE),
        disabled: !!auditing.length,
      }),
      hr({ key: "hr-1" }),
    ];

    const { [FILTERS.ALL]: filterAllChecked, ...filtersWithoutAll } = filters;
    items.push(
      MenuItem({
        key: FILTERS.ALL,
        checked: filterAllChecked,
        className: `filter ${FILTERS.ALL}`,
        label: L10N.getStr(FILTER_LABELS[FILTERS.ALL]),
        onClick: this.onClick.bind(this, FILTERS.ALL),
        disabled: !!auditing.length,
      }),
      hr({ key: "hr-2" }),
      Object.entries(filtersWithoutAll).map(([filterKey, active]) =>
        MenuItem({
          key: filterKey,
          checked: active,
          className: `filter ${filterKey}`,
          label: L10N.getStr(FILTER_LABELS[filterKey]),
          onClick: this.onClick.bind(this, filterKey),
          disabled: !!auditing.length,
        })
      )
    );

    let label;
    if (filterNoneChecked) {
      label = L10N.getStr(FILTER_LABELS[FILTERS.NONE]);
    } else if (filterAllChecked) {
      label = L10N.getStr(FILTER_LABELS[FILTERS.ALL]);
    } else {
      label = Object.keys(filtersWithoutAll)
        .filter(filterKey => filtersWithoutAll[filterKey])
        .map(filterKey => L10N.getStr(FILTER_LABELS[filterKey]))
        .join(", ");
    }

    return div(
      {
        role: "group",
        className: "accessibility-tree-filters",
        "aria-labelledby": toolbarLabelID,
        "aria-describedby": describedby,
      },
      span(
        { id: toolbarLabelID, role: "presentation" },
        L10N.getStr("accessibility.tree.filters")
      ),
      MenuButton(
        {
          menuId: "accessibility-tree-filters-menu",
          toolboxDoc,
          className: `devtools-button badge toolbar-menu-button filters`,
          label,
        },
        MenuList({}, items)
      )
    );
  }
}

const mapStateToProps = ({ audit: { filters, auditing } }) => {
  return { filters, auditing };
};

// Exports from this module
module.exports = connect(mapStateToProps)(AccessibilityTreeFilter);
