var util = require('./util')
var OHOS_THEME_PROP_GROUPS = require('../../theme/ohosStyles');

// http://www.w3.org/TR/css3-color/#html4
var BASIC_COLOR_KEYWORDS = {
  black: '#000000',
  silver: '#C0C0C0',
  gray: '#808080',
  white: '#FFFFFF',
  maroon: '#800000',
  red: '#FF0000',
  purple: '#800080',
  fuchsia: '#FF00FF',
  green: '#008000',
  lime: '#00FF00',
  olive: '#808000',
  yellow: '#FFFF00',
  navy: '#000080',
  blue: '#0000FF',
  teal: '#008080',
  aqua: '#00FFFF'
}

// http://www.w3.org/TR/css3-color/#svg-color
var EXTENDED_COLOR_KEYWORDS = {
  aliceblue: '#F0F8FF',
  antiquewhite: '#FAEBD7',
  aqua: '#00FFFF',
  aquamarine: '#7FFFD4',
  azure: '#F0FFFF',
  beige: '#F5F5DC',
  bisque: '#FFE4C4',
  black: '#000000',
  blanchedalmond: '#FFEBCD',
  blue: '#0000FF',
  blueviolet: '#8A2BE2',
  brown: '#A52A2A',
  burlywood: '#DEB887',
  cadetblue: '#5F9EA0',
  chartreuse: '#7FFF00',
  chocolate: '#D2691E',
  coral: '#FF7F50',
  cornflowerblue: '#6495ED',
  cornsilk: '#FFF8DC',
  crimson: '#DC143C',
  cyan: '#00FFFF',
  darkblue: '#00008B',
  darkcyan: '#008B8B',
  darkgoldenrod: '#B8860B',
  darkgray: '#A9A9A9',
  darkgreen: '#006400',
  darkgrey: '#A9A9A9',
  darkkhaki: '#BDB76B',
  darkmagenta: '#8B008B',
  darkolivegreen: '#556B2F',
  darkorange: '#FF8C00',
  darkorchid: '#9932CC',
  darkred: '#8B0000',
  darksalmon: '#E9967A',
  darkseagreen: '#8FBC8F',
  darkslateblue: '#483D8B',
  darkslategray: '#2F4F4F',
  darkslategrey: '#2F4F4F',
  darkturquoise: '#00CED1',
  darkviolet: '#9400D3',
  deeppink: '#FF1493',
  deepskyblue: '#00BFFF',
  dimgray: '#696969',
  dimgrey: '#696969',
  dodgerblue: '#1E90FF',
  firebrick: '#B22222',
  floralwhite: '#FFFAF0',
  forestgreen: '#228B22',
  fuchsia: '#FF00FF',
  gainsboro: '#DCDCDC',
  ghostwhite: '#F8F8FF',
  gold: '#FFD700',
  goldenrod: '#DAA520',
  gray: '#808080',
  green: '#008000',
  greenyellow: '#ADFF2F',
  grey: '#808080',
  honeydew: '#F0FFF0',
  hotpink: '#FF69B4',
  indianred: '#CD5C5C',
  indigo: '#4B0082',
  ivory: '#FFFFF0',
  khaki: '#F0E68C',
  lavender: '#E6E6FA',
  lavenderblush: '#FFF0F5',
  lawngreen: '#7CFC00',
  lemonchiffon: '#FFFACD',
  lightblue: '#ADD8E6',
  lightcoral: '#F08080',
  lightcyan: '#E0FFFF',
  lightgoldenrodyellow: '#FAFAD2',
  lightgray: '#D3D3D3',
  lightgreen: '#90EE90',
  lightgrey: '#D3D3D3',
  lightpink: '#FFB6C1',
  lightsalmon: '#FFA07A',
  lightseagreen: '#20B2AA',
  lightskyblue: '#87CEFA',
  lightslategray: '#778899',
  lightslategrey: '#778899',
  lightsteelblue: '#B0C4DE',
  lightyellow: '#FFFFE0',
  lime: '#00FF00',
  limegreen: '#32CD32',
  linen: '#FAF0E6',
  magenta: '#FF00FF',
  maroon: '#800000',
  mediumaquamarine: '#66CDAA',
  mediumblue: '#0000CD',
  mediumorchid: '#BA55D3',
  mediumpurple: '#9370DB',
  mediumseagreen: '#3CB371',
  mediumslateblue: '#7B68EE',
  mediumspringgreen: '#00FA9A',
  mediumturquoise: '#48D1CC',
  mediumvioletred: '#C71585',
  midnightblue: '#191970',
  mintcream: '#F5FFFA',
  mistyrose: '#FFE4E1',
  moccasin: '#FFE4B5',
  navajowhite: '#FFDEAD',
  navy: '#000080',
  oldlace: '#FDF5E6',
  olive: '#808000',
  olivedrab: '#6B8E23',
  orange: '#FFA500',
  orangered: '#FF4500',
  orchid: '#DA70D6',
  palegoldenrod: '#EEE8AA',
  palegreen: '#98FB98',
  paleturquoise: '#AFEEEE',
  palevioletred: '#DB7093',
  papayawhip: '#FFEFD5',
  peachpuff: '#FFDAB9',
  peru: '#CD853F',
  pink: '#FFC0CB',
  plum: '#DDA0DD',
  powderblue: '#B0E0E6',
  purple: '#800080',
  red: '#FF0000',
  rosybrown: '#BC8F8F',
  royalblue: '#4169E1',
  rebeccapurple: '#663399',
  saddlebrown: '#8B4513',
  salmon: '#FA8072',
  sandybrown: '#F4A460',
  seagreen: '#2E8B57',
  seashell: '#FFF5EE',
  sienna: '#A0522D',
  silver: '#C0C0C0',
  skyblue: '#87CEEB',
  slateblue: '#6A5ACD',
  slategray: '#708090',
  slategrey: '#708090',
  snow: '#FFFAFA',
  springgreen: '#00FF7F',
  steelblue: '#4682B4',
  tan: '#D2B48C',
  teal: '#008080',
  thistle: '#D8BFD8',
  tomato: '#FF6347',
  turquoise: '#40E0D0',
  violet: '#EE82EE',
  wheat: '#F5DEB3',
  white: '#FFFFFF',
  whitesmoke: '#F5F5F5',
  yellow: '#FFFF00',
  yellowgreen: '#9ACD32'
}

var DEFAULT_ANIMATION = {
    animationDuration : "0ms",
    animationDelay : "0ms",
    animationDirection : 'normal',
    animationTimingFunction : 'ease',
    animationPlayState : 'running',
    animationIterationCount : 1,
    animationFillMode : 'none'
}

var LENGTH_REGEXP = /^[-+]?\d*\.?\d+(\S*)$/
var LINE_GRADIENT_ITEM_REGEXP = /^([0-9a-zA-Z-]+)\((.*)\)/
var LINE_GRADIENT_DIRECTION_REGEXP = /^\s*(to|bottom|right|left|top)|[-+]?[0-9]*\.?[0-9]+(.*)/
var LINE_GRADIENT_TO_DIRECTION_REGEXP = /(to|bottom|right|left|top)/
var ANGLE_REGEXP = /^[-+]?[0-9]*\.?[0-9]+(.*)/
var ARRAY_COLOR_STOP_REGEXP = /(rgba|rgb)\([0-9,.\spx%vpfp]+\)\s?[0-9-+px%vpfp]*|[#]?\w+\s?[0-9+-\spx%vpfp]*/gi
var URL_REGEXP = /^url\(\s*['"]?\s*([^()]+?)\s*['"]?\s*\)$/
var NAME_REGEXP = /^[a-zA-Z_]+[a-zA-Z0-9-]*$/
var INT_REGEXP = /^[-+]?[0-9]+$/
var ID_REGEXP = /^\"@id\d+\"$/
var NORMAL_REGEXP =  /^normal$/
var AUTO_REGEXP = /^auto$/
var DATE_REGEXP = /(^([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((1[02]|0?[13578])-([12][0-9]|3[01]|0?[1-9]))|((11|0?[469])-(30|[12][0-9]|0?[1-9]))|(0?2-(1[0-9]|2[0-8]|0?[1-9])))$)|(^(([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[13579][26])00))-(0?)2-29$)/
var TRANSFORM_REGEXP = /[0-9a-zA-Z]+\s*\(\s*[0-9(a-zA-Z-|%)\.]+\s*(,\s*[0-9(a-zA-Z-|%)\.]+)*\)/g
var TRANSFORM_ITEM_REGEXP = /^([0-9a-zA-Z]+)\s*\((.*)\)$/
var FILTER_REGEXP = /^blur\(([1-9]\d*|0)(px|fp|vp)\)$/
var FILTER_PERCENTAGE_REGEXP = /^blur\(([1-9]?\d|100)%\)$/
var FILTER_STYLE_REGEXP = /^blur\(([1-9]?\d|100)%\)\s+[A-Za-z_]+$/
var SUPPORT_CSS_EXPRESSION = /calc\(|var\(\-\-/
var SUPPORT_VAR_EXPRESSION = /var\(\-\-/
var SUPPORT_CSS_UNIT = ['px', 'pt', 'wx', 'vp', 'fp']
var SUPPORT_CSS_TIME_UNIT = ['ms', 's']
var SUPPORT_CSS_PERCENTAGE_UNIT = ['px', '%', 'vp', 'fp']
var SUPPORT_CSS_GRID_UNIT = ['px', '%', 'fr', 'vp', 'fp']
var SUPPORT_CSS_TEXT_INDENT_UNIT = ['px', 'cm', '%', 'em', 'vp', 'fp']
var SUPPORT_CSS_ANGLE_UNIT = ["deg", "rad", "grad", "turn"]
var logTypes = ["NOTE", "WARNING", "ERROR"]

var ANYTHING_VALIDATOR = function ANYTHING_VALIDATOR(v) {
  v = (v || '').toString().trim()
  return { value: v }
}

/**
 * the values below is valid
 * - auto
 * - number
 * - number + 'px'|'%'|'vp'| 'fp'
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: number|null
 * - reason(k, v, result)
 */
var AUTO_PERCENTAGE_LENGTH_VALIDATOR = function AUTO_PERCENTAGE_LENGTH_VALIDATOR(v) {
  v = (v || '').toString().trim()
  if (v.match(AUTO_REGEXP)) {
    return { value: v }
  } else if (v.match(ID_REGEXP)) {
    return { value: v }
  } else if (v.match(SUPPORT_CSS_EXPRESSION)) {
    return { value: v }
  } else {
    return LENGTH(v, SUPPORT_CSS_PERCENTAGE_UNIT)
  }
}

/**
 * the values below is valid
 * - number
 * - number + 'px'|'%'|'vp'| 'fp'
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: number|null
 * - reason(k, v, result)
 */
var PERCENTAGE_LENGTH_VALIDATOR = function PERCENTAGE_LENGTH_VALIDATOR(v) {
  v = (v || '').toString().trim()
  if (v.match(ID_REGEXP)) {
    return { value: v }
  } else if (v.match(SUPPORT_CSS_EXPRESSION)) {
    return { value: v }
  } else {
    return LENGTH(v, SUPPORT_CSS_PERCENTAGE_UNIT)
  }
}

/**
 * the values below is valid
 * - number
 * - number + 'px'
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: number|null
 * - reason(k, v, result)
 */
var LENGTH_VALIDATOR = function LENGTH_VALIDATOR(v) {
  v = (v || '').toString().trim()
  if (v.match(SUPPORT_CSS_EXPRESSION)) {
    return { value: v }
  } else if (v.match(ID_REGEXP)) {
    return { value: v }
  } else {
    return LENGTH(v, SUPPORT_CSS_UNIT)
  }
}

var LENGTH = function LENGTH(v, SUPPORT_UNIT) {
  v = (v || '').toString().trim()
  var match = v.match(LENGTH_REGEXP)

  if (match) {
    var unit = match[1]
    if (!unit) {
      return v === '0' ? { value: parseFloat(v) + SUPPORT_UNIT[0] } :
        {
          value: parseFloat(v) + SUPPORT_UNIT[0],
          reason: function(k, v) {
            return 'WARNING: No unit is specified for the `' + util.camelCaseToHyphened(k) +
              '` attribute. The default unit is ' + SUPPORT_UNIT[0]
          }
        }
    } else if (SUPPORT_UNIT.indexOf(unit) > -1) {
      return { value: v }
    } else {
      return {
        value: parseFloat(v) + SUPPORT_UNIT[0],
        reason: function reason(k, v, result) {
          return 'ERROR: The `' + k + '` attribute does not support `' + unit +
            '`. The default unit is ' + SUPPORT_UNIT[0]
        }
      }
    }
  }

  if (v.indexOf('@') >= 0) {
    let result
    // target format "@sys.float.id_sys_length" or '@sys.float.id_sys_length'
    let SysResourceTypeRefReg = /['"]\s*@sys\.float\.(?<resName>\w+)\s*['"]/
    result = SysResourceTypeRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
        return { value: "@sys.float." + OHOS_THEME_PROP_GROUPS[resourceName] }
      }
    }
    // target format "@app.float.developer_defined_length" or '@app.float.developer_defined_length'
    let AppResourceTypeRefReg = /['"]\s*@app\.float\.(?<resName>\w+)\s*['"]/
    result = AppResourceTypeRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName) {
        return { value: "@app.float." + resourceName}
      }
    }
    // target format "@id_sys_length" or '@id_sys_length' or @id_sys_length
    let ResourceRefReg = /['"]?\s*@(?<resName>\w+)\s*['"]?/
    result = ResourceRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
        return { value: "@ohos_id_" + OHOS_THEME_PROP_GROUPS[resourceName] }
      }
    }
  }

  return {
    value: null,
    reason: function reason(k, v, result) {
      return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support the `' +
        v + '` value (only numbers are supported).'
    }
  }
}

var TEXT_INDENT_VALIDATOR = function TEXT_INDENT_VALIDATOR(v) {
  return LENGTH(v, SUPPORT_CSS_TEXT_INDENT_UNIT)
}

var TEXT_LINE_HEIGHT_VALIDATOR = function TEXT_LINE_HEIGHT_VALIDATOR(v) {
  v = (v || '').toString().trim()

  if (v.match(NORMAL_REGEXP)) {
    return { value: v }
  } else {
    return LENGTH_VALIDATOR(v)
  }
}

/**
 * the values below is valid
 * - number
 * - number + 'ms'|'s'
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: number|null
 * - reason(k, v, result)
 */
var TIME_VALIDATOR = function TIME_VALIDATOR(v) {
  return LENGTH(v, SUPPORT_CSS_TIME_UNIT)
}

/**
 * the values below is valid
 * - number {1,4}
 * - number + 'px' {1,4}
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: number|null
 * - reason(k, v, result)
 */
var SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR = function SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR(v) {
  v = (v || '').toString().trim()
  let rule = PERCENTAGE_LENGTH_VALIDATOR
  return SHORTHAND_VALIDATOR(v, rule)
}

var SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR = function SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR(v) {
  v = (v || '').toString().trim()
  let rule = AUTO_PERCENTAGE_LENGTH_VALIDATOR
  return SHORTHAND_VALIDATOR(v, rule)
}

var SHORTHAND_LENGTH_VALIDATOR = function SHORTHAND_LENGTH_VALIDATOR(v) {
  v = (v || '').toString().trim()
  let rule = LENGTH_VALIDATOR
  return SHORTHAND_VALIDATOR(v, rule)
}

var ARRAY_LENGTH_VALIDATOR = function ARRAY_LENGTH_VALIDATOR(v) {
  v = (v || '').toString().trim().replace(/,/g, ' ')
  var isArray = true
  return SHORTHAND_VALIDATOR(v, LENGTH_VALIDATOR, isArray)
}

/**
 * the values below is valid
 * - hex color value (#xxxxxx or #xxx)
 * - basic and extended color keywords in CSS spec
 * - expression
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: string|null
 * - reason(k, v, result)
 */
var COLOR_VAR_VALIDATOR = function COLOR_VAR_VALIDATOR(v) {
  v = (v || '').toString().trim()
  if (v.match(SUPPORT_VAR_EXPRESSION)) {
    return { value: v }
  } else {
    return COLOR_VALIDATOR(v)
  }
}

/**
 * the values below is valid
 * - hex color value (#xxxxxx or #xxx)
 * - basic and extended color keywords in CSS spec
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: string|null
 * - reason(k, v, result)
 */
var COLOR_VALIDATOR = function COLOR_VALIDATOR(v) {
  v = (v || '').toString().trim()

  if (v.indexOf('linear-gradient') >= 0) {
    let result = {
      values: []
    }
    let temp = LINEAR_GRADIENT_VALIDATOR(v)
    if (util.isValidValue(temp.value)) {
      let tempValue = JSON.parse(temp.value)
      result.values.push(tempValue)
      return { value: JSON.stringify(result) }
    } else {
      return temp
    }
  }

  if (v.match(ID_REGEXP)) {
    return { value: v }
  }

  if (v.indexOf('@') >= 0) {
    let result
    // target format "@sys.color.id_color_background" or '@sys.color.id_color_background'
    let SysResourceTypeRefReg = /['"]\s*@sys\.color\.(?<resName>\w+)\s*['"]/
    result = SysResourceTypeRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
        return { value: "@sys.color." + OHOS_THEME_PROP_GROUPS[resourceName] }
      }
    }
    // target format "@app.color.developer_defined_color" or '@app.color.developer_defined_color'
    let AppResourceTypeRefReg = /['"]\s*@app\.color\.(?<resName>\w+)\s*['"]/
    result = AppResourceTypeRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName) {
        return { value: "@app.color." + resourceName}
      }
    }
    // target format "@id_color_background" or '@id_color_background' or @id_color_background
    let ResourceRefReg = /['"]?\s*@(?<resName>\w+)\s*['"]?/
    result = ResourceRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
        return { value: "@ohos_id_" + OHOS_THEME_PROP_GROUPS[resourceName] }
      }
    }
  }

  if (v.match(/^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/)) {
    return { value: v }
  }

  if (v.match(/^#[0-9a-fA-F]{3}$/)) {
    return {
      value: '#' + v[1] + v[1] + v[2] + v[2] + v[3] + v[3],
      reason: function reason(k, v, result) {
        return 'NOTE: Attribute value `' + v + '` is automatically fixed to `' + result + '`.'
      }
    }
  }

  if (EXTENDED_COLOR_KEYWORDS[v]) {
    return {
      value: EXTENDED_COLOR_KEYWORDS[v],
      reason: function reason(k, v, result) {
        return 'NOTE: Attribute value `' + v + '` is automatically fixed to `' + result + '`.'
      }
    }
  }

  if (v === 'transparent' || v === 'none') {
    return { value: 'rgba(0,0,0,0)' }
  }

  const returnColorReg = COLOR_REG(v)
  if (returnColorReg.value !== null) {
    return returnColorReg
  }

  return {
    value: null,
    reason: function reason(k, v, result) {
      return 'ERROR: Value `' + v + '` is invalid for the `' + util.camelCaseToHyphened(k) + '` attribute.'
    }
  }
}

var COLOR_REG = function COLOR_REG(v) {
  let arrColor, r, g, b, a
  const RGB_REGEXP = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/gi
  const RGBA_REGEXP = /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d*\.?\d+)\s*\)$/gi
  const HSL_REGEXP = /^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$/gi
  const HSLA_REGEXP = /^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d*\.?\d+)\s*\)$/gi
  if (arrColor = RGB_REGEXP.exec(v)) {
    r = parseInt(arrColor[1])
    g = parseInt(arrColor[2])
    b = parseInt(arrColor[3])
    if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
      return { value: 'rgb(' + [r, g, b].join(',') + ')' }
    }
  }
  if (arrColor = RGBA_REGEXP.exec(v)) {
    r = parseInt(arrColor[1])
    g = parseInt(arrColor[2])
    b = parseInt(arrColor[3])
    a = parseFloat(arrColor[4])
    if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 && a >= 0 && a <= 1) {
      return { value: 'rgba(' + [r, g, b, a].join(',') + ')' }
    }
  }
  if (arrColor = HSL_REGEXP.exec(v)) {
    r = arrColor[1]
    g = arrColor[2]
    b = arrColor[3]
    if (r >= 0 && r <= 360 && g >= 0 && g <= 100 && b >= 0 && b <= 100) {
      return { value: 'hsl(' + [r, g+'%', b+'%'].join(',') + ')' }
    }
  }
  if (arrColor = HSLA_REGEXP.exec(v)) {
    r = arrColor[1]
    g = arrColor[2]
    b = arrColor[3]
    a = arrColor[4]
    if (r >= 0 && r <= 360 && g >= 0 && g <= 100 && b >= 0 && b <= 100 && a >= 0 && a <= 1) {
      return { value: 'hsla(' + [r, g+'%', b+'%', a].join(',') + ')' }
    }
  }

  return { value: null }
}

