////////////通用FORM校验///////////////
//////////Feng 2007-05-30//////////////
var PARMASSPLITKEY = "||";
var VALUESPLITKEY = ":";
var TITLENAME = "TITLE";
var CHECKTYPE = "CHECKTYPE";
var INFORMATION = "INFORMATION";
//调试开关
var DEBUG_TAG = false;
//根据调试开关提示信息
function PrintDebugInfo(value) {
  if (DEBUG_TAG) {
    var debugwin = window.open("", "DEBUGWIND");
    if (!debugwin) {
      return;
    }
    var sVal = "";
    if (typeof value == "object") {
      for (var prop in value) {
        sVal += value[ prop ] != null ? value[ prop ] + '' : '[null]<br>';
      }
    } else {
      sVal = value;
    }
    debugwin.document.body.innerHTML += "<li>" + value + "</li>";

  }
}
/*
数组对象CheckArray  对array对象重新包装
@array数组
@num数组中元素个数
@getArrayOfIndex(index)取得array[index]的值
@getNum取得数组数据的个数
@setArrayOfIndex(index,data)设置array[index]的值
@delArrayOfIndex(index)删除array[index]的值
@add(data)加入数据
*/
function CheckArray() {
  this.array = new Array();
  this.num = 0;
  this.GetArrayOfIndex = function(index) {
    if (index < this.num) {//位置编号小于数组中数据个数
      return this.array[index];
      //取得array[index]的值
    } else {
      return null;
      //如果编号大于数组数据个数返回null
    }
  }
  this.GetNum = function() {
    return this.num;
  }
  this.SetArrayOfIndex = function(index, data) {
    if (index < this.num) {//附值必须满足index在数组容量内
      this.array[index] = data;
    }
  }
  this.DelArrayOfIndex = function(index) {
    if (index < this.num) {//删除数据index必须在数组数据个数内
      for (var i = index; i < this.num; i++) {
        this.array[i] = this.array[i + 1];
        //将index以后的数据前移
      }
      this.num--;
      //减少个数
    }
  }
  this.AddData = function(data) {
    this.array[this.num] = data;
    this.num++;
  }
}
//封装的校验对象
function CheckFunctionObject() {
  this.tag = "undifine";
  //标示
  this.info = "";
  //校验方法句柄可由外部获得
  this.check = check;
  function check(tag, form, obj, value) {
    return true;
  }
  //提示信息句柄可由外部获得
  this.message = message;
  function message(tag, form, obj, value) {
    return this.info;
  }
}
//校验方法对象集合
var FORM_CHECK_FUNCTIONS = new CheckArray();
//增加校验方法
function AddCheckFunction(tag, info, check, message) {
  var checkfunctionobject = new CheckFunctionObject();
  checkfunctionobject.tag = tag;
  checkfunctionobject.info = info;
  if (check != null) {
    checkfunctionobject.check = check;
  }
  if (message != null) {
    checkfunctionobject.message = message;
  }
  var num = FORM_CHECK_FUNCTIONS.GetNum();
  FORM_CHECK_FUNCTIONS.AddData(checkfunctionobject);
  PrintDebugInfo("如果这个值：" + (FORM_CHECK_FUNCTIONS.GetNum() - num) + "=1表示" + tag + "校验方法正确加入！");
}
function AddCheckFunctionObject(checkFunctionObj) {
  FORM_CHECK_FUNCTIONS.AddData(checkFunctionObj);
}
//获得对象的值
//todo::可以更加完善
function GetObjValue(obj) {
  var ret = "";
  if (obj != null) {
    ret = obj.value;
  }
  if (obj.type) {
    var typeName = obj.type.toLocaleLowerCase();
    //checkbox,radio获取值方法
    if (typeName == "checkbox" || typeName == "radio") {
      ret = "";
      var objs = document.getElementsByName(obj.name);
      for (var i = 0; i < objs.length; i++) {
        var o = objs[i];
        if (o.checked) {
          ret += o.value;
        }
      }
    }
  }
  return ret;
}
//获得检测的方法对象
function GetCheckFunctionObject(tag) {
  //默认返回检测对象 即检测任何值都返回正确
  var ret = new CheckFunctionObject();
  for (var i = 0; i < FORM_CHECK_FUNCTIONS.GetNum(); i++) {
    var obj = FORM_CHECK_FUNCTIONS.GetArrayOfIndex(i);
    //返回标示相同的对象
    if (obj.tag == tag) {
      return obj;
    }
    //扩展：用于检测标志上带有检测条件的情况，会引起意想不到错误
    //示例：检验标志长度大于100，检验方法只要提供“长度”便可校验这一类的数据
    if (tag.indexOf(obj.tag) == 0) {
      return obj;
    }
  }
  return ret;
}
//校验某个对象如出错返回错误信息否则返回null
function CheckObject(form, obj) {
  //校验类型
  var checktype = "";
  //自定义错误信息
  var streorr = "";
  //校验对象名称
  var title = "";
  //获取属性
  checktype = GetAttribute(obj, "checktype");
  streorr = GetAttribute(obj, "streorr");
  title = GetAttribute(obj, "title");
  //测试title字段是否封装了测试方法 设置title校验会覆盖checktype类型
  if (typeof obj.title != "undefined") {
    var temps = obj.title.split(PARMASSPLITKEY);
    for (var i = 0; i < temps.length; i++) {
      var temp = temps[i];
      var titletag = TITLENAME + VALUESPLITKEY;
      var checktag = CHECKTYPE + VALUESPLITKEY;
      var infotag = INFORMATION + VALUESPLITKEY;
      if (temp.indexOf(titletag) == 0) {
        title = temp.substring(titletag.length);
      }
      if (temp.indexOf(checktag) == 0) {
        checktype = temp.substring(checktag.length);
      }
      if (temp.indexOf(infotag) == 0) {
        streorr = temp.substring(infotag.length);
      }
    }
    PrintDebugInfo("获得的字符串解析后的值：名称[" + title + "];校验类型[" + checktype + "];自定义信息[" + streorr + "]");
  }
  //存储错误信息
  var retInfo = null;
  //检测类型表达式操作数组“!”非“&”与“|”或，优先级从左至右递减
  var oparray = new CheckArray();
  //检测类型数组
  var typearray = new CheckArray();
  //检测类型值数组
  var valuearray = new CheckArray();

  //------------------------------------------------------------------------------------------------------------------//
  //1 分离检测类型。得到输入的判定条件
  var strtype = "";
  //检验表单元素类型，从而进行相应判断
  if ((typeof checktype != "undefined") && (checktype != "")) {
    strtype = checktype;
  } else {
    //未设置检测类型便不进行检验返回默认值即可
    return retInfo;
  }
  PrintDebugInfo("需要校验的类型表达式为" + strtype);
  //获得需要校验的值
  var value = GetObjValue(obj);
  PrintDebugInfo("需要校验的值为" + value);
  /*例子:
   "!空&金额"意思为输入为必填的金额
   分离后为
   oparray[0]=0;
   oparray[1]=1;
   typearray[0]="空"
   typearray[1]="金额"
  */
  var strtemp = "";
  var x = 0;
  var t = 0;
  for (var i = 0; i < strtype.length; i++) {
    if ((strtype.charAt(i) == '!') || (strtype.charAt(i) == '&') || (strtype.charAt(i) == '|')) {
      switch (strtype.charAt(i)) {//将操作符转换为可看出优先级的数字,0最高
        case  '!' : t = 0;break;
        case  '&' : t = 1;break;
        case  '|' : t = 2;break;
      }
      oparray.AddData(t);
      //将操作符加入数组
      strtemp = strtype.substring(x, i);
      if (strtemp != "") {
        typearray.AddData(strtemp);
        strtemp = "";
      }
      x = i + 1;
    }
  }
  //如果剩余则为检测类型，例如上例中金额
  strtemp = strtype.substring(x, strtype.length);
  if (strtemp != "") {
    typearray.AddData(strtemp);
    strtemp = "";
  }
  //分离完毕
  PrintDebugInfo("操作符数组长度：" + oparray.GetNum() + "比检测类型数组长度：" + typearray.GetNum());

  //2  检测检测方法中的各种类型，将结果加入valuearray中
  for (var j = 0; j < typearray.GetNum(); j++) {
    //获得校验对象
    var checkFunctionObject = GetCheckFunctionObject(typearray.GetArrayOfIndex(j));
    //对输入数据带检测类型逐个进行检测，结果放入valuearray中
    valuearray.AddData(checkFunctionObject.check(typearray.GetArrayOfIndex(j), form, obj, value));
    PrintDebugInfo("此次校验的结果：信息[" + checkFunctionObject.info + "]值[" + checkFunctionObject.check(typearray.GetArrayOfIndex(j), form, obj, value) + "]");
  }

  //3  根据操作符判断最终检测结果
  while (oparray.GetNum() != 0) {
    var op = -1;
    var ww = 0;
    //获取优先级最靠前最高的操作符
    for (var i = 0; i < oparray.GetNum(); i++) {
      if ((oparray.GetArrayOfIndex(i) < oparray.GetArrayOfIndex(i + 1)) || (i == oparray.GetNum() - 1)) {
        op = oparray.GetArrayOfIndex(i);
        ww = i;
        oparray.DelArrayOfIndex(i);
        i = oparray.GetNum();
      }
    }
    //根据操作符换算结果数组
    switch (op) {
      case 0  :
        PrintDebugInfo("现在进行“非”运算，原值是:" + valuearray.GetArrayOfIndex(ww));
        valuearray.SetArrayOfIndex(ww, !valuearray.GetArrayOfIndex(ww));
        PrintDebugInfo("进行“非”运算后值是:" + valuearray.GetArrayOfIndex(ww));
        break;
      //如果是非操作，则根据操作符所在位数进行单目运算，将结果存入当前位置
      case 1  :
        PrintDebugInfo("现在进行“与”运算，原值是:" + valuearray.GetArrayOfIndex(ww));
        valuearray.SetArrayOfIndex(ww, valuearray.GetArrayOfIndex(ww) && valuearray.GetArrayOfIndex(ww + 1));
        PrintDebugInfo("进行“与”运算后值是:" + valuearray.GetArrayOfIndex(ww));
        valuearray.DelArrayOfIndex(ww + 1);
        break;
      //如果是与操作，进行双目运算，将结果存入第一元素位置，然后删除第二元素
      case 2  :
        PrintDebugInfo("现在进行“或”运算，原值是:" + valuearray.GetArrayOfIndex(ww));
        valuearray.SetArrayOfIndex(ww, (valuearray.GetArrayOfIndex(ww) || valuearray.GetArrayOfIndex(ww + 1)));
        PrintDebugInfo("进行“或”运算后值是:" + valuearray.GetArrayOfIndex(ww));
        valuearray.DelArrayOfIndex(ww + 1);
        break;
      //如果是或操作，进行双目运算，将结果存入第一元素位置，然后删除第二元素
    }
  }

  //检测运算后的值如果正确返回正确信息。
  if (valuearray.GetArrayOfIndex(0)) {
    return retInfo;
  }

  //4 返回错误信息
  //取得自定义错误提示信息
  if ((typeof streorr != "undefined") && ("" != streorr)) {
    return streorr;
  }

  //根据判定条件自动生成错误提示，取得输入名称
  var strtitle = "";
  if (typeof title != "undefined") {
    strtitle = title;
  }
  var strautoeorr = strtitle + "输入有误! 参考格式：";
  var opstr = "";
  var y = 0;
  var strtemp2 = "";
  for (var i = 0; i < strtype.length; i++) {
    if (strtemp2 != "") {
      PrintDebugInfo("此时截取的字符串为：" + strtemp2);
      var checkFunctionObject = GetCheckFunctionObject(strtemp2);
      strautoeorr = strautoeorr + checkFunctionObject.message(strtemp2, form, obj, value);
      strtemp2 = "";
    }
    strautoeorr += opstr;
    opstr = "";
    if ((strtype.charAt(i) == '!') || (strtype.charAt(i) == '&') || (strtype.charAt(i) == '|')) {
      switch (strtype.charAt(i)) {//将操作符转换为可看出优先级的数字,0最高
        case  '!' : opstr = "不能为";break;
        case  '&' : opstr = "并且为";break;
        case  '|' : opstr = "或者为";break;
      }
      strtemp2 = strtype.substring(y, i);
      y = i + 1;
    }
  }
  strtemp2 = strtype.substring(y);
  PrintDebugInfo("此时剩下的字符串为：" + strtemp2);
  var checkFunctionObject = GetCheckFunctionObject(strtemp2);
  strautoeorr = strautoeorr + checkFunctionObject.message(strtemp2, form, obj, value);
  return strautoeorr;
  //结束单项校验 测试ok
}
//选中对象
//todo::根据对象类型选中对象
function SelectObject(obj) {

  try {
    obj.select();
  } catch(e) {
  }
  try {
    obj.focus();
  } catch(e) {
  }
}
//校验表格
function CheckFormFunction(inputform) {
  var ret = false;
  var str = "";
  for (var kk = 0; kk < inputform.elements.length; kk++) {
    var formelement = inputform.elements[kk];
    var strInfo = CheckObject(inputform, formelement);
    if (strInfo != null) {
      alert(strInfo);
      //如果出错处理出错信息
      SelectObject(formelement);
      return false;
    }
  }
  return true;
  //没有错误
}
//////////////////常用的校验方法//////////////////////
function GetStrLength(str) {
  var num = str.length
  var arr = str.match(/[^\x00-\xff]/ig)
  if (arr != null) {
    num += arr.length;
  }
  return num
}
//获得对象某属性，返回非空字符串
function GetAttribute(obj, attribute) {
  var ret = "";
  try {
    ret = obj.getAttribute(attribute);
    if ((typeof ret == "undefined") || ret == null) {
      ret = "";
    }
  } catch(e) {
    ret = "";
  }
  return ret;
}
//获得本校验方法支持的校验种类及标识符
function GetCheckFormSupport() {
  var message = "本系统支持的校验种类为：\n";
  for (var i = 0; i < FORM_CHECK_FUNCTIONS.GetNum(); i++) {
    var obj = FORM_CHECK_FUNCTIONS.GetArrayOfIndex(i);
    message += "[" + obj.tag + "" + "]:[" + obj.info + "]\n";
  }
  //使用方法
  message += "系统使用方法:\n";
  message += "设置校验方法：增加checktype=\"TAG\" \n";
  message += "设置自定义方法：增加streorr属性\n";
  message += "或者可以设置TITLE属性，格式为：\n";
  message += TITLENAME + VALUESPLITKEY + "字段名" + PARMASSPLITKEY;
  message += CHECKTYPE + VALUESPLITKEY + "TAG" + PARMASSPLITKEY;
  message += INFORMATION + VALUESPLITKEY;
  return message;
}
//下面为扩展的校验方法
/*
扩展方法 Ver1:
1、设置校验的标识符以及提示信息
2、编写一个校验方法
3、将这些加入校验数组中
扩展方法 Ver2:
1、声明一个校验对象
2、重载校验等方法
3、将这加入校验数组中
*/
//空
var NullCheck = new CheckFunctionObject();
NullCheck.tag = "NULL";
NullCheck.info = "空";
NullCheck.check = function (tag, form, obj, value) {
  try {
    var str = value.replace(/(^\s*)|(\s*$)/g, "");
    if (str == "") {
      return true;
    }
  } catch(e) {
    return true;
  }
  return false;
}
AddCheckFunctionObject(NullCheck);
//整形
var tag1 = "INT";
var info1 = "整数(由数字和负号组成,例：0,1,-55)";
function check1(tag, form, obj, value) {
  var sExp = new RegExp("^(0|(\\-?[1-9][0-9]*))$");
  //获得该类型正则表达式
  return sExp.test(value);
}
AddCheckFunction(tag1, info1, check1, null);
//年龄
var tag2 = "AGE";
var info2 = "年龄(在1-139之间的整数)";
function check2(tag, form, obj, value) {
  var sExp = new RegExp("(^[1-9]$)|(^[1-9]\\d$)|(^1[0-3]\\d$)");
  //获得该类型正则表达式
  return sExp.test(value);
}
AddCheckFunction(tag2, info2, check2, null);
//电邮
var tag3 = "EMAIL";
var info3 = "E-Mail(例:china@china.cn)";
function check3(tag, form, obj, value) {
  var sExp = new RegExp("^((\\w)+\\-*\\.?){1,3}@((\\w)+\\.){1,3}(\\w)+$");
  //获得该类型正则表达式
  return sExp.test(value);
}
AddCheckFunction(tag3, info3, check3, null);
//枚举
var tag4 = "SAMPLE";
var info4 = "自定义枚举";
function check4(tag, form, obj, value) {
  if (value == "") {
    return false;
  }
  var sample = GetAttribute(obj, "sample");
  return (sample.indexOf(value) > -1);
}
function message4(tag, form, obj, value) {
  var sample = GetAttribute(obj, "sample");
  if (sample != "") {
    return "枚举值(" + sample + ")";
  }
  alert("没有设置枚举值");
  return "[没有设置枚举值]";
}
AddCheckFunction(tag4, info4, check4, message4);

