/**
* 存放公共函数
**/
var console = {
    log:function(str){
        print(str)
    }
}
function getCallback(javaCallback){
    return function(error){
        javaCallback.callback(error)
    }
}

function isNativeStringType(type) {
  return (
    type === 'string' ||
    type === 'url' ||
    type === 'hex' ||
    type === 'email' ||
    type === 'date' ||
    type === 'pattern'
  );
}
function isEmptyValue(value, type) {
  if (value === undefined || value === null) {
    return true;
  }
  if (type === 'array' && Array.isArray(value) && !value.length) {
    return true;
  }
  if (isNativeStringType(type) && typeof value === 'string' && !value) {
    return true;
  }
  return false;
}


function executeRequiredRule(rule,value,source,type){
    if(rule.required && isEmptyValue(value,type || rule.type)){
        return false;
    }
    return true;
}

function executeRangeRule(rule,value,source,type){
    var len = typeof rule.len === 'number';
    var min = typeof rule.min === 'number';
    var max = typeof rule.max === 'number';
    // 正则匹配码点范围从U+010000一直到U+10FFFF的文字（补充平面Supplementary Plane）
    var spRegexp = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
    var val = value;
    var key = null;
    var num = typeof value === 'number';
    var str = typeof value === 'string';
    var arr = Array.isArray(value);
    if (num) {
        key = 'number';
    } else if (str) {
        key = 'string';
    } else if (arr) {
        key = 'array';
    }
    // if the value is not of a supported type for range validation
    // the validation rule rule should use the
    // type property to also test for a particular type
    if (!key) {
        return false;
    }
    if (arr) {
        val = value.length;
    }
    if (str) {
        // 处理码点大于U+010000的文字length属性不准确的bug，如"𠮷𠮷𠮷".length !== 3
        val = value.replace(spRegexp, '_').length;
    }
    if (len) {
        if (val !== rule.len) {
            return false;
        }
    } else if (min && !max && val < rule.min) {
        return false;
    } else if (max && !min && val > rule.max) {
        return false;
    } else if (min && max && (val < rule.min || val > rule.max)) {
        return false;
    }
    return true;
}

function executePatternRule(rule,value,source,type){
    if (rule.pattern) {
        if (rule.pattern instanceof RegExp) {
          // if a RegExp instance is passed, reset `lastIndex` in case its `global`
          // flag is accidentally set to `true`, which in a validation scenario
          // is not necessary and the result might be misleading
          rule.pattern.lastIndex = 0;
          if (!rule.pattern.test(value)) {
            return false;
          }
        } else if (typeof rule.pattern === 'string') {
          var _pattern = new RegExp(rule.pattern);
          if (!_pattern.test(value)) {
            return false;
          }
        }
      }
    return true;
}

function executeEnumRule(rule,value,source,type){
    var ENUM = "enum";
    rule[ENUM] = Array.isArray(rule[ENUM]) ? rule[ENUM] : [];
      if (rule[ENUM].indexOf(value) === -1) {
        return false;
      }
    return true;
}
var pattern = {
  // http://emailregex.com/
  email: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+\.)+[a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{2,}))$/,
  // url: new RegExp(
  //   '^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$',
  //   'i',
  // ),
  hex: /^#?([a-f0-9]{6}|[a-f0-9]{3})$/i,
};
function getUrlRegex(){
    //TODO
    return /^[\s\S]*$/g
}
var types = {
  integer:function(value) {
    return types.number(value) && parseInt(value, 10) === value;
  },
  float:function(value) {
    return types.number(value) && !types.integer(value);
  },
  array:function(value) {
    return Array.isArray(value);
  },
  regexp:function(value) {
    if (value instanceof RegExp) {
      return true;
    }
    try {
      return !!new RegExp(value);
    } catch (e) {
      return false;
    }
  },
  date:function(value) {
    return (
      typeof value.getTime === 'function' &&
      typeof value.getMonth === 'function' &&
      typeof value.getYear === 'function' &&
      !isNaN(value.getTime())
    );
  },
  number:function(value) {
    if (isNaN(value)) {
      return false;
    }
    return typeof value === 'number';
  },
  object:function(value) {
    return typeof value === 'object' && !types.array(value);
  },
  method:function(value) {
    return typeof value === 'function';
  },
  email:function(value) {
    return (
      typeof value === 'string' &&
      value.length <= 320 &&
      !!value.match(pattern.email)
    );
  },
  url:function(value) {
    return (
      typeof value === 'string' &&
      value.length <= 2048 &&
      !!value.match(getUrlRegex())
    );
  },

  hex:function(value) {
    return typeof value === 'string' && !!value.match(pattern.hex);
  },
};
function executeTypeRule(rule,value,source,type){
  if (rule.required && value === undefined) {
    //required(rule, value, source, errors, options);
    //必填且值也没有
    return false;
  }
  var custom = [
    'integer',
    'float',
    'array',
    'regexp',
    'object',
    'method',
    'email',
    'number',
    'date',
    'url',
    'hex',
  ];
  var ruleType = rule.type;
  if (custom.indexOf(ruleType) > -1) {
    if (!types[ruleType](value)) {
      return false;
    }
    // straight typeof check
  } else if (ruleType && typeof value !== rule.type) {
    return false;
  }
    return true;
}
function executeUrlRule(rule,value,source,type){
    return true;
}

function executeWhitespaceRule(rule,value,source,type){
    if (/^\s+$/.test(value) || value === '') {
        return false;
      }
    return true;
}
Object.assign = function(){
    var target = arguments[0];
    for (var i = 1; i < arguments.length; i++) {
        var source = arguments[i]
        for(var key in source){
            target[key] = source[key]
        }
    }
    return target
}