/**
 * the values below is valid
 * - color {1,4}
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: color|null
 * - reason(k, v, result)
 */
var SHORTHAND_COLOR_VALIDATOR = function SHORTHAND_COLOR_VALIDATOR(v) {
  v = (v || '').toString().trim()
  v = v.replace(/\s*,\s+/g, ',')
  return SHORTHAND_VALIDATOR(v, COLOR_VAR_VALIDATOR)
}

var ARRAY_COLOR_VALIDATOR = function ARRAY_COLOR_VALIDATOR(v) {
  v = (v || '').toString().trim()
  var isArray = true
  return SHORTHAND_VALIDATOR(v.replace(/,/g, ' '), COLOR_VAR_VALIDATOR, isArray)
}

var SHORTHAND_STYLE_VALIDATOR = function SHORTHAND_STYLE_VALIDATOR(v) {
  v = (v || '').toString().trim()
  return SHORTHAND_VALIDATOR(v, STYLE_VALIDATOR)
}

var STYLE_VALIDATOR = function STYLE_VALIDATOR(v) {
  const styleList = ["solid", "dashed", "dotted"]
  v = (v || '').toString().trim()
  if (styleList.includes(v)) {
    return { value:v }
  } else {
    return {
      value: null,
      reason: function (k,v) {
        return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' +
          v + '` (the support value is `' + styleList.join('`|`') + '`).'
      }
    }
  }
}

var SHORTHAND_VALIDATOR = function SHORTHAND_VALIDATOR(v, validateFunction, isArray) {
  v = (v || '').toString().trim()
  let value = []
  let reason = []
  let results = v.split(/(?<!\+|\-|\*|\/|\,)\s+(?!\+|\-|\*|\/|\,)/).map(validateFunction)
  for (let i = 0; i < results.length; ++i) {
    let res = results[i]
    if (!res.value) {
      value = null
      reason = res.reason
      break
    }
    value.push(res.value)
    if (res.reason) {
      reason.push(res.reason)
    }
  }

  if (!value) {
    return {
      value: value,
      reason: reason
    }
  }
  else {
    return {
      value: isArray ? value.join(',') : value.join(' '),
      reason: reason.length > 0 ? function (k, v, result) {
        return reason.map(function (res) {
          if (typeof res === 'function') {
            return res(k, v, result)
          }
        }).join('\n')
      } : null
    }
  }
}

var BORDER_VALIDATOR = function BORDER_VALIDATOR (value, name) {
  value = (value || '').toString().trim();
  let values = '';
  const colorAttribute = value.match(/\(.*?\)/g);
  if (colorAttribute && colorAttribute.length === 1) {
    values = value.replace(colorAttribute[0], colorAttribute[0].replace(/\s+/g, '')).split(/\s+/);
  } else {
    values = value.split(/\s+/);
  }
  const res = []
  let hasError = false
  const reasons = []
  let index = 0
  const order = []
  let validatorResult
  const rules = [
    {
      match (item) { return LENGTH_VALIDATOR(item).value },
      action (item) {
        validatorResult = LENGTH_VALIDATOR(item)
        order.push(0)
        res.push({
          value: validatorResult.value,
          type: 'Width'
        })
      }
    },
    {
      match (item) { return validate('borderStyle', item).value },
      action (item) {
        validatorResult = validate('borderStyle', item)
        order.push(1)
        res.push({
          value: validatorResult.value,
          type: 'Style'
        })
      }
    },
    {
      match (item) { return COLOR_VAR_VALIDATOR(item).value },
      action (item) {
        validatorResult = COLOR_VAR_VALIDATOR(item)
        order.push(2)
        res.push({
          value: validatorResult.value,
          type: 'Color'
        })
      }
    },
    {
      match () { return true },
      action () {
        hasError = true
      }
    }
  ]
  if (values && values.length <= 3) {
    for (let i = 0; i < values.length; i++) {
      const item = values[i]
      for (let i = 0; i < rules.length; i++) {
        if (rules[i].match(item)) {
          rules[i].action(item)
          break;
        }
      }
      // style width color pass verification, but did not write in order, such as "1px red solid", should be error
      let orderIndex = -1
      order.forEach((item) => {
        orderIndex < item ? orderIndex = item : hasError = true
      })
      // get all warning and note log
      logUtil(validatorResult, name, item, reasons, index)
    }
    // print warning and note
    if (!hasError) {
      return {
        value: res,
        reason: reasons.length > 0 ? function (k, v) {
          return (
            logTypes[index] + ': There are some problems with value `' + v + '` of the `' +
              util.camelCaseToHyphened(k) + '` attribute. \n ' + reasons.join(' \n'))
        } : null
      }
    }
  }
  // print error
  return {
    value: null,
    reason: function reason (k, v, result) {
      return 'ERROR: The `' + util.camelCaseToHyphened(k) +
        '` attribute does not support value `' + v +
        '` (this value does not meet the inspection standards for the width, style, and color).'
    }
  }
}

function logUtil (validatorResult, name, item, reasons, index) {
  if (validatorResult.reason) {
    let str = validatorResult.reason(name, item, validatorResult.value)
    const mesg = str.match(/^([A-Z]+):/)
    // When both warning and note information are included, a high severity sign is output
    const num = logTypes.indexOf(mesg[1])
    if (index < num) {
      index = num
    }
    str = str.replace(mesg[0], '')
    reasons.push(str)
  }
}

var BOX_SHADOW_VALIDATOR = function BOX_SHADOW_VALIDATOR(value, name) {
  value = (value || '').toString().trim()
  const values = value.split(/\s+/)
  let validatorResult
  const res = []
  const order = []
  const reasons = []
  let index = 0
  let ruleIndex = 0
  let hasError = false
  const rules = [
    {
      match (item) { return validate('boxShadowH', item).value },
      action (item) {
        validatorResult = validate('boxShadowH', item)
        order.push(0)
        res.push({
          value: validatorResult.value,
          type: 'H'
        })
      }
    },
    {
      match (item) { return validate('boxShadowV', item).value },
      action (item) {
        validatorResult = validate('boxShadowV', item)
        order.push(1)
        res.push({
          value: validatorResult.value,
          type: 'V'
        })
      }
    },
    {
      match (item) { return validate('boxShadowBlur', item).value },
      action (item) {
        validatorResult = validate('boxShadowBlur', item)
        order.push(2)
        res.push({
          value: validatorResult.value,
          type: 'Blur'
        })
      }
    },
    {
      match (item) { return validate('boxShadowSpread', item).value },
      action (item) {
        validatorResult = validate('boxShadowSpread', item)
        order.push(3)
        res.push({
          value: validatorResult.value,
          type: 'Spread'
        })
      }
    },
    {
      match (item) { return COLOR_VAR_VALIDATOR(item).value },
      action (item) {
        validatorResult = COLOR_VAR_VALIDATOR(item)
        order.push(4)
        res.push({
          value: validatorResult.value,
          type: 'Color'
        })
      }
    }
  ]
  const length = values.length
  const flag = (length <= 6 && length >= 2) && values[0].match(LENGTH_REGEXP) && values[1].match(LENGTH_REGEXP)
  if (values && flag) {
    for (let i = 0; i < values.length; i++) {
      const item = values[i]
      for (let j = ruleIndex; j < rules.length; j++) {
        if (rules[j].match(item)) {
          ruleIndex++
          rules[j].action(item)
          break
        }
      }
      let orderIndex = -1
      order.forEach((item) => {
        orderIndex < item ? orderIndex = item : hasError = true
      })
      // get all warning and note log
      logUtil(validatorResult, name, item, reasons, index)
    }
    if (!hasError) {
      return {
        value: res,
        reason: reasons.length > 0 ? function (k, v) {
          return (
            logTypes[index] + ': There are some problems with value `' + v +
              '` of the `' + util.camelCaseToHyphened(k) + '` attribute. \n ' + reasons.join(' \n'))
        } : null
      }
    }
  }
  return {
    value: null,
    reason: function reason (k, v, result) {
      return 'ERROR: The `' + util.camelCaseToHyphened(k) +
        '` attribute does not support value `' + v +
        '` (this value does not meet the inspection standards).'
    }
  }
}

/**
 * only integer or float value is valid
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: number|null
 * - reason(k, v, result)
 */
var NUMBER_VALIDATOR = function NUMBER_VALIDATOR(v, isInt) {
  v = (v || '').toString().trim()

  if (v.match(ID_REGEXP)) {
    return { value: v }
  }

  var match = v.match(LENGTH_REGEXP)

  if (match && !match[1]) {
    return { value: isInt === true ? parseInt(v, 10) : parseFloat(v) }
  }

  if (v.indexOf('@') >= 0) {
    let result
    // target format "@sys.float.id_sys_number" or '@sys.float.id_sys_number'
    let SysResourceTypeRefReg = /['"]\s*@sys\.float\.(?<resName>\w+)\s*['"]/
    result = SysResourceTypeRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
        return { value: "@sys.float." + OHOS_THEME_PROP_GROUPS[resourceName] }
      }
    }
    // target format "@app.float.developer_defined_number" or '@app.float.developer_defined_number'
    let AppResourceTypeRefReg = /['"]\s*@app\.float\.(?<resName>\w+)\s*['"]/
    result = AppResourceTypeRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName) {
        return { value: "@app.float." + resourceName}
      }
    }
    // target format "@id_sys_number" or '@id_sys_number' or @id_sys_number
    let ResourceRefReg = /['"]?\s*@(?<resName>\w+)\s*['"]?/
    result = ResourceRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
        return { value: "@ohos_id_" + OHOS_THEME_PROP_GROUPS[resourceName] }
      }
    }
  }

  return {
    value: null,
    reason: function reason(k, v, result) {
      return 'ERROR: The `' + util.camelCaseToHyphened(k) +
        '` attribute does not support value `' + v + '` (only numbers are supported).'
    }
  }
}

