"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.updateAllClasses = updateAllClasses;
exports.updateLastClasses = updateLastClasses;
exports.transformAllSelectors = transformAllSelectors;
exports.transformAllClasses = transformAllClasses;
exports.transformLastClasses = transformLastClasses;
exports.asValue = asValue;
exports.asUnit = asUnit;
exports.asList = asList;
exports.asColor = asColor;
exports.asAngle = asAngle;
exports.asLength = asLength;
exports.asLookupValue = asLookupValue;
exports.coerceValue = coerceValue;

var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));

var _postcss = _interopRequireDefault(require("postcss"));

var _color = _interopRequireDefault(require("color"));

var _escapeCommas = _interopRequireDefault(require("./escapeCommas"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function updateAllClasses(selectors, updateClass) {
  let parser = (0, _postcssSelectorParser.default)(selectors => {
    selectors.walkClasses(sel => {
      let updatedClass = updateClass(sel.value, {
        withPseudo(className, pseudo) {
          sel.parent.insertAfter(sel, _postcssSelectorParser.default.pseudo({
            value: `:${pseudo}`
          }));
          return className;
        }

      });
      sel.value = updatedClass;

      if (sel.raws && sel.raws.value) {
        sel.raws.value = (0, _escapeCommas.default)(sel.raws.value);
      }
    });
  });
  let result = parser.processSync(selectors);
  return result;
}

function updateLastClasses(selectors, updateClass) {
  let parser = (0, _postcssSelectorParser.default)(selectors => {
    selectors.each(sel => {
      let lastClass = sel.filter(({
        type
      }) => type === 'class').pop();

      if (lastClass === undefined) {
        return;
      }

      let updatedClass = updateClass(lastClass.value, {
        withPseudo(className, pseudo) {
          lastClass.parent.insertAfter(lastClass, _postcssSelectorParser.default.pseudo({
            value: `:${pseudo}`
          }));
          return className;
        }

      });
      lastClass.value = updatedClass;

      if (lastClass.raws && lastClass.raws.value) {
        lastClass.raws.value = (0, _escapeCommas.default)(lastClass.raws.value);
      }
    });
  });
  let result = parser.processSync(selectors);
  return result;
}

function transformAllSelectors(transformSelector, wrap = null) {
  return ({
    container
  }) => {
    container.walkRules(rule => {
      let transformed = rule.selector.split(',').map(transformSelector).join(',');
      rule.selector = transformed;
      return rule;
    });

    if (wrap) {
      let wrapper = wrap();
      wrapper.append(container.nodes);
      container.append(wrapper);
    }
  };
}

function transformAllClasses(transformClass) {
  return ({
    container
  }) => {
    container.walkRules(rule => {
      let selector = rule.selector;
      let variantSelector = updateAllClasses(selector, transformClass);
      rule.selector = variantSelector;
      return rule;
    });
  };
}

function transformLastClasses(transformClass, wrap = null) {
  return ({
    container
  }) => {
    container.walkRules(rule => {
      let selector = rule.selector;
      let variantSelector = updateLastClasses(selector, transformClass);
      rule.selector = variantSelector;
      return rule;
    });

    if (wrap) {
      let wrapper = wrap();
      wrapper.append(container.nodes);
      container.append(wrapper);
    }
  };
}

function asValue(modifier, lookup = {}, {
  validate = () => true,
  transform = v => v
} = {}) {
  let value = lookup[modifier];

  if (value !== undefined) {
    return value;
  }

  if (modifier[0] !== '[' || modifier[modifier.length - 1] !== ']') {
    return undefined;
  }

  value = modifier.slice(1, -1);

  if (!validate(value)) {
    return undefined;
  } // add spaces around operators inside calc() that do not follow an operator or (


  return transform(value).replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, '$1 $2 ');
}

function asUnit(modifier, units, lookup = {}) {
  return asValue(modifier, lookup, {
    validate: value => {
      let unitsPattern = `(?:${units.join('|')})`;
      return new RegExp(`${unitsPattern}$`).test(value) || new RegExp(`^calc\\(.+?${unitsPattern}`).test(value);
    },
    transform: value => {
      return value;
    }
  });
}

function asList(modifier, lookup = {}) {
  return asValue(modifier, lookup, {
    transform: value => {
      return _postcss.default.list.comma(value).map(v => v.replace(/,/g, ', ')).join(' ');
    }
  });
}

function asColor(modifier, lookup = {}) {
  return asValue(modifier, lookup, {
    validate: value => {
      try {
        (0, _color.default)(value);
        return true;
      } catch (e) {
        return false;
      }
    }
  });
}

function asAngle(modifier, lookup = {}) {
  return asUnit(modifier, ['deg', 'grad', 'rad', 'turn'], lookup);
}

function asLength(modifier, lookup = {}) {
  return asUnit(modifier, ['cm', 'mm', 'Q', 'in', 'pc', 'pt', 'px', 'em', 'ex', 'ch', 'rem', 'lh', 'vw', 'vh', 'vmin', 'vmax', '%'], lookup);
}

function asLookupValue(modifier, lookup = {}) {
  return lookup[modifier];
}

let typeMap = {
  any: asValue,
  list: asList,
  color: asColor,
  angle: asAngle,
  length: asLength,
  lookup: asLookupValue
};

function coerceValue(type, modifier, values) {
  return typeMap[type](modifier, values);
}