'use strict';

exports.name = 'removeAttrs';
exports.description = 'removes specified attributes';

const DEFAULT_SEPARATOR = ':';
const ENOATTRS = `Warning: The plugin "removeAttrs" requires the "attrs" parameter.
It should have a pattern to remove, otherwise the plugin is a noop.
Config example:

plugins: [
  {
    name: "removeAttrs",
    params: {
      attrs: "(fill|stroke)"
    }
  }
]
`;

/**
 * Remove attributes
 *
 * @example elemSeparator
 *   format: string
 *
 * @example preserveCurrentColor
 *   format: boolean
 *
 * @example attrs:
 *
 *   format: [ element* : attribute* : value* ]
 *
 *   element   : regexp (wrapped into ^...$), single * or omitted > all elements (must be present when value is used)
 *   attribute : regexp (wrapped into ^...$)
 *   value     : regexp (wrapped into ^...$), single * or omitted > all values
 *
 *   examples:
 *
 *     > basic: remove fill attribute
 *     ---
 *     removeAttrs:
 *       attrs: 'fill'
 *
 *     > remove fill attribute on path element
 *     ---
 *       attrs: 'path:fill'
 *
 *     > remove fill attribute on path element where value is none
 *     ---
 *       attrs: 'path:fill:none'
 *
 *
 *     > remove all fill and stroke attribute
 *     ---
 *       attrs:
 *         - 'fill'
 *         - 'stroke'
 *
 *     [is same as]
 *
 *       attrs: '(fill|stroke)'
 *
 *     [is same as]
 *
 *       attrs: '*:(fill|stroke)'
 *
 *     [is same as]
 *
 *       attrs: '.*:(fill|stroke)'
 *
 *     [is same as]
 *
 *       attrs: '.*:(fill|stroke):.*'
 *
 *
 *     > remove all stroke related attributes
 *     ----
 *     attrs: 'stroke.*'
 *
 *
 * @author Benny Schudel
 *
 * @type {import('./plugins-types').Plugin<'removeAttrs'>}
 */
exports.fn = (root, params) => {
  if (typeof params.attrs == 'undefined') {
    console.warn(ENOATTRS);
    return null;
  }

  const elemSeparator =
    typeof params.elemSeparator == 'string'
      ? params.elemSeparator
      : DEFAULT_SEPARATOR;
  const preserveCurrentColor =
    typeof params.preserveCurrentColor == 'boolean'
      ? params.preserveCurrentColor
      : false;
  const attrs = Array.isArray(params.attrs) ? params.attrs : [params.attrs];

  return {
    element: {
      enter: (node) => {
        for (let pattern of attrs) {
          // if no element separators (:), assume it's attribute name, and apply to all elements *regardless of value*
          if (!pattern.includes(elemSeparator)) {
            pattern = ['.*', pattern, '.*'].join(elemSeparator);
            // if only 1 separator, assume it's element and attribute name, and apply regardless of attribute value
          } else if (pattern.split(elemSeparator).length < 3) {
            pattern = [pattern, '.*'].join(elemSeparator);
          }

          // create regexps for element, attribute name, and attribute value
          const list = pattern.split(elemSeparator).map((value) => {
            // adjust single * to match anything
            if (value === '*') {
              value = '.*';
            }
            return new RegExp(['^', value, '$'].join(''), 'i');
          });

          // matches element
          if (list[0].test(node.name)) {
            // loop attributes
            for (const [name, value] of Object.entries(node.attributes)) {
              const isFillCurrentColor =
                preserveCurrentColor &&
                name == 'fill' &&
                value == 'currentColor';
              const isStrokeCurrentColor =
                preserveCurrentColor &&
                name == 'stroke' &&
                value == 'currentColor';
              if (
                !isFillCurrentColor &&
                !isStrokeCurrentColor &&
                // matches attribute name
                list[1].test(name) &&
                // matches attribute value
                list[2].test(value)
              ) {
                delete node.attributes[name];
              }
            }
          }
        }
      },
    },
  };
};