var ARRAY_NUMBER_VALIDATOR = function ARRAY_NUMBER_VALIDATOR(v) {
  v = (v || '').toString().trim().replace(/,/g, ' ')
  var isArray = true
  return SHORTHAND_VALIDATOR(v, NUMBER_VALIDATOR, isArray)
}

/**
 * only integer value is valid
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: number|null
 * - reason(k, v, result)
 */
var INTEGER_VALIDATOR = function INTEGER_VALIDATOR(v) {
  return NUMBER_VALIDATOR(v, true)
}

/**
 * transition-property: only css property is valid
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: string|null
 * - reason(k, v, result)
 */
var TRANSITION_PROPERTY_VALIDATOR = function TRANSITION_PROPERTY_VALIDATOR(v) {
  v = (v || '').toString()
  v = v.split(/\s*,\s*/).map(util.hyphenedToCamelCase).join(',')

  if (v.split(/\s*,\s*/).every(p => !!validatorMap[p])) {
    return {value: v}
  }

  return {
    value: null,
    reason: function reason(k, v, result) {
      return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' +
        v + '` (only CSS attributes support this value).'
    }
  }
}

/**
 * transition-duration & transition-delay: only number of seconds or milliseconds is valid
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: number|null
 * - reason(k, v, result)
 */
var TRANSITION_INTERVAL_VALIDATOR = function TRANSITION_INTERVAL_VALIDATOR(v) {
  v = (v || 0).toString()
  var match, num, ret

  if (match = v.match(/^\d*\.?\d+(ms|s)?$/)) {
    num = parseFloat(match[0])
    if (!match[1]) {
      ret = {value: parseInt(num)}
    }
    else {
      if (match[1] === 's') {
        num *= 1000
      }
      ret = {
        value: parseInt(num),
        reason: function reason(k, v, result) {
          return 'NOTE: Attribute value `' + v + '` is automatically fixed to `' + result + '`.'
        }
      }
    }
    return ret
  }

  return {
    value: null,
    reason: function reason(k, v, result) {
      return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' +
        v + '` (only seconds and milliseconds are supported).'
    }
  }
}

/**
 * transition-timing-function: only linear|ease|ease-in|ease-out|ease-in-out|cubic-bezier(n,n,n,n) is valid
 *
 * @param {string} v
 * @return {function} a function to return
 * - value: linear|ease|ease-in|ease-out|ease-in-out|cubic-bezier(n,n,n,n)|null
 * - reason(k, v, result)
 */
var TRANSITION_TIMING_FUNCTION_VALIDATOR = function TRANSITION_TIMING_FUNCTION_VALIDATOR(v) {
  v = (v || '').toString()

  if (v.match(/^linear|ease|ease-in|ease-out|ease-in-out|fast-out-slow-in|linear-out-slow-in$/) ||
    v.match(/^fast-out-linear-in|friction|extreme-deceleration|sharp|rhythm|smooth$/)) {
    return {value: v}
  }

  let match, ret
  let NUM_REGEXP = /^[-]?\d*\.?\d+$/
  if (match = v.match(/^cubic-bezier\(\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*\)$/)) {
    /* istanbul ignore else */
    if (match[1].match(NUM_REGEXP) && match[2].match(NUM_REGEXP) &&
      match[3].match(NUM_REGEXP) && match[4].match(NUM_REGEXP)) {
      ret = [parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3]), parseFloat(match[4])].join(',')
      return {value: 'cubic-bezier(' + ret + ')'}
    }
  }

  // check steps
  if (match = v.match(/^steps\(\s*([\d]*)\s*(,\s*(start|end)\s*){0,1}\)$/)) {
    var stepCnt = parseFloat(match[1]);
    if (stepCnt > 0) {
      if (match[3] === undefined) {
        ret = stepCnt;
      } else {
        ret = [stepCnt, match[3]].join(',')
      }
      return {value: 'steps(' + ret + ')'}
    }
  }

  return {
    value: null,
    reason: function reason(k, v, result) {
      return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' + v +
             '` (supported values include `linear`, `ease`, `ease-in`, `ease-out`, `ease-in-out`,' +
             ' `cubic-bezier(n,n,n,n)` and `steps(n[, start|end])`).'
    }
  }
}

function parseAnimationOption(key, option, style)
{
   var subResult = validate(key, option)
   if (subResult.value) {
       style[key] = subResult.value
       return true
   }
    return false
}

function parseSimpleAnimation(style, animation) {
    // init default animation brief value
    Object.assign(style, DEFAULT_ANIMATION)
    let options = animation.trim().replace(/,\s+/g, ",").split(/\s+/)
    let durationIdx = NaN
    let delayIdx = NaN
    let directionIdx = NaN
    let timingIdx = NaN
    let playStateIdx = NaN
    let iterationIdx = NaN
    let fillModeIdx = NaN
    for (let idx in options) {
        const option = options[idx]
        if (isNaN(timingIdx) && parseAnimationOption('animationTimingFunction', option, style)) {
            timingIdx = idx
            continue
        }
        if (isNaN(directionIdx) && parseAnimationOption('animationDirection', option, style)) {
            directionIdx = idx
            continue
        }
        if (isNaN(playStateIdx) && parseAnimationOption('animationPlayState', option, style)) {
            playStateIdx = idx
            continue
        }
        if (isNaN(iterationIdx) && parseAnimationOption('animationIterationCount', option, style)) {
            iterationIdx = idx
            continue
        }
        if (isNaN(fillModeIdx) && parseAnimationOption('animationFillMode', option, style)) {
            fillModeIdx = idx
            continue
        }
        if (isNaN(durationIdx) && parseAnimationOption('animationDuration', option, style)) {
            durationIdx = idx
            continue
        }
        if (isNaN(delayIdx) && parseAnimationOption('animationDelay', option, style)) {
            delayIdx = idx
            continue
        }
    }
    delete options[durationIdx]
    delete options[delayIdx]
    delete options[directionIdx]
    delete options[timingIdx]
    delete options[playStateIdx]
    delete options[iterationIdx]
    delete options[fillModeIdx]
    options = options.filter(res => { return !(res === 'undefined') })
    if (options.length === 1) {
       if (!parseAnimationOption('animationName', options[0], style)) {
           return false
       }
       return true
    } else if (options.length > 1) {
        return false
    } else {
        // use default.
        return true
    }
}

var ANIMATION_VALIDATOR = function ANIMATION_VALIDATOR(v) {
    var style = {}
    if (parseSimpleAnimation(style, v)) {
        return {value: style}
    } else {
        return {
            value: null,
            reason: function reason(k, v, result) {
                return 'ERROR: animation is invalid'
            }
        }
    }
}

