'use strict';

var util = require('../../../../../zrender@6.0.0/node_modules/zrender/lib/core/util.js');
var log = require('./log.js');
var dataValueHelper = require('../data/helper/dataValueHelper.js');

;
var RELATIONAL_EXPRESSION_OP_ALIAS_MAP = {
  value: 'eq',
  // PENDING: not good for literal semantic?
  '<': 'lt',
  '<=': 'lte',
  '>': 'gt',
  '>=': 'gte',
  '=': 'eq',
  '!=': 'ne',
  '<>': 'ne'
  // Might be misleading for sake of the difference between '==' and '===',
  // so don't support them.
  // '==': 'eq',
  // '===': 'seq',
  // '!==': 'sne'
  // PENDING: Whether support some common alias "ge", "le", "neq"?
  // ge: 'gte',
  // le: 'lte',
  // neq: 'ne',
};
// type RelationalExpressionOpEvaluate = (tarVal: unknown, condVal: unknown) => boolean;
var RegExpEvaluator = /** @class */function () {
  function RegExpEvaluator(rVal) {
    // Support condVal: RegExp | string
    var condValue = this._condVal = util.isString(rVal) ? new RegExp(rVal) : util.isRegExp(rVal) ? rVal : null;
    if (condValue == null) {
      var errMsg = '';
      if (process.env.NODE_ENV !== 'production') {
        errMsg = log.makePrintable('Illegal regexp', rVal, 'in');
      }
      log.throwError(errMsg);
    }
  }
  RegExpEvaluator.prototype.evaluate = function (lVal) {
    var type = typeof lVal;
    return util.isString(type) ? this._condVal.test(lVal) : util.isNumber(type) ? this._condVal.test(lVal + '') : false;
  };
  return RegExpEvaluator;
}();
var ConstConditionInternal = /** @class */function () {
  function ConstConditionInternal() {}
  ConstConditionInternal.prototype.evaluate = function () {
    return this.value;
  };
  return ConstConditionInternal;
}();
var AndConditionInternal = /** @class */function () {
  function AndConditionInternal() {}
  AndConditionInternal.prototype.evaluate = function () {
    var children = this.children;
    for (var i = 0; i < children.length; i++) {
      if (!children[i].evaluate()) {
        return false;
      }
    }
    return true;
  };
  return AndConditionInternal;
}();
var OrConditionInternal = /** @class */function () {
  function OrConditionInternal() {}
  OrConditionInternal.prototype.evaluate = function () {
    var children = this.children;
    for (var i = 0; i < children.length; i++) {
      if (children[i].evaluate()) {
        return true;
      }
    }
    return false;
  };
  return OrConditionInternal;
}();
var NotConditionInternal = /** @class */function () {
  function NotConditionInternal() {}
  NotConditionInternal.prototype.evaluate = function () {
    return !this.child.evaluate();
  };
  return NotConditionInternal;
}();
var RelationalConditionInternal = /** @class */function () {
  function RelationalConditionInternal() {}
  RelationalConditionInternal.prototype.evaluate = function () {
    var needParse = !!this.valueParser;
    // Call getValue with no `this`.
    var getValue = this.getValue;
    var tarValRaw = getValue(this.valueGetterParam);
    var tarValParsed = needParse ? this.valueParser(tarValRaw) : null;
    // Relational cond follow "and" logic internally.
    for (var i = 0; i < this.subCondList.length; i++) {
      if (!this.subCondList[i].evaluate(needParse ? tarValParsed : tarValRaw)) {
        return false;
      }
    }
    return true;
  };
  return RelationalConditionInternal;
}();
function parseOption(exprOption, getters) {
  if (exprOption === true || exprOption === false) {
    var cond = new ConstConditionInternal();
    cond.value = exprOption;
    return cond;
  }
  var errMsg = '';
  if (!isObjectNotArray(exprOption)) {
    if (process.env.NODE_ENV !== 'production') {
      errMsg = log.makePrintable('Illegal config. Expect a plain object but actually', exprOption);
    }
    log.throwError(errMsg);
  }
  if (exprOption.and) {
    return parseAndOrOption('and', exprOption, getters);
  } else if (exprOption.or) {
    return parseAndOrOption('or', exprOption, getters);
  } else if (exprOption.not) {
    return parseNotOption(exprOption, getters);
  }
  return parseRelationalOption(exprOption, getters);
}
function parseAndOrOption(op, exprOption, getters) {
  var subOptionArr = exprOption[op];
  var errMsg = '';
  if (process.env.NODE_ENV !== 'production') {
    errMsg = log.makePrintable('"and"/"or" condition should only be `' + op + ': [...]` and must not be empty array.', 'Illegal condition:', exprOption);
  }
  if (!util.isArray(subOptionArr)) {
    log.throwError(errMsg);
  }
  if (!subOptionArr.length) {
    log.throwError(errMsg);
  }
  var cond = op === 'and' ? new AndConditionInternal() : new OrConditionInternal();
  cond.children = util.map(subOptionArr, function (subOption) {
    return parseOption(subOption, getters);
  });
  if (!cond.children.length) {
    log.throwError(errMsg);
  }
  return cond;
}
function parseNotOption(exprOption, getters) {
  var subOption = exprOption.not;
  var errMsg = '';
  if (process.env.NODE_ENV !== 'production') {
    errMsg = log.makePrintable('"not" condition should only be `not: {}`.', 'Illegal condition:', exprOption);
  }
  if (!isObjectNotArray(subOption)) {
    log.throwError(errMsg);
  }
  var cond = new NotConditionInternal();
  cond.child = parseOption(subOption, getters);
  if (!cond.child) {
    log.throwError(errMsg);
  }
  return cond;
}
function parseRelationalOption(exprOption, getters) {
  var errMsg = '';
  var valueGetterParam = getters.prepareGetValue(exprOption);
  var subCondList = [];
  var exprKeys = util.keys(exprOption);
  var parserName = exprOption.parser;
  var valueParser = parserName ? dataValueHelper.getRawValueParser(parserName) : null;
  for (var i = 0; i < exprKeys.length; i++) {
    var keyRaw = exprKeys[i];
    if (keyRaw === 'parser' || getters.valueGetterAttrMap.get(keyRaw)) {
      continue;
    }
    var op = util.hasOwn(RELATIONAL_EXPRESSION_OP_ALIAS_MAP, keyRaw) ? RELATIONAL_EXPRESSION_OP_ALIAS_MAP[keyRaw] : keyRaw;
    var condValueRaw = exprOption[keyRaw];
    var condValueParsed = valueParser ? valueParser(condValueRaw) : condValueRaw;
    var evaluator = dataValueHelper.createFilterComparator(op, condValueParsed) || op === 'reg' && new RegExpEvaluator(condValueParsed);
    if (!evaluator) {
      if (process.env.NODE_ENV !== 'production') {
        errMsg = log.makePrintable('Illegal relational operation: "' + keyRaw + '" in condition:', exprOption);
      }
      log.throwError(errMsg);
    }
    subCondList.push(evaluator);
  }
  if (!subCondList.length) {
    if (process.env.NODE_ENV !== 'production') {
      errMsg = log.makePrintable('Relational condition must have at least one operator.', 'Illegal condition:', exprOption);
    }
    // No relational operator always disabled in case of dangers result.
    log.throwError(errMsg);
  }
  var cond = new RelationalConditionInternal();
  cond.valueGetterParam = valueGetterParam;
  cond.valueParser = valueParser;
  cond.getValue = getters.getValue;
  cond.subCondList = subCondList;
  return cond;
}
function isObjectNotArray(val) {
  return util.isObject(val) && !util.isArrayLike(val);
}
var ConditionalExpressionParsed = /** @class */function () {
  function ConditionalExpressionParsed(exprOption, getters) {
    this._cond = parseOption(exprOption, getters);
  }
  ConditionalExpressionParsed.prototype.evaluate = function () {
    return this._cond.evaluate();
  };
  return ConditionalExpressionParsed;
}();
;
function parseConditionalExpression(exprOption, getters) {
  return new ConditionalExpressionParsed(exprOption, getters);
}

exports.parseConditionalExpression = parseConditionalExpression;