//日期
var tag5 = "TIME";
var info5 = "时间(格式参照:1981-10-01 01:01:00或1981-10-01)";
function check5(tag, form, obj, value) {
  var sExp = new RegExp("(^[1-9]\\d{3}((-\\d{2}){1,2}(\\s[0-2][0-9]\\:[0-5][0-9]\\:[0-5][0-9])?)$)");
  //获得该类型正则表达式
  return sExp.test(value);
}
AddCheckFunction(tag5, info5, check5, null);
//长度
var tag6 = "长度";
var info6 = "检测长度";
function check6(tag, form, obj, value) {
  var ret = false;
  try {
    var length = parseInt(tag.substring(4));
    var type = tag.substring(2, 4);
    var num = GetStrLength(value);
    if ("大于" == type) {
      return num > length;
    }
    if ("等于" == type) {
      return num == length;
    }
    if ("小于" == type) {
      return num < length;
    }
  } catch(e) {
    alert("长度校验参数设置异常");
    return "[长度校验参数设置异常]";
  }
  return ret;
}
function message6(tag, form, obj, value) {
  try {
    var num = GetStrLength(value);
    var info = "";
    return "长度不正确(您输入长度为" + num + info + ",建议" + tag + ")";
  } catch(e) {
    alert("长度校验参数设置异常");
    return "[长度校验参数设置异常]";
  }
}
AddCheckFunction(tag6, info6, check6, message6);
//短日期
var tag7 = "SHORTDATE";
var info7 = "日期(格式参照:2006-06-29,如日不确定填入2006-06,月不确定填入2006)";
function check7(tag, form, obj, value) {
  var sExp = new RegExp("(^[1-9]\\d{3}((-\\d{2}){1,2})?$)");
  //获得该类型正则表达式
  return sExp.test(value);
}
AddCheckFunction(tag7, info7, check7, null);
//日期
var tag8 = "DATE";
var info8 = "日期(格式参照:2006-06-29)";
function check8(tag, form, obj, value) {
  var sExp = new RegExp("(^[1-9]\\d{3}(-\\d{2}){1,2}$)");
  //获得该类型正则表达式
  return sExp.test(value);
}
AddCheckFunction(tag8, info8, check8, null);
//文件
var tag9 = "FILE";
var info9 = "校验文件类型";
function check9(tag, form, obj, value) {
  if (value == "") {
    return false;
  }
  var index = value.toLowerCase().lastIndexOf(".");
  var type = value.substring(index + 1);
  var allowfiletype = GetAttribute(obj, "allow");
  var stopfiletype = GetAttribute(obj, "stop");
  if (stopfiletype.indexOf(type) > -1) {
    return false;
  }
  return (allowfiletype.indexOf(type) > -1);
}
function message9(tag, form, obj, value) {
  var allowfiletype = GetAttribute(obj, "allow");
  var stopfiletype = GetAttribute(obj, "stop");
  var message = "";
  if (allowfiletype != "") {
    message += "允许的文件类型(" + allowfiletype + ")";
  }
  if (stopfiletype != "") {
    message += "禁止的文件类型(" + stopfiletype + ")";
  }
  if (message != "") {
    return message;
  }
  alert("没有设置类型属性");
  return "[没有设置类型属性]";
}
AddCheckFunction(tag9, info9, check9, message9);
//自定义正则校验
var tag10 = "REGEXP";
var info10 = "自定义正则校验";
function check10(tag, form, obj, value) {
  var reg = GetAttribute(obj, "regexp");
  var sExp = new RegExp(reg);
  return sExp.test(value);
}
function message10(tag, form, obj, value) {
  var message = GetAttribute(obj, "message");
  if (message != "") {
    return message;
  } else {
    return "类型不正确";
  }
}
AddCheckFunction(tag10, info10, check10, message10);
//浮点
var tag11 = "FLOAT";
var info11 = "浮点数(例:0.01,100.2)";
function check11(tag, form, obj, value) {
  var sExp = new RegExp("^((\\-?0)|(\\-?[1-9][0-9]*))(\\.\\d*[0-9])?$");
  return sExp.test(value);
}
AddCheckFunction(tag11, info11, check11, null);
//IP
var tag12 = "IP";
var info12 = "IP(范围：0.0.0.0-255.255.255.255)";
function check12(tag, form, obj, value) {
  var sExp = new RegExp("^(((\\d)|([1-9]\\d)|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))\\.){3}((\\d)|([1-9]\\d)|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))$");
  return sExp.test(value);
}
AddCheckFunction(tag12, info12, check12, null);
//解析范围
function SubAreasFromTag(tag) {
  var ret = "";
  try {
    ret = tag.substring(2, (tag.length));
  } catch(e) {
  }
  return ret;
}
//转化字符串
function ParseStr(value) {
  //利用浮点数校验
  if (check11(null, null, null, value)) {
    return parseFloat(value);
  }
  //日期等做字符串处理
  return value;
}
//范围
var tag13 = "范围";
var info13 = "限制输入数据的范围";
function check13(tag, form, obj, value) {
  var ret = false;
  var area = SubAreasFromTag(tag);
  try {
    if (area.indexOf("至") > -1) {
      var as = area.split("至");
      var s = as[0];
      var e = as[1];
      return ((ParseStr(value) >= ParseStr(s)) && (ParseStr(value) <= ParseStr(e)));
    }
    var strArea = area.substring(2);
    if (area.indexOf("大于") > -1) {
      if (area.indexOf("等于") > -1) {
        return (ParseStr(value) >= ParseStr(strArea.substring(4)));
      } else {
        return (ParseStr(value) > ParseStr(strArea));
      }
    }
    if (area.indexOf("小于") > -1) {
      if (area.indexOf("等于") > -1) {
        return (ParseStr(value) <= ParseStr(strArea.substring(4)));
      } else {
        return (ParseStr(value) < ParseStr(strArea));
      }
    }
  } catch(e) {
    return "[范围参数设置异常]" + e;
  }
  return ret;
}
function message13(tag, form, obj, value) {
  try {
    return "输入数据的范围不正确(应为" + SubAreasFromTag(tag) + ")";
  } catch(e) {
    return "[范围参数设置异常]" + e;
  }
}
AddCheckFunction(tag13, info13, check13, message13);
var tag14 = "ICCARD";
var info14 = "身份证号码为15或18位数组组成！";
function check14(tag, form, obj, value) {
  var sExp = new RegExp("(^\\d{15}$)|(^\\d{17}\\w$)");
  return sExp.test(value);
}
AddCheckFunction(tag14, info14, check14, null);
var tag15 = "MOBEL";
var info15 = "移动电话为11数字组成,外地手机前加拨0";
function check15(tag, form, obj, value) {
  var sExp = new RegExp("^0?1\\d{10}$");
  return sExp.test(value);
}
AddCheckFunction(tag15, info15, check15, null);
var tag16 = "PHONE";
var info16 = "电话号码的格式为：区号-电话号码-分机，区号、分机为选填";
function check16(tag, form, obj, value) {
  var sExp = new RegExp("^(\\d{3,4}-)?\\d{7,8}(-\\d+)?$");
  return sExp.test(value);
}
AddCheckFunction(tag16, info16, check16, null);
//本网站的默认配置信息
PARMASSPLITKEY = "；";
//参数分隔符
VALUESPLITKEY = "：";
//值分隔符
TITLENAME = "字段名";
//标题tag
CHECKTYPE = "校验方式";
//校验tag
INFORMATION = "提示信息";
//提示信息tag