var TRANSFORM_VALIDATOR = function TRANSFORM_VALIDATOR(v) {
  v = (v || '').toString().trim()
  if (v.match(/^none$/)) {
    return { value: JSON.stringify({}) }
  }
  const values = []
  TRANSFORM_REGEXP.lastIndex = 0
  while (true) {
    let matchValue = TRANSFORM_REGEXP.exec(v)
    if (!matchValue) {
      break
    }
    values.push(v.slice(matchValue.index, TRANSFORM_REGEXP.lastIndex))
  }
  if (!values.length) {
    return {
      value: null,
      reason: function reason(k, v) {
        return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' + v + '`.'
      }
    }
  }
  let result = {}
  let reasonMaps = []
  let allLength = 0
  values.forEach(function(v) {
    let length = 0
    let match = v.match(TRANSFORM_ITEM_REGEXP)
    if (match) {
      let firstValue = match[1]
      let secondValue = match[2]
      let checkFuntion = transformValidatorMap[firstValue]
      if (typeof checkFuntion == 'function') {
        var checkResult = checkFuntion(secondValue)
        if (typeof checkResult.value == 'number' || typeof checkResult.value == 'string') {
          result[firstValue] = checkResult.value
        }
        let check = checkReason(checkResult, firstValue, secondValue, length)
        length = check.length
        if (check.realReason) {
          reasonMaps.push(check.realReason)
        }
      } else {
        length = 2
        reasonMaps.push('property `' + firstValue + '` is invalid.')
      }
    } else {
      length = 2
      reasonMaps.push('property value `' + v + '` is invalid.')
    }
    if (allLength < length) {
      allLength = length
    }
  })
  return {
    value: result ? JSON.stringify(result) : null,
    reason: reasonMaps.length > 0 ?
      function(k, v) {
        return logTypes[allLength] + ': Value `' + v + '` of the `' +
          util.camelCaseToHyphened(k) + '` attribute is incorrect. \n ' + reasonMaps.join(' \n ')
      } : null
  }
}

var MULTIPLE_PERCENTAGE_LENGTH_VALIDATOR = function MULTIPLE_PERCENTAGE_LENGTH_VALIDATOR(v) {
  v = (v || '').toString().trim()
  return MULTIPLE_POSITION_VALIDATOR(v, PERCENTAGE_LENGTH_VALIDATOR)
}

var MULTIPLE_NUMBER_VALIDATOR = function MULTIPLE_NUMBER_VALIDATOR(v) {
  v = (v || '').toString().trim()
  return MULTIPLE_POSITION_VALIDATOR(v, NUMBER_VALIDATOR)
}

var MUTIPLE_ANGLE_VALIDATOR = function MUTIPLE_ANGLE_VALIDATOR(v) {
  v = (v || '').toString().trim()
  return MULTIPLE_POSITION_VALIDATOR(v, ANGLE_VALIDATOR)
}

var ROTATE3D_VALIDATOR = function ROTATE3D_VALIDATOR(v) {
  v = (v || '').toString().trim()
  let values = v.split(/,/g)
  if (values && values.length > 0) {
    let resultValues = []
    let childResult = void 0
    let reasonMaps = []
    let length = 0
    if (values.length != 4) {
      length = 2
      reasonMaps.push('The number of properties is 4, value ' + values + ' is incorrect.')
    } else {
      values.forEach(function (value, index) {
        if (index < 3) {
          childResult = NUMBER_VALIDATOR(value)
        } else {
          childResult = ANGLE_VALIDATOR(value)
        }
        if (typeof childResult.value == 'number' || typeof childResult.value == 'string') {
          resultValues.push(childResult.value)
        }
        let check = checkReason(childResult, index.toString(), value, length)
        length = check.length
        if (check.realReason !== null) {
          reasonMaps.push(check.realReason)
        }
      })
    }

    return {
      value: length < 2 ? resultValues.join(' ') : null,
      reason: reasonMaps.length > 0 ?
        function (k, v) {
          return logTypes[length] + ': Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
            '` attribute is incorrect. \n ' + reasonMaps.join(' \n ')
        } : null
    }
  }
}

var MULTIPLE_POSITION_VALIDATOR = function MULTIPLE_POSITION_VALIDATOR(v, validateFunction) {
  v = (v || '').toString().trim()
  let values = v.split(/,/g)
  if (values && values.length > 0) {
    let resultValues = []
    let childResult = void 0
    let reasonMaps = []
    let length = 0
    if (values.length > 16) {
      length = 2
      reasonMaps.push('The maximum number of properties is 16, value ' + values + ' is incorrect.')
    }
    values.forEach(function (value, index) {
      childResult = validateFunction(value)
      if (typeof childResult.value == 'number' || typeof childResult.value == 'string') {
        resultValues.push(childResult.value)
      }
      let check = checkReason(childResult, index.toString(), value, length)
      length = check.length
      if (check.realReason !== null) {
        reasonMaps.push(check.realReason)
      }
    })
    return {
      value: length < 2 ? resultValues.join(' ') : null,
      reason: reasonMaps.length > 0 ?
        function (k, v) {
          return logTypes[length] + ': Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
            '` attribute is incorrect. \n ' + reasonMaps.join(' \n ')
        } : null
    }
  }
}

/**
 * generate a function to check whether a value is in `list`
 * - first value: default, could be removed
 * - not in `list`: incorrect
 *
 * @param  {Array} list
 * @return {function} a function(v) which returns a function to return
 * - value: string|null
 * - reason(k, v, result)
 */
function genEnumValidator(list) {
  return function ENUM_VALIDATOR(v, name) {
    v = (v || '').toString().trim()
    if (v.match(ID_REGEXP)) {
      return {value: v}
    }

    var index = list.indexOf(v)
    if (index > 0) {
      return {value: v}
    }
    if (index === 0) {
      return {
        value: v,
        reason: name !== 'objectFit' ?
          function reason(k, v, result) {
            return 'NOTE: Value `' + v + '` is the default value of the `' + util.camelCaseToHyphened(k) +
              '` attribute (the value can be removed).'
          } : null
      }
    }
    else {
      return {
        value: null,
        reason: function reason(k, v, result) {
          return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' + v +
            '` (the supported value is `' + list.join('`|`') + '`).'
        }
      }
    }
  }
}

var MASK_VALIDATOR = function MASK_VALIDATOR(v) {
  if (v.indexOf('url') >= 0) {
      return URL_VALIDATOR(v)
  } else {
      return BACKGROUND_VALIDATOR(v)
  }
}

var BACKGROUND_VALIDATOR = function BACKGROUND_VALIDATOR(v) {
  v = (v || '').toString().trim()
  if (v.indexOf('-gradient') > 0) {
    let valueMatch = v.match(/(repeating-linear|linear).*?(?=\s*(repeating|linear)|$)/g)
    let resultValues = {
      values: []
    }
    if (valueMatch && valueMatch.length) {
      let reasonMaps = []
      let length = 0
      valueMatch.forEach(function (realValue) {
        let temp, gradientValidator
        if(realValue.indexOf("-gradient") >= 0){
          temp = realValue.indexOf("repeating") >= 0 ? "repeatingLinearGradient": "linearGradient"
          gradientValidator = backgroundValidatorMap[temp]
        }
        if (typeof gradientValidator == 'function') {
          let validateResult = gradientValidator(realValue)
          if (util.isValidValue(validateResult.value)) {
            let jsonValue = JSON.parse(validateResult.value)
            resultValues.values.push(jsonValue)
          }
          let check = checkReason(validateResult, temp, realValue, length)
          length = check.length
          if (check.realReason !== null) {
            reasonMaps.push(check.realReason)
          }
        } else {
          length = 2
          reasonMaps.push("background type '" + realValue + "' is not supported.")
        }
      })
      return {
        value: length < 2 ? JSON.stringify(resultValues) : null,
        reason: reasonMaps.length > 0 ?
          function (k, v) {
            return logTypes[length] + ': Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
              '` attribute is incorrect. \n ' + reasonMaps.join(' \n ')
          } : null
      }
    }
  }
  return {
    value: null,
    reason: function (k, v) {
      return 'ERROR: The format of value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
        '` attribute is incorrect.'
    }
  }
}

var LINEAR_GRADIENT_VALIDATOR = function LINEAR_GRADIENT_VALIDATOR(v) {
  v = (v || "").toString().trim()
  let result = {
    type: "",
    directions: ["to", "bottom"],
    values: []
  }
  let valueMatch = v.match(LINE_GRADIENT_ITEM_REGEXP)
  if (valueMatch) {
    let tempResult = {}
    let reasonMaps = []
    let length = 0
    let typeName = util.hyphenedToCamelCase(valueMatch[1])
    result.type = typeName
    let matchValues = valueMatch[2].split(/,/)
    if (LINE_GRADIENT_DIRECTION_REGEXP.test(matchValues[0])) {
      let directionValidator
      if (LINE_GRADIENT_TO_DIRECTION_REGEXP.test(matchValues[0])) {
        directionValidator = backgroundValidatorMap.linearGradientDirection
      } else if (matchValues[0].match(ANGLE_REGEXP)) {
        directionValidator = backgroundValidatorMap.linearGradientAngle
      }
      if (typeof directionValidator == "function") {
        tempResult = directionValidator(matchValues[0])
        if (util.isValidValue(tempResult.value)) {
          result.directions = tempResult.value.split(/\s+/)
        }
        let check = checkReason(tempResult, typeName, matchValues[0], length)
        length = check.length
        if (check.realReason !== null) {
          reasonMaps.push(check.realReason)
        }
        matchValues.splice(0, 1)
      }
    }
    if (matchValues.length > 0) {
      let colorStopResult = {}
      colorStopResult = backgroundValidatorMap.linearGradientColor(matchValues)
      if (util.isValidValue(colorStopResult.value)) {
        result.values = JSON.parse(colorStopResult.value)
      }
      let check = checkReason(colorStopResult, typeName, matchValues, length)
        length = check.length
        if (check.realReason !== null) {
          reasonMaps.push(check.realReason)
        }
    } else {
      length = 2
      reasonMaps.push("parameter '" + v + "' missing transition colors.")
    }
    return {
      value: length < 2 ? JSON.stringify(result) : null,
      reason: reasonMaps.length > 0 ?
        function (k, v) {
          return logTypes[length] + ': Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
            '` attribute is incorrect. \n  ' + reasonMaps.join('\n  ')
        }: null
    }
  }
  return {
    value: null,
    reason: function (k, v) {
      return 'ERROR: The format of value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
        '` attribute is incorrect.'
    }
  }
}

var ARRAY_COLOR_STOP_VALIDATOR = function ARRAY_COLOR_STOP_VALIDATOR(v) {
  v = (v || '').toString().trim()
  let values = v.match(ARRAY_COLOR_STOP_REGEXP)
  if (values && values.length > 1) {
    let resultValues = []
    let reasonMaps = []
    let length = 0
    processValueItem(v, values, resultValues, reasonMaps, length)
    return {
      value: length < 2 ? JSON.stringify(resultValues) : null,
      reason: reasonMaps.length > 0 ?
        function (k, v) {
          return logTypes[length] + ': Value `' + v + '` of the `' +
            util.camelCaseToHyphened(k) + '` attribute is incorrect. \n  ' + reasonMaps.join('\n  ')
        } : null
    }
  }
  return {
    value: null,
    reason: function (k, v) {
      return 'ERROR: The format of value `' + v + '` of the `'+ util.camelCaseToHyphened(k) +
        '` attribute is incorrect. Please specify at least two colors.'
    }
  }
}

function processValueItem(v, values, resultValues, reasonMaps, length) {
  values.forEach(function (value, n) {
    let widthMatch = value.match(/[\s]+[-+0-9]+(px|%|vp|fp)?$/)
    let tempValues = []
    if (widthMatch) {
      let matchResult = PERCENTAGE_LENGTH_VALIDATOR(widthMatch[0])
      let index = value.indexOf(widthMatch[0])
      value = value.substring(0, index)
      if (util.isValidValue(matchResult.value)) {
        tempValues.push(matchResult.value)
      }
      let check = checkReason(matchResult, n.toString(), widthMatch[0], length)
      length = check.length
      if (check.realReason !== null) {
        reasonMaps.push(check.realReason)
      }
    }
    if (value) {
      let colorResult = COLOR_VAR_VALIDATOR(value)
      if (util.isValidValue(colorResult.value)) {
        tempValues.unshift(colorResult.value)
      }
      resultValues.push(tempValues.join(' '))
      let check = checkReason(colorResult, n.toString(), value, length)
      length = check.length
      if (check.realReason !== null) {
        reasonMaps.push(check.realReason)
      }
    } else {
      length = 2
      reasonMaps.push("parameter '" + v + "' is incorrect format.")
    }
  })
}

function checkReason(result, k, v, length) {
  let reason
  if (result.reason) {
    reason = result.reason(k, v, result.value)
    if (reason) {
      let reasonType = reason.match(/^([A-Z]+):/)
      let index
      if (reasonType) {
        index = logTypes.indexOf(reasonType[1])
        if (logTypes.indexOf(reasonType[1]) > length) {
          length = index
        }
        reason = reason.replace(reasonType[0], '').trim()
      }
    }
  }
  return {
    length: length,
    realReason: reason ? reason : null
  }
}

var ANGLE_VALIDATOR = function ANGLE_VALIDATOR(v) {
  v = (v || '').toString().trim()
  let match = v.match(ANGLE_REGEXP)
  if (match) {
    let unit = match[1]
    if (unit) {
      let angle = parseFloat(v)
      if (unit.toLowerCase() === 'rad') {
        return {
          value: Math.round(180 * angle / Math.PI) + SUPPORT_CSS_ANGLE_UNIT[0]
        }
      } else {
        if (SUPPORT_CSS_ANGLE_UNIT.indexOf(unit.toLowerCase()) >= 0) {
          return { value: v }
        } else {
          return {
            value: angle + SUPPORT_CSS_ANGLE_UNIT[0],
            reason: function(k, v) {
              return 'ERROR: The `' + util.camelCaseToHyphened(k) +
                '` attribute does not support `' + unit + '`. It only supports `' +
                JSON.stringify(SUPPORT_CSS_ANGLE_UNIT) + '`.'
            }
          }
        }
      }
    } else {
      return {
        value: parseFloat(v) + SUPPORT_CSS_ANGLE_UNIT[0],
        reason: function(k, v) {
          return 'WARNING: No unit is specified for the value `' + v +
            '` of the `' + util.camelCaseToHyphened(k) + '` attribute. The default unit is `' +
            SUPPORT_CSS_ANGLE_UNIT[0] + '`.'
        }
      }
    }
  }
  return {
    value: null,
    reason: function(k, v) {
      return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `'
        + v + '` (only numbers are supported).'
    }
  }
}

var GRADIENT_DIRECTION_VALIDATOR = function GRADIENT_DIRECTION_VALIDATOR(v) {
  v = (v || "").toString().trim()
  let values = v.split(/\s+/)
  let invalid = false
  let scaleY = ['top','bottom']
  let scaleX = ['left','right']
  let valueOrder = []

  values.forEach(function (value) {
    if (value === 'to') {
      valueOrder.push(0)
    } else if (scaleY.includes(value)) {
      valueOrder.push(1)
    } else if (scaleX.includes(value)) {
      valueOrder.push(2)
    } else {
      invalid = true
    }
  })
  if (!invalid) {
    if (valueOrder[0] === 0 && valueOrder.length > 1 && valueOrder.length < 4 && valueOrder[1] !== 0) {
      if (valueOrder[2] && valueOrder[1] + valueOrder[2] !== 3) {
        invalid = true
      }
    }
  }

  return {
    value: invalid ? null : v,
    reason: invalid ?
      function (k, v) {
        return 'ERROR: The format of value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
          '` attribute is incorrect.'
      } : null
  }
}

var URL_VALIDATOR = function URL_VALIDATOR(v) {
  v = (v || "").toString().trim()
  if (v.match(/^none$/i)) {
    return { value: "none" }
  }
  if (v.indexOf('@') >= 0) {
    let result
    // target format "@sys.media.sys_background_image" or '@sys.media.sys_background_image'
    let SysResourceTypeRefReg = /['"]\s*@sys\.media\.(?<resName>\w+)\s*['"]/
    result = SysResourceTypeRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
        return { value: "@sys.media." + OHOS_THEME_PROP_GROUPS[resourceName] }
      }
    }
    // target format "@app.media.customized_background_image" or '@app.media.customized_background_image'
    let AppResourceTypeRefReg = /['"]\s*@app\.media\.(?<resName>\w+)\s*['"]/
    result = AppResourceTypeRefReg.exec(v)
    if (result) {
      const resourceName = result.groups['resName']
      if (resourceName) {
        return { value: "@app.media." + resourceName}
      }
    }
  }

  let matchValues = URL_REGEXP.exec(v)
  if (matchValues) {
    if(isLiteDevice){
      return { value: matchValues[0] }
    }else{
      if (matchValues[1].match(/^\.\.\/|^\.\//)) {
        return {
          value: matchValues[1],
          isRelative: true
        }
      }
      else {
        return { value: matchValues[1] }
      }
    }
  }
  else {
    return {
      value: null,
      reason: function (k, v) {
          return 'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
            '` attribute must be none or url(...).'
      }
    }
  }
}

var NAME_VALIDATOR = function NAME_VALIDATOR(v) {
  v = (v || "").toString().trim()
  if (v.match(NAME_REGEXP)) {
    return  { value: v }
  } else {
    return {
      value: null,
      reason: function(k, v) {
        return 'ERROR: The format of value `' + v + '` of the `' +  util.camelCaseToHyphened(k) +
          '` attribute is incorrect.'
      }
    }
  }
}

var ITERATIONCOUNT_VALIDATOR = function ITERATIONCOUNT_VALIDATOR(v) {
  v = (v || "").toString().trim()
  if (v.match(INT_REGEXP)) {
    return {
      value: parseInt(v, 10)
    }
  } else if (v.match(/^infinite$/)) {
    return { value: -1 }
  } else {
    return {
      value: null,
      reason: function(k, v) {
          return 'ERROR: The format of value `' + v + '` of the `' +  util.camelCaseToHyphened(k) +
            '` attribute is incorrect (only integers and infinity are supported).'
      }
    }
  }
}

var BACKGROUND_SIZE_VALIDATOR = function BACKGROUND_SIZE_VALIDATOR(v) {
  v = (v || "").toString().trim()
  let values = v.split(/\s+/)
  const sizeReg = /auto|contain|cover/g
  if (values.length === 1) {
    if (/^(auto|contain|cover)$/.test(v)) {
      return { value: v }
    } else {
      return PERCENTAGE_LENGTH_VALIDATOR(v)
    }
  }
  if (values.length === 2 && !sizeReg.test(v)) {
    return SHORTHAND_VALIDATOR(v, PERCENTAGE_LENGTH_VALIDATOR)
  }
  return {
    value: null,
    reason: function(k, v) {
      return 'ERROR: Value `' + v + '` of the `' +  util.camelCaseToHyphened(k) + '` attribute is incorrect.'
    }
  }
}

var BACKGROUND_POSITION_VALIDATOR = function BACKGROUND_POSITION_VALIDATOR(v) {
  v = (v || '').toString().trim()
  let values = v.split(/\s+/)
  const positionReg = /left|right|top|bottom|center/g
  if (values.length === 1) {
    if (/^(left|right|top|bottom|center)$/.test(v)) {
      return { value: v }
    } else {
      return PERCENTAGE_LENGTH_VALIDATOR(v)
    }
  }
  if (values.length === 2) {
    if (!positionReg.test(v)) {
      return SHORTHAND_VALIDATOR(v, PERCENTAGE_LENGTH_VALIDATOR)
    } else {
      return CHECK_BACKGROUND_POSITION(v)
    }
  }
  return {
    value: null,
    reason: function(k, v) {
      return 'ERROR: Value `' + v + '` of the `' +  util.camelCaseToHyphened(k) + '` attribute is incorrect.'
    }
  }
}

var CHECK_BACKGROUND_POSITION = function CHECK_BACKGROUND_POSITION(v) {
  let values = v.split(/\s+/)
  let result = []
  let reasons = []
  let directions = []
  values.forEach(function(value, index) {
    if (/^(left|right|top|bottom|center)$/.test(value)) {
      result.push(value)
      if (checkDirection(value)) {
        directions.push(checkDirection(value))
      }
    } else {
      let tempResult = PERCENTAGE_LENGTH_VALIDATOR(value)
      if (tempResult.value) {
        result.push(value)
        if(index === 0){
          directions.push('horizon')
        } else {
          directions.push('vertical')
        }
      }
      if (tempResult.reason) {
        reasons.push(tempResult.reason)
      }
    }
  })
  if (directions.length === 2 && directions[0] === directions[1]) {
    reasons.push(function(k, v) {
      return 'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) + '` attribute is incorrect.'
    })
  }
  return {
    value: result.length > 0 ? result.join(' ') : null,
    reason: reasons.length > 0 ?
      function(k, v) {
        return reasons.map(function(res) {
          if (typeof res === 'function') {
            return res(k, v)
          }
        }).join('\n')
      }: null
  }
}

function checkDirection(v) {
  const scaleXReg = /^(left|right)$/
  const scaleYReg = /^(top|bottom)$/
  if (scaleXReg.test(v)) {
    return 'horizon'
  }
  if (scaleYReg.test(v)) {
    return 'vertical'
  }
  return null
}

var MYLOCATION_VALIDATOR = function MYLOCATION_VALIDATOR(v) {
  v = (v || "").toString().trim()
  let values = v.match(/\((.+?)\)/g) || []
  let replaceValue = null
  if (values.length) {
    for (let index = 0; index < values.length; index++) {
      replaceValue = values[index].replace(/\s*/g, "")
      v = v.replace(values[index], replaceValue);
    }
  }
  let realValues = v.split(/\s+/)
  let resultValues = []
  let valuesOrder = []
  let reason = null
  if (realValues && realValues.length <= 3) {
    realValues.forEach(function(realValue) {
      if (typeof COLOR_VAR_VALIDATOR(realValue).value == 'string') {
        resultValues.push(COLOR_VAR_VALIDATOR(realValue).value)
        valuesOrder.push(0)
      } else if (typeof URL_VALIDATOR(realValue).value == 'string') {
        resultValues.push(URL_VALIDATOR(realValue).value)
        valuesOrder.push(1)
      } else {
        reason = 'value'
      }
    })
    let n = -1
    valuesOrder.forEach(function(order) {
      if (order >= n) {
        n = order
      } else {
        if (!reason) {
          reason = 'order'
        }
      }
    })
    if (reason) {
      return {
        value : null,
        reason: function(k, v) {
          return reason == 'value' ?
            'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
            '` attribute does not meet the inspection standards for the color or url.' :
            'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
            '` attribute must be set in order(color color url).'
        }
      }
    }
    return {
      value: resultValues.join(" ")
    }
  }
  return {
    value: null,
    reason: function(k, v) {
      return 'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) + '` attribute is invalid.'
    }
  }
}

var TRANSFORM_ORIGIN_VALIDATOR = function TRANSFORM_ORIGIN_VALIDATOR(v) {
  v = (v || "").toString().trim()
  let values = v.split(/\s+/)
  const positionReg = /left|right|top|bottom|center/g
  if (values.length == 1) {
    if (/^(left|right|top|bottom|center)$/.test(v)) {
      return { value: v }
    } else {
      return PERCENTAGE_LENGTH_VALIDATOR(v);
    }
  }
  if (values.length == 2) {
    if (!positionReg.test(v)) {
      return SHORTHAND_VALIDATOR(v, PERCENTAGE_LENGTH_VALIDATOR)
    } else {
      return CHECK_TRANSFORM_ORIGIN(values)
    }
  }
  return {
    value: null,
    reason: function (k, v) {
      return 'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
        '` attribute is invalid. such as left 100px or 50% bottom.'
    }
  }
}

var CHECK_TRANSFORM_ORIGIN = function CHECK_TRANSFORM_ORIGIN(values) {
  let result = []
  let reasons = []
  let directions = []
  values.forEach(function (value, index) {
    if (/^(left|right|top|bottom|center)$/.test(value)) {
      result.push(value)
      directions.push(checkDirection(value))
    } else {
      let tempResult = PERCENTAGE_LENGTH_VALIDATOR(value)
      if (tempResult.value) {
        result.push(value)
        if (index === 0) {
          directions.push('horizon')
        } else {
          directions.push('vertical')
        }
      }
      if (tempResult.reason) {
        reasons.push(tempResult.reason)
      }
    }
  })
  if (directions.length != 2 || directions.length === 2 &&
    (directions[0] === 'vertical' || directions[1] === 'horizon')) {
    reasons.push(function (k, v) {
      return 'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) + '` attribute is incorrect.'
    })
  }
  return {
    value: result.length > 0 ? result.join(' ') : null,
    reason: reasons.length > 0 ?
      function (k, v) {
        return reasons.map(function (res) {
          if (typeof res === 'function') {
            return res(k, v)
          }
        }).join('\n')
      } : null
  }
}

var GRID_VALIDATOR = function GRID_VALIDATOR(v) {
  v = (v || '').toString().trim()
  if (v == 'auto' || v == 'auto-fill') {
    return { value: v }
  } else {
    return LENGTH(v, SUPPORT_CSS_GRID_UNIT)
  }
}

var GRID_TEMPLATE_VALIDATOR = function GRID_TEMPLATE_VALIDATOR(v) {
  v = (v || '').toString().trim()
  if (v.match(/^repeat/)) {
    let str = []
    if (v.match(/auto-fill/)) {
      let match = v.match(/^repeat\((.+),(.+)\)/)
      str.push(match[1].trim(), match[2].trim())
      return GRID_TEMPLATE_VALIDATOR(str.join(' '))
    } else {
      let match = v.match(/^repeat\((\d+),(.+)\)/)
      if (match[1] && match[2]) {
        let n = match[1]
          while (n > 0) {
            str.push(match[2].trim())
            n--
          }
        return GRID_TEMPLATE_VALIDATOR(str.join(' '))
      }
      else {
        return {
          value: null,
          reason: function reason(k, v, result) {
            return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' + v + '`.'
          }
        }
      }
    }
  }
  else {
    let value = []
    let reason = []
    let results = v.split(/\s+/).map(GRID_VALIDATOR)
    for (let i = 0; i < results.length; ++i) {
      let res = results[i]
      if (!res.value) {
        value = null
        reason = res.reason
        break
      }
      value.push(res.value)
      if (res.reason) {
        reason.push(res.reason)
      }
    }

    if (!value) {
      return {
        value: value,
        reason: reason
      }
    } else {
      return {
        value: value.join(' '),
        reason: reason.length > 0 ? function(k, v, result) {
          return reason.map(function (res) {
            if (typeof res === 'function') {
              return res(k, v, result)
            }
          }).join('\n')
        } : null
      }
    }
  }
}

var DATE_VALIDATOR = function DATE_VALIDATOR(v) {
  v = (v || '').toString().trim()
  if (DATE_REGEXP.test(v)) {
    return { value: v }
  } else {
    return {
      value: null,
      reason:function (k, v, result) {
        return 'ERROR: The format of value `' + v + '` of the `' +
          util.camelCaseToHyphened(k) + '` attribute is incorrect.'
      }
    }
  }
}

var FILTER_VALIDATOR = function FILTER_VALIDATOR(v) {
  v = (v || '').toString().trim().replace(/\s*/g, '')
  if (FILTER_REGEXP.test(v)) {
    return { value: v }
  } else {
    return {
      value: null,
      reason:function (k, v, result) {
        return 'ERROR: The format of value `' + v + '` of the `' +
          util.camelCaseToHyphened(k) + '` attribute is incorrect.'
      }
    }
  }
}

var FILTER_PERCENTAGE_VALIDATOR = function FILTER_PERCENTAGE_VALIDATOR(v) {
  v = (v || '').toString().trim().replace(/\s*,\s*/g, " ")
  if (FILTER_PERCENTAGE_REGEXP.test(v)) {
    return { value: v }
  }
  if (FILTER_STYLE_REGEXP.test(v)) {
    const values = v.trim().split(/\s+/)
    if(values[1] && values.length === 2){
      const blurStyleValidator = genEnumValidator(['small_light', 'medium_light', 'large_light',
        'xlarge_light', 'small_dark', 'medium_dark', 'large_dark', 'xlarge_dark'])
      const blurStyleResult = blurStyleValidator(values[1])
      if(util.isValidValue(blurStyleResult.value)){
        return { value: v }
      }
      let reasonMaps = [];
      let length = 0;
      let check = checkReason(blurStyleResult, 'window-filter', values[1], length)
      if(check.realReason !== null) {
        reasonMaps.push(check.realReason)
      }
      return {
        value: check.length < 2 ? JSON.stringify(blurStyleResult.value) : null,
        reason: function(k, v) {
          return 'ERROR: ' + reasonMaps
        }
      }
    }
  }
  return {
    value: null,
    reason:function (k, v, result) {
      return 'ERROR: The format of value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
        '` attribute is incorrect.'
    }
  }
}

var BORDER_IMAGE_VALIDATOR = function BORDER_IMAGE_VALIDATOR(v) {
  var regexp = /(repeating-linear|linear).*?(?=\s*(repeating|linear)|$)/g;
  if (regexp.test(v)) {
    return BORDER_IMAGE_GRADIENT_VALIDATOR(v);
  } else {
    return BORDER_IMAGE_URL_VALIDATOR(v);
  }
}

var BORDER_IMAGE_URL_VALIDATOR = function BORDER_IMAGE_URL_VALIDATOR(v) {
  let base = {
    values: []
  };
  let value = {
    url: "",
    repeat: ""
  };
  var URL_REGEXP_FIRST = /^url\(\s*['"]?\s*([^()]+?)\s*['"]?\s*\)(.*)/;
  var regexpFirst = /(stretch|round|repeat|space)$/;
  var URL_REGEXP_SECOND = /^(.*)(stretch|round|repeat|space)$/;
  let result;
  result = URL_REGEXP_FIRST.exec(v);
  if (regexpFirst.test(result[2])) {
    let res = URL_REGEXP_SECOND.exec(result[2]);
    value = BORDER_IMAGE_NOL(res[1]);
    value.repeat = res[2];
  } else {
    var reg = /px|%/;
    if (reg.test(result[2])) {
      value = BORDER_IMAGE_NOL(result[2]);
    }
  }
  value.url = result[1];
  base.values.push(value);
  return {
    value: JSON.stringify(base)
  };
}

var BORDER_IMAGE_NOL = function BORDER_IMAGE_NOL(v) {
  let value = {
    url: "",
    repeat: ""
  };
  var reg = /px|%/;
  if (!reg.test(v)) {
    return value;
  }
  let num = v.split(/\//);
  switch (num.length) {
    case 1:
    value.slice = BORDER_IMAGE_SPLIT(num[0]);
    break;
    case 2:
    value.slice = BORDER_IMAGE_SPLIT(num[0]);
    value.width = BORDER_IMAGE_SPLIT(num[1]);
    break;
    case 3:
    value.slice = BORDER_IMAGE_SPLIT(num[0]);
    value.width = BORDER_IMAGE_SPLIT(num[1]);
    value.outset = BORDER_IMAGE_SPLIT(num[2]);
    break;
  }
  return value;
}

var BORDER_IMAGE_SPLIT = function BORDER_IMAGE_SPLIT(v) {
  const NUM_REGEXP = SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR(v);
  let result = [];
  const value = NUM_REGEXP.value.split(/\s/);
  value.forEach(element => {
    result.push(element);
  });
  return result;
}

var BORDER_IMAGE_GRADIENT_VALIDATOR = function BORDER_IMAGE_GRADIENT_VALIDATOR(v) {
  v = (v || "").toString().trim()
  var BORDER_IMAGE_GRADIENT_ITEM_REGEXP = /^([0-9a-zA-Z-]+)\((.*)\)(.*)/;
  let base = {
    values: []
  }
  let valueMatch = v.match(BORDER_IMAGE_GRADIENT_ITEM_REGEXP)
  if (valueMatch) {
    const gradientStr = valueMatch[1].toString() + '(' + valueMatch[2].toString() + ')';
    const gradient = LINEAR_GRADIENT_VALIDATOR(gradientStr);
    let value = {};
    if (util.isValidValue(gradient.value)) {
      value = JSON.parse(gradient.value)
    }
    var reg = /px|%/;
    if (valueMatch[3].match(reg)) {
      value.slice = BORDER_IMAGE_SPLIT(valueMatch[3]);
    }
    base.values.push(value);
    return {
      value: JSON.stringify(base),
      reason: gradient.reason
    }
  }
  return {
    value: null,
    reason: function(k, v) {
      return 'ERROR: The format of value `' + v + '` of the `' + util.camelCaseToHyphened(k)
        + '` attribute is incorrect.'
    }
  }
}

var Color_Picker_VALIDATOR = function Color_Picker_VALIDATOR(v) {
  v = (v || "").toString().trim()
  let num = v.split(/\//);
  let base = {
    cValues: []
  }
  num.forEach(element => {
    base.cValues.push(COLOR_VAR_VALIDATOR(element).value);
  });
  return {
    value: JSON.stringify(base)
  }
}

var RICH_PROP_NAME_GROUPS = {
  boxModel: {
    width: PERCENTAGE_LENGTH_VALIDATOR,
    height: PERCENTAGE_LENGTH_VALIDATOR,
    overflow: genEnumValidator(['auto', 'hidden','scroll','visible']),
    padding: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
    paddingLeft: PERCENTAGE_LENGTH_VALIDATOR,
    paddingRight: PERCENTAGE_LENGTH_VALIDATOR,
    paddingTop: PERCENTAGE_LENGTH_VALIDATOR,
    paddingBottom: PERCENTAGE_LENGTH_VALIDATOR,
    paddingStart: PERCENTAGE_LENGTH_VALIDATOR,
    paddingEnd: PERCENTAGE_LENGTH_VALIDATOR,
    margin: SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginLeft: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginRight: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginTop: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginBottom: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginStart: PERCENTAGE_LENGTH_VALIDATOR,
    marginEnd: PERCENTAGE_LENGTH_VALIDATOR,
    placeholderColor: COLOR_VAR_VALIDATOR,
    selectedColor: COLOR_VAR_VALIDATOR,
    caretColor: COLOR_VAR_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
    progressColor: COLOR_VAR_VALIDATOR,
    slideWidth: LENGTH_VALIDATOR,
    slideMargin: LENGTH_VALIDATOR,
    resizeMode: genEnumValidator(['cover', 'contain', 'stretch', 'center']),
    columns: NUMBER_VALIDATOR,
    columnSpan: NUMBER_VALIDATOR,
    maskColor: COLOR_VAR_VALIDATOR,
    mylocation: MYLOCATION_VALIDATOR,
    mylocationFillColor: COLOR_VAR_VALIDATOR,
    mylocationStrokeColor: COLOR_VAR_VALIDATOR,
    mylocationIconPath: URL_VALIDATOR,
    displayIndex: NUMBER_VALIDATOR,
    aspectRatio: NUMBER_VALIDATOR,
    minWidth: PERCENTAGE_LENGTH_VALIDATOR,
    minHeight: PERCENTAGE_LENGTH_VALIDATOR,
    maxWidth: PERCENTAGE_LENGTH_VALIDATOR,
    maxHeight: PERCENTAGE_LENGTH_VALIDATOR,
    flexWeight: NUMBER_VALIDATOR,
    boxShadow: BOX_SHADOW_VALIDATOR,
    boxShadowH: LENGTH_VALIDATOR,
    boxShadowV: LENGTH_VALIDATOR,
    boxShadowBlur: LENGTH_VALIDATOR,
    boxShadowSpread: LENGTH_VALIDATOR,
    boxShadowColor: COLOR_VAR_VALIDATOR,
    filter: FILTER_VALIDATOR,
    backdropFilter: FILTER_VALIDATOR,
    windowFilter: FILTER_PERCENTAGE_VALIDATOR,
    transitionEffect: genEnumValidator(['unfold', 'none'])
  },
  div: {
    gridTemplateColumns: GRID_TEMPLATE_VALIDATOR,
    gridTemplateRows: GRID_TEMPLATE_VALIDATOR,
    gridGap: LENGTH_VALIDATOR,
    gridColumnsGap: LENGTH_VALIDATOR,
    gridRowsGap: LENGTH_VALIDATOR,
    gridRowStart: NUMBER_VALIDATOR,
    gridRowEnd: NUMBER_VALIDATOR,
    gridColumnStart: NUMBER_VALIDATOR,
    gridColumnEnd: NUMBER_VALIDATOR,
    gridAutoFlow: genEnumValidator(['row', 'column'])
  },
  border: {
    border: BORDER_VALIDATOR,
    borderWidth: SHORTHAND_LENGTH_VALIDATOR,
    borderLeftWidth: LENGTH_VALIDATOR,
    borderTopWidth: LENGTH_VALIDATOR,
    borderRightWidth: LENGTH_VALIDATOR,
    borderBottomWidth: LENGTH_VALIDATOR,
    borderColor: SHORTHAND_COLOR_VALIDATOR,
    borderLeftColor: COLOR_VAR_VALIDATOR,
    borderTopColor: COLOR_VAR_VALIDATOR,
    borderRightColor: COLOR_VAR_VALIDATOR,
    borderBottomColor: COLOR_VAR_VALIDATOR,
    borderStyle: SHORTHAND_STYLE_VALIDATOR,
    borderTopStyle: STYLE_VALIDATOR,
    borderRightStyle: STYLE_VALIDATOR,
    borderBottomStyle: STYLE_VALIDATOR,
    borderLeftStyle: STYLE_VALIDATOR,
    borderRadius: PERCENTAGE_LENGTH_VALIDATOR,
    borderBottomLeftRadius: PERCENTAGE_LENGTH_VALIDATOR,
    borderBottomRightRadius: PERCENTAGE_LENGTH_VALIDATOR,
    borderTopLeftRadius: PERCENTAGE_LENGTH_VALIDATOR,
    borderTopRightRadius: PERCENTAGE_LENGTH_VALIDATOR,
    borderLeft: BORDER_VALIDATOR,
    borderRight: BORDER_VALIDATOR,
    borderTop: BORDER_VALIDATOR,
    borderBottom: BORDER_VALIDATOR,
    borderImage: BORDER_IMAGE_VALIDATOR,
    borderImageSource: URL_VALIDATOR,
    borderImageOutset: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
    borderImageSlice: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
    borderImageWidth: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
    borderImageRepeat: genEnumValidator(['stretch', 'round', 'repeat', 'space'])
  },
  indicator: {
    indicatorSize: LENGTH_VALIDATOR,
    indicatorTop: PERCENTAGE_LENGTH_VALIDATOR,
    indicatorRight: PERCENTAGE_LENGTH_VALIDATOR,
    indicatorBottom: PERCENTAGE_LENGTH_VALIDATOR,
    indicatorLeft: PERCENTAGE_LENGTH_VALIDATOR,
    indicatorColor: COLOR_VAR_VALIDATOR,
    indicatorSelectedColor: COLOR_VAR_VALIDATOR
  },
  animation: {
    animationDuration: TIME_VALIDATOR,
    animationDelay: TIME_VALIDATOR,
    animationName: NAME_VALIDATOR,
    animationTimingFunction: TRANSITION_TIMING_FUNCTION_VALIDATOR,
    animationIterationCount: ITERATIONCOUNT_VALIDATOR,
    animationFillMode: genEnumValidator(['none', 'forwards', 'backwards', 'both']),
    animationPlayState: genEnumValidator(['running', 'paused']),
    animationDirection: genEnumValidator(['normal', 'reverse', 'alternate', 'alternate-reverse']),
    animation: ANIMATION_VALIDATOR,
  },
  flexbox: {
    flex: genEnumValidator(['none', 'auto', 'initial']),
    flexWrap: genEnumValidator(['nowrap', 'wrap']),
    flexGrow: NUMBER_VALIDATOR,
    flexShrink: NUMBER_VALIDATOR,
    flexBasis: LENGTH_VALIDATOR,
    flexDirection: genEnumValidator(['row', 'column']),
    justifyContent: genEnumValidator(['flex-start', 'flex-end', 'center', 'space-between',
      'space-around', 'space-evenly']),
    alignItems: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center', 'baseline']),
    alignContent: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center', 'space-between', 'space-around']),
    alignSelf: genEnumValidator(["auto", "flex-start", "flex-end", "center", "baseline", "stretch"])
  },
  position: {
    position: genEnumValidator(['relative', 'fixed', 'absolute']),
    top: PERCENTAGE_LENGTH_VALIDATOR,
    bottom: PERCENTAGE_LENGTH_VALIDATOR,
    left: PERCENTAGE_LENGTH_VALIDATOR,
    right: PERCENTAGE_LENGTH_VALIDATOR,
    zIndex: INTEGER_VALIDATOR
  },
  common: {
    opacity: NUMBER_VALIDATOR,
    background: BACKGROUND_VALIDATOR,
    backgroundColor: COLOR_VAR_VALIDATOR,
    backgroundImage: URL_VALIDATOR,
    backgroundRepeat: genEnumValidator(['repeat', 'no-repeat', 'repeat-x', 'repeat-y']),
    visibility: genEnumValidator(['visible', 'hidden']),
    objectFit: genEnumValidator(['cover', 'fill', 'contain', 'none', 'scale-down']),
    backgroundSize: BACKGROUND_SIZE_VALIDATOR,
    backgroundPosition: BACKGROUND_POSITION_VALIDATOR,
    display: genEnumValidator(['flex', 'none', 'grid']),
    imageFill: COLOR_VAR_VALIDATOR,
    maskImage: MASK_VALIDATOR,
    maskPosition: BACKGROUND_POSITION_VALIDATOR,
    maskSize: BACKGROUND_SIZE_VALIDATOR
  },
  text: {
    lines: INTEGER_VALIDATOR,
    color: COLOR_VAR_VALIDATOR,
    fontSize: LENGTH_VALIDATOR,
    fontStyle: genEnumValidator(['normal', 'italic']),
    fontFamily: ANYTHING_VALIDATOR,
    fontWeight: genEnumValidator(['normal', 'lighter', 'bold', 'bolder', "medium", "regular",
      '100', '200', '300', '400', '500', '600', '700', '800', '900']),
    textDecoration: genEnumValidator(['none', 'underline', 'line-through']),
    textAlign: genEnumValidator(['start', 'end', 'left', 'center', 'right']),
    textOverflow: genEnumValidator(['clip', 'ellipsis']),
    textIndent: TEXT_INDENT_VALIDATOR,
    lineHeight: TEXT_LINE_HEIGHT_VALIDATOR,
    letterSpacing: LENGTH_VALIDATOR,
    minLines: NUMBER_VALIDATOR,
    maxLines: ANYTHING_VALIDATOR,
    minFontSize: LENGTH_VALIDATOR,
    maxFontSize: LENGTH_VALIDATOR,
    fontSizeStep: LENGTH_VALIDATOR,
    preferFontSizes: ARRAY_LENGTH_VALIDATOR,
    adaptHeight: genEnumValidator(['true', 'false']),
    allowScale: genEnumValidator(['true', 'false']),
    fontVariant: ANYTHING_VALIDATOR,
    id: ANYTHING_VALIDATOR,
    x: PERCENTAGE_LENGTH_VALIDATOR,
    y: PERCENTAGE_LENGTH_VALIDATOR,
    dx: PERCENTAGE_LENGTH_VALIDATOR,
    dy: PERCENTAGE_LENGTH_VALIDATOR,
    rotate: NUMBER_VALIDATOR,
    fill: COLOR_VAR_VALIDATOR,
    fillOpacity: NUMBER_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
    fontFeatureSettings: ANYTHING_VALIDATOR,
    textDecorationColor: COLOR_VAR_VALIDATOR
  },
  calendar: {
    boundaryColOffset: LENGTH_VALIDATOR,
    boundaryRowOffset: LENGTH_VALIDATOR,
    colSpace: LENGTH_VALIDATOR,
    dailyFiveRowSpace: LENGTH_VALIDATOR,
    dayColor: COLOR_VAR_VALIDATOR,
    dayFontSize: LENGTH_VALIDATOR,
    dayHeight: LENGTH_VALIDATOR,
    dayWidth: LENGTH_VALIDATOR,
    focusedAreaBackgroundColor: COLOR_VAR_VALIDATOR,
    focusedAreaRadius: LENGTH_VALIDATOR,
    focusedDayColor: COLOR_VAR_VALIDATOR,
    focusedLunarColor: COLOR_VAR_VALIDATOR,
    gregorianCalendarHeight: LENGTH_VALIDATOR,
    lunarColor: COLOR_VAR_VALIDATOR,
    lunarDayFontSize: LENGTH_VALIDATOR,
    lunarDayYAxisOffset: LENGTH_VALIDATOR,
    lunarHeight: LENGTH_VALIDATOR,
    markLunarColor: COLOR_VAR_VALIDATOR,
    nonCurrentMonthDayColor: COLOR_VAR_VALIDATOR,
    nonCurrentMonthLunarColor: COLOR_VAR_VALIDATOR,
    nonCurrentMonthOffDayMarkColor: COLOR_VAR_VALIDATOR,
    nonCurrentMonthWorkDayMarkColor: COLOR_VAR_VALIDATOR,
    offDayMarkColor: COLOR_VAR_VALIDATOR,
    offDayMarkSize: LENGTH_VALIDATOR,
    scheduleMarkerRadius: LENGTH_VALIDATOR,
    scheduleMarkerXAxisOffset: LENGTH_VALIDATOR,
    scheduleMarkerYAxisOffset: LENGTH_VALIDATOR,
    underscoreLength: LENGTH_VALIDATOR,
    underscoreWidth: LENGTH_VALIDATOR,
    underscoreXAxisOffset: LENGTH_VALIDATOR,
    underscoreYAxisOffset: LENGTH_VALIDATOR,
    weekAndDayRowSpace: LENGTH_VALIDATOR,
    weekColor: COLOR_VAR_VALIDATOR,
    weekFontSize: LENGTH_VALIDATOR,
    weekHeight: LENGTH_VALIDATOR,
    weekWidth: LENGTH_VALIDATOR,
    weekendDayColor: COLOR_VAR_VALIDATOR,
    weekendLunarColor: COLOR_VAR_VALIDATOR,
    workDayMarkColor: COLOR_VAR_VALIDATOR,
    workDayMarkSize: LENGTH_VALIDATOR,
    workStateHorizontalMovingDistance: LENGTH_VALIDATOR,
    workStateVerticalMovingDistance: LENGTH_VALIDATOR,
    workStateWidth: LENGTH_VALIDATOR
  },
  rating: {
    starBackground: URL_VALIDATOR,
    starForeground: URL_VALIDATOR,
    starSecondary: URL_VALIDATOR,
    rtlFlip: genEnumValidator(['true', 'false'])
  },
  transition: {
    transitionProperty: TRANSITION_PROPERTY_VALIDATOR,
    transitionDuration: TRANSITION_INTERVAL_VALIDATOR,
    transitionDelay: TRANSITION_INTERVAL_VALIDATOR,
    transitionEnter: NAME_VALIDATOR,
    transitionExit: NAME_VALIDATOR,
    transitionDuration: TIME_VALIDATOR,
    transitionTimingFunction: TRANSITION_TIMING_FUNCTION_VALIDATOR
  },
  transform: {
    transform: TRANSFORM_VALIDATOR,
    transformOrigin: TRANSFORM_ORIGIN_VALIDATOR
  },
  customized: {
    itemSize: LENGTH_VALIDATOR,
    itemColor: COLOR_VAR_VALIDATOR,
    itemSelectedColor: COLOR_VAR_VALIDATOR,
    textColor: COLOR_VAR_VALIDATOR,
    timeColor: COLOR_VAR_VALIDATOR,
    textHighlightColor: COLOR_VAR_VALIDATOR
  },
  list: {
    itemExtent: PERCENTAGE_LENGTH_VALIDATOR,
    fadeColor: COLOR_VAR_VALIDATOR,
    dividerColor: COLOR_VAR_VALIDATOR,
    dividerHeight: LENGTH_VALIDATOR,
    dividerLength: LENGTH_VALIDATOR,
    dividerOrigin: LENGTH_VALIDATOR,
    scrollbarColor: COLOR_VALIDATOR,
    scrollbarWidth: LENGTH_VALIDATOR,
    scrollbarOffset: ARRAY_LENGTH_VALIDATOR
  },
  progress: {
    secondaryColor: COLOR_VAR_VALIDATOR,
    scaleWidth: LENGTH_VALIDATOR,
    scaleNumber: NUMBER_VALIDATOR,
    startAngle: ANGLE_VALIDATOR,
    totalAngle: ANGLE_VALIDATOR,
    centerX: LENGTH_VALIDATOR,
    centerY: LENGTH_VALIDATOR,
    radius: LENGTH_VALIDATOR,
    direction: genEnumValidator(['start-to-end', 'end-to-start']),
    sections: NAME_VALIDATOR,
    colors: ARRAY_COLOR_VALIDATOR,
    weights: ARRAY_NUMBER_VALIDATOR
  },
  navigation: {
    titleColor: COLOR_VAR_VALIDATOR,
    subtitleColor: COLOR_VAR_VALIDATOR
  },
  button: {
    iconWidth: LENGTH_VALIDATOR,
    iconHeight: LENGTH_VALIDATOR
  },
  switch: {
    textonColor: COLOR_VAR_VALIDATOR,
    textoffColor: COLOR_VAR_VALIDATOR,
    textPadding: LENGTH_VALIDATOR
  },
  share: {
    sharedTransitionEffect: genEnumValidator(['exchange', 'static']),
    sharedTransitionName: NAME_VALIDATOR,
    sharedTransitionTimingFunction: TRANSITION_TIMING_FUNCTION_VALIDATOR
  },
  image: {
    matchTextDirection: genEnumValidator(['false', 'true']),
    fitOriginalSize: genEnumValidator(['false', 'true']),
  },
  divider: {
    lineCap: genEnumValidator(['butt', 'square', 'round'])
  },
  picker: {
    columnHeight: LENGTH_VALIDATOR
  },
  pickerView: {
    selectedFontSize: LENGTH_VALIDATOR,
    selectedFontFamily: ANYTHING_VALIDATOR,
    focusColor: COLOR_VAR_VALIDATOR,
    focusFontSize: LENGTH_VALIDATOR,
    focusFontFamily: ANYTHING_VALIDATOR,
    disappearFontSize: LENGTH_VALIDATOR,
    disappearColor: COLOR_VAR_VALIDATOR
  },
  colorpicker: {
    colorPickerColor: Color_Picker_VALIDATOR
  },
  colorpickerView: {
    colorPickerColor: Color_Picker_VALIDATOR
  },
  slider: {
    blockColor: COLOR_VAR_VALIDATOR,
  },
  badge: {
    badgeColor: COLOR_VAR_VALIDATOR,
    badgeSize: LENGTH_VALIDATOR
  },
  ellipse: {
    fill: COLOR_VAR_VALIDATOR,
    fillOpacity: NUMBER_VALIDATOR,
    fillRule: genEnumValidator(['nonzero', 'evenodd']),
    opacity: NUMBER_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR,
    strokeDasharray: ANYTHING_VALIDATOR,
    strokeDashoffset: LENGTH_VALIDATOR,
    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
    strokeMiterlimit: NUMBER_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
    transform: TRANSFORM_VALIDATOR,
    id: ANYTHING_VALIDATOR,
    cx: PERCENTAGE_LENGTH_VALIDATOR,
    cy: PERCENTAGE_LENGTH_VALIDATOR,
    rx: PERCENTAGE_LENGTH_VALIDATOR,
    ry: PERCENTAGE_LENGTH_VALIDATOR
  },
  rect: {
    id: ANYTHING_VALIDATOR,
    fill: COLOR_VAR_VALIDATOR,
    fillOpacity: NUMBER_VALIDATOR,
    fillRule: genEnumValidator(['nonzero', 'evenodd']),
    opacity: NUMBER_VALIDATOR,
    strokeDasharray: ANYTHING_VALIDATOR,
    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
    strokeMiterlimit: NUMBER_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
    transform: TRANSFORM_VALIDATOR,
    width: PERCENTAGE_LENGTH_VALIDATOR,
    height: PERCENTAGE_LENGTH_VALIDATOR,
    x: PERCENTAGE_LENGTH_VALIDATOR,
    y: PERCENTAGE_LENGTH_VALIDATOR,
    rx: PERCENTAGE_LENGTH_VALIDATOR,
    ry: PERCENTAGE_LENGTH_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR,
    strokeDashoffset: LENGTH_VALIDATOR
  },
  circle: {
    fill: COLOR_VAR_VALIDATOR,
    fillOpacity: NUMBER_VALIDATOR,
    fillRule: genEnumValidator(['nonzero', 'evenodd']),
    opacity: NUMBER_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR,
    strokeDasharray: ANYTHING_VALIDATOR,
    strokeDashoffset: LENGTH_VALIDATOR,
    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
    strokeMiterlimit: NUMBER_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
    transform: TRANSFORM_VALIDATOR,
    id: ANYTHING_VALIDATOR,
    cx: PERCENTAGE_LENGTH_VALIDATOR,
    cy: PERCENTAGE_LENGTH_VALIDATOR,
    r: PERCENTAGE_LENGTH_VALIDATOR
  },
  path: {
    fillOpacity: NUMBER_VALIDATOR,
    fillRule: genEnumValidator(['nonzero', 'evenodd']),
    opacity: NUMBER_VALIDATOR,
    strokeDashoffset: LENGTH_VALIDATOR,
    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
    strokeMiterlimit: NUMBER_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
    transform: TRANSFORM_VALIDATOR,
    id: ANYTHING_VALIDATOR,
    d: ANYTHING_VALIDATOR,
    fill: COLOR_VAR_VALIDATOR,
    strokeDasharray: ANYTHING_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR
  },
  svg: {
    fill: COLOR_VAR_VALIDATOR,
    fillOpacity: NUMBER_VALIDATOR,
    fillRule: genEnumValidator(['nonzero', 'evenodd']),
    opacity: NUMBER_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR,
    strokeDasharray: ANYTHING_VALIDATOR,
    strokeDashoffset: LENGTH_VALIDATOR,
    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
    strokeMiterlimit: NUMBER_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
    transform: TRANSFORM_VALIDATOR,
    id: ANYTHING_VALIDATOR,
    width: PERCENTAGE_LENGTH_VALIDATOR,
    height: PERCENTAGE_LENGTH_VALIDATOR,
    x: PERCENTAGE_LENGTH_VALIDATOR,
    y: PERCENTAGE_LENGTH_VALIDATOR,
    viewbox: ANYTHING_VALIDATOR
  },
  polygon: {
    fill: COLOR_VAR_VALIDATOR,
    fillOpacity: NUMBER_VALIDATOR,
    opacity: NUMBER_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR,
    strokeDasharray: ANYTHING_VALIDATOR,
    strokeDashoffset: LENGTH_VALIDATOR,
    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
    strokeMiterlimit: NUMBER_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
    transform: TRANSFORM_VALIDATOR,
    id: ANYTHING_VALIDATOR,
    points: ANYTHING_VALIDATOR,
    fillRule: genEnumValidator(['nonzero', 'evenodd'])
  },
  polyline: {
    fill: COLOR_VAR_VALIDATOR,
    fillOpacity: NUMBER_VALIDATOR,
    opacity: NUMBER_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR,
    strokeDasharray: ANYTHING_VALIDATOR,
    strokeDashoffset: LENGTH_VALIDATOR,
    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
    strokeMiterlimit: NUMBER_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
    transform: TRANSFORM_VALIDATOR,
    id: ANYTHING_VALIDATOR,
    points: ANYTHING_VALIDATOR,
    fillRule: genEnumValidator(['nonzero', 'evenodd'])
  },
  tspan: {
    id: ANYTHING_VALIDATOR,
    x: PERCENTAGE_LENGTH_VALIDATOR,
    y: PERCENTAGE_LENGTH_VALIDATOR,
    dx: PERCENTAGE_LENGTH_VALIDATOR,
    dy: PERCENTAGE_LENGTH_VALIDATOR,
    rotate: NUMBER_VALIDATOR,
    fontSize: LENGTH_VALIDATOR,
    fill: COLOR_VAR_VALIDATOR,
    fillOpacity: NUMBER_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR
  },
  textPath: {
    id: ANYTHING_VALIDATOR,
    path: ANYTHING_VALIDATOR,
    startOffset: PERCENTAGE_LENGTH_VALIDATOR,
    fontSize: LENGTH_VALIDATOR,
    fill: COLOR_VAR_VALIDATOR,
    fillOpacity: NUMBER_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR
  },
  animate: {
    id: ANYTHING_VALIDATOR,
    attributeName: ANYTHING_VALIDATOR,
    begin: ANYTHING_VALIDATOR,
    dur: ANYTHING_VALIDATOR,
    end: ANYTHING_VALIDATOR,
    repeatCount: ANYTHING_VALIDATOR,
    fill: genEnumValidator(['freeze', 'remove']),
    calcMode: genEnumValidator(['discrete', 'linear', 'paced', 'spline']),
    keyTimes: ANYTHING_VALIDATOR,
    keySplines: ANYTHING_VALIDATOR,
    from: ANYTHING_VALIDATOR,
    to: ANYTHING_VALIDATOR,
    values: ANYTHING_VALIDATOR
  },
  animateMotion: {
    id: ANYTHING_VALIDATOR,
    attributeName: ANYTHING_VALIDATOR,
    begin: ANYTHING_VALIDATOR,
    dur: ANYTHING_VALIDATOR,
    end: ANYTHING_VALIDATOR,
    repeatCount: ANYTHING_VALIDATOR,
    fill: genEnumValidator(['freeze', 'remove']),
    calcMode: genEnumValidator(['discrete', 'linear', 'paced', 'spline']),
    keyTimes: ANYTHING_VALIDATOR,
    keySplines: ANYTHING_VALIDATOR,
    from: ANYTHING_VALIDATOR,
    to: ANYTHING_VALIDATOR,
    keyPoints: ANYTHING_VALIDATOR,
    path: ANYTHING_VALIDATOR,
    rotate: ANYTHING_VALIDATOR
  },
  animateTransform: {
    id: ANYTHING_VALIDATOR,
    attributeName: ANYTHING_VALIDATOR,
    begin: ANYTHING_VALIDATOR,
    dur: ANYTHING_VALIDATOR,
    end: ANYTHING_VALIDATOR,
    repeatCount: ANYTHING_VALIDATOR,
    fill: genEnumValidator(['freeze', 'remove']),
    calcMode: genEnumValidator(['discrete', 'linear', 'paced', 'spline']),
    from: ANYTHING_VALIDATOR,
    to: ANYTHING_VALIDATOR,
    type: genEnumValidator(['translate', 'scale', 'skewX', 'skewY'])
  },
  line: {
    fill: COLOR_VAR_VALIDATOR,
    fillOpacity: NUMBER_VALIDATOR,
    opacity: NUMBER_VALIDATOR,
    stroke: COLOR_VAR_VALIDATOR,
    strokeDasharray: ANYTHING_VALIDATOR,
    strokeDashoffset: LENGTH_VALIDATOR,
    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
    strokeMiterlimit: NUMBER_VALIDATOR,
    strokeOpacity: NUMBER_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
    fillRule: genEnumValidator(['nonzero', 'evenodd']),
    transform: TRANSFORM_VALIDATOR,
    id: ANYTHING_VALIDATOR,
    x1: PERCENTAGE_LENGTH_VALIDATOR,
    y1: PERCENTAGE_LENGTH_VALIDATOR,
    x2: PERCENTAGE_LENGTH_VALIDATOR,
    y2: PERCENTAGE_LENGTH_VALIDATOR
  }
}

var LITE_PROP_NAME_GROUPS = {
  boxModel: {
    width: PERCENTAGE_LENGTH_VALIDATOR,
    height: PERCENTAGE_LENGTH_VALIDATOR,
    padding: SHORTHAND_LENGTH_VALIDATOR,
    paddingLeft: LENGTH_VALIDATOR,
    paddingRight: LENGTH_VALIDATOR,
    paddingTop: LENGTH_VALIDATOR,
    paddingBottom: LENGTH_VALIDATOR,
    margin:SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginLeft: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginRight: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginTop: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginBottom: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    strokeWidth: LENGTH_VALIDATOR,
  },
  border:{
    borderWidth: SHORTHAND_LENGTH_VALIDATOR,
    borderColor: SHORTHAND_COLOR_VALIDATOR,
    borderRadius: LENGTH_VALIDATOR,
  },
  animation:{
    animationDuration: TIME_VALIDATOR,
    animationDelay: TIME_VALIDATOR,
    animationName: NAME_VALIDATOR,
    animationTimingFunction: genEnumValidator(['linear', 'ease-in', 'ease-out', 'ease-in-out']),
    animationIterationCount: ITERATIONCOUNT_VALIDATOR,
    animationFillMode: genEnumValidator(['none', 'forwards'])
  },
  flexbox: {
    flexDirection: genEnumValidator(['row', 'column']),
    flexWrap: genEnumValidator(['nowrap', 'wrap']),
    justifyContent: genEnumValidator(['flex-start', 'flex-end', 'center', 'space-between',
      'space-around', 'space-evenly']),
    alignItems: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center']),
  },
  position: {
    top: PERCENTAGE_LENGTH_VALIDATOR,
    left: PERCENTAGE_LENGTH_VALIDATOR,
  },
  common: {
    opacity: NUMBER_VALIDATOR,
    backgroundColor: COLOR_VAR_VALIDATOR,
    backgroundImage: URL_VALIDATOR,
    placeholderColor: COLOR_VAR_VALIDATOR,
    display: genEnumValidator(['flex', 'none']),
  },
  text: {
    color: COLOR_VAR_VALIDATOR,
    fontSize: LENGTH_VALIDATOR,
    fontFamily: genEnumValidator(['HYQiHei-65S']),
    letterSpacing: LENGTH_VALIDATOR,
    textAlign: genEnumValidator(['left', 'center', 'right']),
    textOverflow: genEnumValidator(['clip', 'ellipsis']),
  },
  slider: {
    selectedColor: COLOR_VAR_VALIDATOR,
    selectedFontSize: LENGTH_VALIDATOR,
    selectedFontFamily: genEnumValidator(['HYQiHei-65S']),
    blockColor: COLOR_VAR_VALIDATOR,
  },
  transform: {
    transform: TRANSFORM_VALIDATOR,
  },
  progress: {
    centerX: LENGTH_VALIDATOR,
    centerY: LENGTH_VALIDATOR,
    radius: LENGTH_VALIDATOR,
    startAngle: ANGLE_VALIDATOR,
    totalAngle: ANGLE_VALIDATOR
  }
}

var CARD_PROP_NAME_GROUPS = {
  boxModel: {
    width: PERCENTAGE_LENGTH_VALIDATOR,
    height: PERCENTAGE_LENGTH_VALIDATOR,
    overflow: genEnumValidator(['auto', 'hidden','scroll','visible']),
    padding: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
    paddingLeft: PERCENTAGE_LENGTH_VALIDATOR,
    paddingRight: PERCENTAGE_LENGTH_VALIDATOR,
    paddingTop: PERCENTAGE_LENGTH_VALIDATOR,
    paddingBottom: PERCENTAGE_LENGTH_VALIDATOR,
    paddingStart: PERCENTAGE_LENGTH_VALIDATOR,
    paddingEnd: PERCENTAGE_LENGTH_VALIDATOR,
    margin: SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginLeft: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginRight: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginTop: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginBottom: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
    marginStart: PERCENTAGE_LENGTH_VALIDATOR,
    marginEnd: PERCENTAGE_LENGTH_VALIDATOR,
    columns: NUMBER_VALIDATOR,
    displayIndex: NUMBER_VALIDATOR,
    aspectRatio: NUMBER_VALIDATOR,
    minWidth: PERCENTAGE_LENGTH_VALIDATOR,
    minHeight: PERCENTAGE_LENGTH_VALIDATOR,
    maxWidth: PERCENTAGE_LENGTH_VALIDATOR,
    maxHeight: PERCENTAGE_LENGTH_VALIDATOR,
    flexWeight: NUMBER_VALIDATOR,
    boxShadow: BOX_SHADOW_VALIDATOR,
    boxShadowH: LENGTH_VALIDATOR,
    boxShadowV: LENGTH_VALIDATOR,
    boxShadowBlur: LENGTH_VALIDATOR,
    boxShadowSpread: LENGTH_VALIDATOR,
    boxShadowColor: COLOR_VAR_VALIDATOR,
    filter: FILTER_VALIDATOR,
    backdropFilter: FILTER_VALIDATOR,
    windowFilter: FILTER_PERCENTAGE_VALIDATOR
  },
  div: {
    gridTemplateColumns: GRID_TEMPLATE_VALIDATOR,
    gridTemplateRows: GRID_TEMPLATE_VALIDATOR,
    gridGap: LENGTH_VALIDATOR,
    gridColumnsGap: LENGTH_VALIDATOR,
    gridRowsGap: LENGTH_VALIDATOR,
    gridRowStart: NUMBER_VALIDATOR,
    gridRowEnd: NUMBER_VALIDATOR,
    gridColumnStart: NUMBER_VALIDATOR,
    gridColumnEnd: NUMBER_VALIDATOR
  },
  border: {
    border: BORDER_VALIDATOR,
    borderWidth: SHORTHAND_LENGTH_VALIDATOR,
    borderLeftWidth: LENGTH_VALIDATOR,
    borderTopWidth: LENGTH_VALIDATOR,
    borderRightWidth: LENGTH_VALIDATOR,
    borderBottomWidth: LENGTH_VALIDATOR,
    borderColor: SHORTHAND_COLOR_VALIDATOR,
    borderLeftColor: COLOR_VAR_VALIDATOR,
    borderTopColor: COLOR_VAR_VALIDATOR,
    borderRightColor: COLOR_VAR_VALIDATOR,
    borderBottomColor: COLOR_VAR_VALIDATOR,
    borderStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
    borderTopStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
    borderRightStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
    borderBottomStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
    borderLeftStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
    borderRadius: LENGTH_VALIDATOR,
    borderBottomLeftRadius: LENGTH_VALIDATOR,
    borderBottomRightRadius: LENGTH_VALIDATOR,
    borderTopLeftRadius: LENGTH_VALIDATOR,
    borderTopRightRadius: LENGTH_VALIDATOR,
    borderLeft: BORDER_VALIDATOR,
    borderRight: BORDER_VALIDATOR,
    borderTop: BORDER_VALIDATOR,
    borderBottom: BORDER_VALIDATOR
  },
  flexbox: {
    flex: genEnumValidator(['none', 'auto', 'initial']),
    flexWrap: genEnumValidator(['nowrap', 'wrap']),
    flexGrow: NUMBER_VALIDATOR,
    flexShrink: NUMBER_VALIDATOR,
    flexBasis: LENGTH_VALIDATOR,
    flexDirection: genEnumValidator(['row', 'column']),
    justifyContent: genEnumValidator(['flex-start', 'flex-end', 'center', 'space-between',
      'space-around', 'space-evenly']),
    alignItems: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center', 'baseline']),
    alignContent: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center', 'space-between', 'space-around']),
  },
  position: {
    position: genEnumValidator(['relative', 'fixed', 'absolute']),
    top: PERCENTAGE_LENGTH_VALIDATOR,
    bottom: PERCENTAGE_LENGTH_VALIDATOR,
    left: PERCENTAGE_LENGTH_VALIDATOR,
    right: PERCENTAGE_LENGTH_VALIDATOR,
    zIndex: INTEGER_VALIDATOR
  },
  common: {
    background: BACKGROUND_VALIDATOR,
    backgroundColor: COLOR_VAR_VALIDATOR,
    backgroundImage: URL_VALIDATOR,
    backgroundSize: BACKGROUND_SIZE_VALIDATOR,
    backgroundRepeat: genEnumValidator(['repeat', 'no-repeat', 'repeat-x', 'repeat-y']),
    backgroundPosition: BACKGROUND_POSITION_VALIDATOR,
    opacity: NUMBER_VALIDATOR,
    appearingDuration: NUMBER_VALIDATOR,
    visibility: genEnumValidator(['visible', 'hidden']),
    display: genEnumValidator(['flex', 'none', 'grid']),
    imageFill: COLOR_VAR_VALIDATOR,
    maskImage: MASK_VALIDATOR,
    maskPosition: BACKGROUND_POSITION_VALIDATOR,
    maskSize: BACKGROUND_SIZE_VALIDATOR
  },
  text: {
    color: COLOR_VAR_VALIDATOR,
    fontSize: LENGTH_VALIDATOR,
    allowScale: genEnumValidator(['true', 'false']),
    letterSpacing: LENGTH_VALIDATOR,
    fontStyle: genEnumValidator(['normal', 'italic']),
    fontFamily: ANYTHING_VALIDATOR,
    fontWeight: genEnumValidator(['normal', 'lighter', 'bold', 'bolder', "medium", "regular",
      '100', '200', '300', '400', '500', '600', '700', '800', '900']),
    textDecoration: genEnumValidator(['none', 'underline', 'line-through']),
    textAlign: genEnumValidator(['start', 'end', 'left', 'center', 'right']),
    textOverflow: genEnumValidator(['clip', 'ellipsis']),
    textIndent: TEXT_INDENT_VALIDATOR,
    lineHeight: LENGTH_VALIDATOR,
    maxLines: ANYTHING_VALIDATOR,
    minFontSize: LENGTH_VALIDATOR,
    maxFontSize: LENGTH_VALIDATOR,
    fontSizeStep: LENGTH_VALIDATOR,
    preferFontSizes: ARRAY_LENGTH_VALIDATOR,
    adaptHeight: genEnumValidator(['true', 'false'])
  },
  progress: {
    secondaryColor: COLOR_VAR_VALIDATOR,
    scaleWidth: LENGTH_VALIDATOR,
    scaleNumber: NUMBER_VALIDATOR,
    startAngle: ANGLE_VALIDATOR,
    totalAngle: ANGLE_VALIDATOR,
    centerX: LENGTH_VALIDATOR,
    centerY: LENGTH_VALIDATOR,
    radius: LENGTH_VALIDATOR,
    direction: genEnumValidator(['start-to-end', 'end-to-start']),
    sections: NAME_VALIDATOR,
    colors: ARRAY_COLOR_VALIDATOR,
    weights: ARRAY_NUMBER_VALIDATOR
  },
  chart: {
    strokeWidth: LENGTH_VALIDATOR,
  },
  button: {
    textColor: COLOR_VAR_VALIDATOR,
    iconWidth: LENGTH_VALIDATOR,
    iconHeight: LENGTH_VALIDATOR
  },
  image: {
    objectFit: genEnumValidator(['cover', 'fill', 'contain', 'none', 'scale-down']),
    matchTextDirection: genEnumValidator(['false', 'true']),
    fitOriginalSize: genEnumValidator(['false', 'true']),
  },
  list: {
    itemExtent: PERCENTAGE_LENGTH_VALIDATOR,
    fadeColor: COLOR_VAR_VALIDATOR,
    dividerColor: COLOR_VAR_VALIDATOR,
    dividerHeight: LENGTH_VALIDATOR,
    dividerLength: LENGTH_VALIDATOR,
    dividerOrigin: LENGTH_VALIDATOR,
    scrollbarColor: COLOR_VALIDATOR,
    scrollbarWidth: LENGTH_VALIDATOR,
    scrollbarOffset: ARRAY_LENGTH_VALIDATOR
  }
}

var backgroundValidatorMap = {
  linearGradient: LINEAR_GRADIENT_VALIDATOR,
  repeatingLinearGradient: LINEAR_GRADIENT_VALIDATOR,
  linearGradientColor: ARRAY_COLOR_STOP_VALIDATOR,
  linearGradientAngle: ANGLE_VALIDATOR,
  linearGradientDirection: GRADIENT_DIRECTION_VALIDATOR
}

var transformValidatorMap = {
  translate: MULTIPLE_PERCENTAGE_LENGTH_VALIDATOR,
  translate3d: MULTIPLE_PERCENTAGE_LENGTH_VALIDATOR,
  translateX: PERCENTAGE_LENGTH_VALIDATOR,
  translateY: PERCENTAGE_LENGTH_VALIDATOR,
  translateZ: PERCENTAGE_LENGTH_VALIDATOR,
  scale: MULTIPLE_NUMBER_VALIDATOR,
  scale3d: MULTIPLE_NUMBER_VALIDATOR,
  scaleX: NUMBER_VALIDATOR,
  scaleY: NUMBER_VALIDATOR,
  scaleZ: NUMBER_VALIDATOR,
  rotate: MUTIPLE_ANGLE_VALIDATOR,
  rotate3d: ROTATE3D_VALIDATOR,
  rotateX: ANGLE_VALIDATOR,
  rotateY: ANGLE_VALIDATOR,
  rotateZ: ANGLE_VALIDATOR,
  skew: MUTIPLE_ANGLE_VALIDATOR,
  skewX: ANGLE_VALIDATOR,
  skewY: ANGLE_VALIDATOR,
  matrix: MULTIPLE_NUMBER_VALIDATOR,
  matrix3d: MULTIPLE_NUMBER_VALIDATOR,
  perspective: PERCENTAGE_LENGTH_VALIDATOR,
}

var SUGGESTED_PROP_NAME_GROUP = {}

var validatorMap = {}

const card = process.env.DEVICE_LEVEL === 'card'
var isLiteDevice = process.env.DEVICE_LEVEL === 'lite'

var PROP_NAME_GROUPS = process.env.DEVICE_LEVEL === 'lite' ? LITE_PROP_NAME_GROUPS :
  card ? CARD_PROP_NAME_GROUPS : RICH_PROP_NAME_GROUPS

/**
 * flatten `PROP_NAME_GROUPS` to `validatorMap`
 */
function genValidatorMap() {
  var groupName, group, name
  for (groupName in PROP_NAME_GROUPS) {
    group = PROP_NAME_GROUPS[groupName]
    for (name in group) {
      validatorMap[name] = group[name]
    }
  }
}

genValidatorMap()

function getValueUnit(dem) {
  var str = dem.toString()
  var getValue = str.match(/[-]{0,1}[1-9][0-9]*/)
  var getUnit = str.match(/px|cm|%|em|vp|fp/)
  var result = {value: getValue, unit: getUnit}
  return result
}

function isOperator(value) {
  var operatorString = "+-*/()"
  return operatorString.indexOf(value) > -1
}

function getPrioraty(value) {
  switch(value) {
    case '+':
    case '-':
      return 1
    case '*':
    case '/':
      return 2
    default:
      return 0
  }
}

function prioraty(o1, o2) {
  return getPrioraty(o1) <= getPrioraty(o2)
}

function dal2Rpn(exp) {
  var inputStack = []
  var outputStack = []
  var outputQueue = []
  var str =
    exp.replace(/calc/g, "").replace(/(?<!var\(\-\-\w+|var\(\-\-\w+\,\s*\w+)\)/g, " )").replace(/(?<!var)\(/g, "( ")
  var inputStack=str.split(/(?<!\,)\s+/)
  var value, log
  while(inputStack.length > 0) {
    var cur = inputStack.shift()
    if(isOperator(cur)) {
      if(cur == '(') {
        outputStack.push(cur)
      } else if(cur == ')') {
        var po = outputStack.pop()
        while(po != '(' && outputStack.length > 0) {
          outputQueue.push(po)
          po = outputStack.pop()
        }
        if(po != '(') {
          log = {reason: 'ERROR: Expression unmatched ()'}
        }
      } else {
        while(prioraty(cur, outputStack[outputStack.length - 1]) && outputStack.length > 0) {
          outputQueue.push(outputStack.pop())
        }
        outputStack.push(cur)
      }
    } else {
      outputQueue.push(cur)
    }
  }
  return {
    value: outputQueue,
    log: log
  }
}

function checkComputation(left, right, operator) {
  var value, log
  if (operator == '*') {
    if ((right.match(/[a-zA-Z]/) && left.match(/[a-zA-Z]/)) || (!right.match(/[a-zA-Z]/) && !left.match(/[a-zA-Z]/))) {
      log = {reason: 'ERROR: The multiplier must contain and contain only one integer'}
    }
  }
  if (operator == '/') {
    if (right.match(/[a-zA-Z]|(?<![1-9])[0]/)) {
      log = {reason: 'ERROR: Divisor must be an integer and cannot be zero'}
    }
  }
  if (operator == '+') {
    if (!(right.match(/[a-zA-Z%]/) && left.match(/[a-zA-Z%]/))) {
      log = {reason: 'ERROR: Addition cannot contain integers'}
    }
  }
  if (operator == '-') {
    if (!(right.match(/[a-zA-Z%]/) && left.match(/[a-zA-Z%]/))) {
      log = {reason: 'ERROR: Subtraction cannot contain integers'}
    }
  }
  return log
}

function getResult(left, right, operator) {
  var value, log, errLog
  if (left.match(/var/)) {
    left = cssVarFun(left)
  }
  if (right.match(/var/)) {
    right = cssVarFun(right)
  }
  errLog = checkComputation(left, right, operator)
  if (errLog) {
    return { value: null, log: errLog }
  }
  var result, value, unit
  var leftValue = getValueUnit(left)
  var rightValue = getValueUnit(right)
  if (left.match(/\(/) | right.match(/\(/)) {
    result = left + ' ' + operator + ' ' + right
  } else {
    if (operator == '*') {
      value = leftValue.value * rightValue.value
      if (leftValue.unit == null) {
        unit = rightValue.unit
      } else { unit = leftValue.unit}
      result = value + unit
    } else if (operator == '/') {
      if (parseInt(rightValue.value) != 0) {
        value = leftValue.value / rightValue.value
        unit = leftValue.unit
        result = value + unit
      }
    } else if (operator == '+') {
      if (JSON.stringify(leftValue.unit) == JSON.stringify(rightValue.unit)) {
        value = parseInt(leftValue.value) + parseInt(rightValue.value)
        unit = leftValue.unit
        result = value + unit
      } else result = '(' + left + ' ' + operator + ' ' + right + ')'
    } else if (operator == '-') {
      if (JSON.stringify(leftValue.unit) == JSON.stringify(rightValue.unit)) {
        value = parseInt(leftValue.value) - parseInt(rightValue.value)
        unit = leftValue.unit
        result = value + unit
      } else result = '(' + left + ' ' + operator + ' ' + right + ')'
    }
  }
  return { value: result, log: null }
}

function evalRpn(rpnQueue) {
  var outputStack = []
  var value, res, log
  while(rpnQueue.length > 0) {
    var cur = rpnQueue.shift()
    if(!isOperator(cur)) {
      outputStack.push(cur)
    } else {
      if(outputStack.length < 2) {
      log = {reason: 'ERROR: Expression does not conform to specification'}
      }
      var sec = outputStack.pop()
      var fir = outputStack.pop()
      res = getResult(fir, sec, cur)
      log = res.log
      if (log) {
        return {
          value: null,
          log: log
        }
      } else {
        outputStack.push(res.value)
      }
    }
  }
  if(outputStack.length != 1) {
    log = {reason: 'ERROR: Expression does not conform to specification'}
  } else {
    if (outputStack[0].match(/[+-]/)) {
      value = 'calc' + outputStack[0]
    } else {
      value = outputStack[0]
    }
  }
  return {
    value: value,
    log: log
  }
}

var cssPropData = []

function saveCssProp(name, value) {
  if (name.match(/\-\-/)) {
    while (value.match(/var/)) {
      var value = cssVarFun(value)
    }
    cssPropData.push({name: name,value: value})
  }
}

function cssVarFun(value) {
  if (value.match(/calc/)) {
    return value
  } else {
    if (value.match(/var/)) {
      if (value.match(/\,/)) {
        var cssVarFir = value.substring(0,value.indexOf(",")).replace("var(","").trim()
        var cssVarSec = value.substring(value.indexOf(",")+1,value.length).replace(")","").trim()
      } else {
          var cssVarFir = value.replace("var(","").replace(")","").trim()
          var cssVarSec = ""
      }
      let varValue = cssVarSec
      for(var i=0, len=cssPropData.length; i<len; i++) {
        var cPDName = cssPropData[i].name.trim()
        cssVarFir = util.hyphenedToCamelCase(cssVarFir)
        if (cssVarFir == cPDName) {
          varValue = cssPropData[i].value
        }
      }
      return varValue
    } else {
      return value
    }
  }
}

function expValidate(name, value) {
  var res, log
  saveCssProp(name, value)
  if (typeof value === 'string' && name != 'border') {
    if (value.match(/var/)) {
      value = cssVarFun(value)
    }
    if (value.match(/calc/)) {
      var checkOp =
        /[a-zA-Z0-9()]\+|\+[a-zA-Z0-9()]|[a-zA-Z0-9()](?<!\-)\-(?!\-)|(?<!\-)\-(?!\-)[a-zA-Z0-9()]|[a-zA-Z0-9()]\*|\*[a-zA-Z0-9()]|[a-zA-Z0-9()]\/|\/[a-zA-Z0-9()]/
      if (value.match(checkOp) && value.match(/calc\(|var\(\-\-/)) {
        log = {reason: 'ERROR: Expression error, A space is required before and after the operator'}
        return {
          log: log
        }
      }
      res = dal2Rpn(value)
      res = evalRpn(res.value)
      log = res.log
      value = res.value
    }
  }
  return {
    value: value,
    log: log
  }
}

/**
 * validate a CSS name/value pair
 *
 * @param  {string} name   camel cased
 * @param  {string} value
 * @return {object}
 * - value:string or null
 * - log:{reason:string} or undefined
 */
function validate(name, value) {
  var log, expRes
  expRes = expValidate(name, value)
  if (expRes.log) {
    return {
      value: null,
      log: expRes.log
    }
  } else {
    value = expRes.value
  }

  var result
  var validator = validatorMap[name]
  if (typeof validator === 'function') {
    const flag = /{{{(.+?)}}}|{{(.+?)}}/.test(value) && card
    if (typeof value !== 'function' &&  !flag) {
      result = validator(value, name)
    }
    /* istanbul ignore else */
    else {
      result = {value: value}
    }
    if (result.reason) {
      log = {reason: result.reason(name, value, result.value)}
    }
  }
  else {
    // ensure number type, no `px`
    /* istanbul ignore else */
    if (typeof value !== 'function') {
      var match = value.match(LENGTH_REGEXP)
      if (match && (!match[1] || SUPPORT_CSS_UNIT.indexOf(match[1]) === -1)) {
        value = parseFloat(value)
      }
    }
    result = {value: value}
    var suggestedName = SUGGESTED_PROP_NAME_GROUP[name]
    var suggested = suggestedName ? ', suggest `' + util.camelCaseToHyphened(suggestedName) + '`' : ''
    log = {reason: 'WARNING: `' + util.camelCaseToHyphened(name) +
      '` is not a standard attribute name and may not be supported' + suggested}
  }
  return {
    value: result.value,
    log: log
  }
}

var validateFuncMap = {
  length: LENGTH_VALIDATOR,
  number: NUMBER_VALIDATOR,
  date: DATE_VALIDATOR
}

module.exports = {
  BASIC_COLOR_KEYWORDS: BASIC_COLOR_KEYWORDS,
  EXTENDED_COLOR_KEYWORDS: EXTENDED_COLOR_KEYWORDS,

  LENGTH_VALIDATOR: LENGTH_VALIDATOR,
  COLOR_VALIDATOR: COLOR_VALIDATOR,
  COLOR_VAR_VALIDATOR: COLOR_VAR_VALIDATOR,
  NUMBER_VALIDATOR: NUMBER_VALIDATOR,
  INTEGER_VALIDATOR: INTEGER_VALIDATOR,
  genEnumValidator: genEnumValidator,

  TRANSITION_PROPERTY_VALIDATOR: TRANSITION_PROPERTY_VALIDATOR,
  TRANSITION_DURATION_VALIDATOR: TRANSITION_INTERVAL_VALIDATOR,
  TRANSITION_DELAY_VALIDATOR: TRANSITION_INTERVAL_VALIDATOR,
  TRANSITION_TIMING_FUNCTION_VALIDATOR: TRANSITION_TIMING_FUNCTION_VALIDATOR,

  PROP_NAME_GROUPS: PROP_NAME_GROUPS,
  validateFuncMap: validateFuncMap,

  map: validatorMap,
  validate: validate
}