/****************************************************/
/*           OpenPath PageBuilder                   */
/*       WRITTEN BY Richard, Chih-Shyang Chang      */
/*           2000/12/13                             */
/*      本程式受著作權法保護，侵權必究              */
/****************************************************/
// Purpose: Implement input validation function


function fnCheckRequiredFields(array)
{
  if (array == null)
    array = mVarControlList;

  var cnt = 0;
  for (var i=0; i < array.length; i++) {
    if (array[i].type == "text" || array[i].type == "textarea") {
      if (array[i].V_REQUIRED != null && array[i].V_REQUIRED != "0") {
        if (array[i].value.length == 0) {
          cnt++;
        }
      }
    }
  }

  var invalidCtrlList = new Array(cnt);
  var ndx = 0;

  for (var i=0; i < array.length; i++) {
    if (array[i].type == "text" || array[i].type == "textarea") {
      if (array[i].V_REQUIRED != null && array[i].V_REQUIRED != "0") {
        if (array[i].value.length == 0) {
          invalidCtrlList[ndx++] = array[i];
        }
      }
    }
  }

  return (invalidCtrlList);
}


/*
  Input validation

  Return Value:
     -2: no input found
     -1: data checking is in progress (reentry problem)
      0: invalid input
      1: valid input
*/
function fnInputValidation(obj)
{
  var errMsg = "";

  if (obj.CHECKED == "-1") return -1; // avoid the "reentry" problem

  // enable checking flag
  obj.CHECKED = "-1";


  // return no value input
  if (obj.value == "") {
    obj.CHECKED = "0";
    return -2;
  }


  // Check V_CHECKTYPE
  if (fnCheckDataType(obj.V_CHECKTYPE, obj.value) == false)
  {
    errMsg = obj.ERRMSG_TYPE + ": " + obj.value;
    alert(errMsg);
    obj.focus();
    obj.CHECKED = "0";
    return 0; // false
  }


  switch(obj.V_CHECKTYPE)
  {
    case "string":
      if (fnCheckLength(obj.V_LEN, obj.value) == false && obj.V_LEN != null)
        errMsg = obj.ERRMSG_LEN + ": " + obj.value;

      if (fnCheckStringRange(obj.V_RANGE, obj.value) == false && obj.V_RANGE != null)
        errMsg = errMsg + "\n" + obj.ERRMSG_RANGE + ": " + obj.value;

      break;
    case "integer":
    case "float":
      if (fnCheckRange(obj.V_RANGE, obj.value) == false && obj.V_RANGE != null)
        errMsg = obj.ERRMSG_RANGE + ": " + obj.value;
      break;
    case "datetime":
      var items = obj.value.split(" ");
      var patterns = obj.V_DT.split(" ");

      if (obj.V_DT == null)
      {
      	obj.CHECKED = "0";
        return 1; // true
      }

      if (items.length != patterns.length)
      {
      	errMsg = obj.ERRMSG_DT + ": " + obj.value;
      	break;
      }

      if (patterns.length <= 1)  // check only date
      {
        if (fnCheckDateFormat(obj.V_DT, obj.value) == false)
        {
          errMsg = obj.ERRMSG_DT + ": " + obj.value;
          //alert("Date format error!");
          break;
        }
        else  // Date format is correct, then check date value
        {
          var yy, mm, dd;

          yy = _getYear(obj.V_DT, obj.value);
          mm = _getMonth(obj.V_DT, obj.value);
          dd = _getDay(obj.V_DT, obj.value);

          if (fnCheckDate(yy, mm, dd) == false)
          {
            errMsg = obj.ERRMSG_DT + ": " + obj.value;
            //alert("Date Value error!");
            break;
          }
        }
      }
      else  // check both date and time
      {
      	// check date first
        if (fnCheckDateFormat(patterns[0], items[0]) == false)
        {
          errMsg = obj.ERRMSG_DT + ": " + obj.value;
          break;
        }
        else  // Date format is correct, then check date value
        {
          var dt = items[0].split("/");
          var yy, mm, dd;

          yy = _getYear(patterns[0], items[0]);
          mm = _getMonth(patterns[0], items[0]);
          dd = _getDay(patterns[0], items[0]);

          if (fnCheckDate(yy, mm, dd) == false)
          {
            errMsg = obj.ERRMSG_DT + ": " + obj.value;
            break;
          }
        }

        // check time
        if (fnCheckTimeFormat(patterns[1], items[1]) == false)
        {
          errMsg = obj.ERRMSG_DT + ": " + obj.value;
          break;
        }
        else  // Time format is correct, then check time value
        {
          var tm = items[1].split(":");
          var h, m, s;

          h = parseInt(tm[0]);
          m = parseInt(tm[1]);

          if (tm.length > 2)
            s = tm[2];
          else
            s = 30;

          if (fnCheckTime(h, m, s) == false)
          {
            errMsg = obj.ERRMSG_DT + ": " + obj.value;
            break;
          }
        }
      } // end of outter if

      break;
    case "regexp":
      if (fnCheckRegExpData(obj.V_REGEXP, obj.V_COND, obj.value) == false && obj.V_REGEXP != null)
        errMsg = obj.ERRMSG_REGEXP + ": " + obj.value;
      break;
    case "func":
      if (fnCheckUserFunc(obj) == false && obj.V_FUNC != null)
        errMsg = obj.ERRMSG_FUNC + ": " + obj.value;
      break;
    default:
      break;
  }

  if (errMsg.length > 0)
  {
    alert(errMsg);
    obj.focus();
    obj.CHECKED = "0";
    return 0; // false
  }

  obj.CHECKED = "0";
  return 1; // true
}


function fnCheckDataType(type, value)
{
  if (value == "" || value == null) return false;

  var myRegExp;
  var match;

  switch(type)
  {
    case "string":
    case "datetime":
    case "regexp":
    case "func":
      break;
    case "integer":
      myRegExp = new RegExp("^-?[0-9]+$", "ig");
      match = myRegExp.exec(value);
      if (match == null) return false;
      break;
    case "float":
      myRegExp = new RegExp("^-?[0-9]+(.[0-9]+)?$", "ig");
      match = myRegExp.exec(value);
      if (match == null) return false;
      break;
    default:
      break;
  }

  return true;
}

function fnCheckLength(len, value)
{
  if (len == null || len == "" || value == null || value == "") return false;
  var min, max, tmp, val;
  var bound;

  bound = len.split(":");
  if (bound.length <= 1)
  {
    alert("[Design-time Error]: The string length constraint must be of the form 'min:max'.");
    return false;
  }

  min = parseInt(bound[0]);
  max = parseInt(bound[1]);
  if (isNaN(min) || isNaN(max))
  {
    alert("[Design-time Error]: The max/max value of the string length constraint must be numeric.");
    return false;
  }

  tmp = max;
  if (min > max)
  {
    max = min;
    min = tmp;
  }


  var i;
  var actualLen = 0;

  // compute actual length
  for (i=0; i<value.length; i++)
    if (value.charCodeAt(i) < 127)
      actualLen++;
    else
      actualLen+=2;

  if (actualLen < min || actualLen > max)
    return false;
  else
    return true;
}


function fnCheckRange(range, value)
{
  if (range == null || range == "" || value == null || value == "") return false;
  var min, max, tmp, val;
  var bound;

  val = parseFloat(value);
  if (isNaN(val)) return false;

  bound = range.split(":");
  if (bound.length <= 1)
  {
    alert("[Design-time Error]: The range constraint must be of the form 'min:max'.");
    return false;
  }

  min = parseFloat(bound[0]);
  max = parseFloat(bound[1]);
  if (isNaN(min) || isNaN(max))
  {
    alert("[Design-time Error]: The max/max value of the range constraint must be numeric.");
    return false;
  }

  tmp = max;
  if (min > max)
  {
    max = min;
    min = tmp;
  }

  if (val < min || val > max)
    return false;
  else
    return true;
}


function fnCheckStringRange(range, value)
{
  if (range == null || range == "" || value == null || value == "") return false;
  var min, max;
  var tmp;
  var val;
  var bound;

  bound = range.split(":");
  if (bound.length <= 1)
  {
    alert("[Design-time Error]: The range constraint must be of the form 'min:max'.");
    return false;
  }

  min = bound[0];
  max = bound[1];

  tmp = max;
  if (min > max)
  {
    max = min;
    min = tmp;
  }

  if (value.length > min.length)
    val = value.substring(0, min.length);
  else
    val = value;

  if (val < min) return false;

  if (value.length > max.length)
    val = value.substring(0, max.length);
  else
    val = value;

  if (val > max) return false;

  return true;
}



function fnCheckDateFormat(pattern, value)
{
  var myRegExp;
  var match;

  switch(pattern)
  {
    case "yyyy/M/d":
      myRegExp = new RegExp("^[0-9]{4}\/[0-9]{1,2}\/[0-9]{1,2}$", "ig");
      break;
    case "yyyy/MM/dd":
      myRegExp = new RegExp("^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$", "ig");
      break;
    case "M/d/yy":
      myRegExp = new RegExp("^[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{2}$", "ig");
      break;
    case "M/d/yyyy":
      myRegExp = new RegExp("^[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4}$", "ig");
      break;
    case "MM/dd/yy":
      myRegExp = new RegExp("^[0-9]{2}\/[0-9]{2}\/[0-9]{2}$", "ig");
      break;
    case "MM/dd/yyyy":
      myRegExp = new RegExp("^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$", "ig");
      break;
    default:
      return false;
  }

  match = myRegExp.exec(value);

  if (match == null)
    return false;
  else
    return true;
}


function fnCheckTimeFormat(pattern, value)
{
  var myRegExp;
  var match;

  switch(pattern)
  {
    case "hh:mm:ss":
      myRegExp = new RegExp("^[0-9]{2}:[0-9]{2}:[0-9]{2}$", "ig");
      break;
    case "hh:mm":
      myRegExp = new RegExp("^[0-9]{2}:[0-9]{2}$", "ig");
      break;
    default:
      return false;
  }

  match = myRegExp.exec(value);

  if (match == null)
    return false;
  else
    return true;
}


function fnCheckDate(y, m, d)
{
  //alert(y);
  //alert(m);
  //alert(d);

  if (isNaN(y)) return false;
  if (isNaN(m)) return false;
  if (isNaN(d)) return false;

  if (y < 100 && y > 70) y += 1900;
  if (y < 70) y += 2000;
  if (y > 2070 || y < 1970) return false;

  if (m < 1 || m > 12) return false;
  if (d < 1 || d > 31) return false;

  var isleap = ((y % 100) && !(y % 4)) || !(y % 400);

  switch (m)
  {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
      return true;
    case 4:
    case 6:
    case 9:
    case 11:
      if (d > 30) return false;
      else return true;
    case 2:
      if (isleap) {
        if (d > 29) return false;
        else return true;
      }
      if (d > 28) return false;
      return true;
    default:
      return false;
  }
}


function fnCheckTime(h, m, s)
{
  if (isNaN(h)) return false;
  if (isNaN(m)) return false;
  if (isNaN(s)) return false;

  if (h > 23 || h < 0) return false;
  if (m > 59 || m < 0) return false;
  if (s > 59 || s < 0) return false;

  return true;
}


function fnCheckRegExpData(pattern, condition, value)
{
  var myRegExp;
  var match;

  myRegExp = new RegExp(pattern, condition);

  match = myRegExp.exec(value);

  if (match == null)
    return false;
  else
    return true;
}


function fnCheckUserFunc(obj)
{
  var retval = false;

  eval("retval = checkFunc_" + obj.V_FUNC + "(" + obj.id + ");");

  return retval;
}



function _getYear(pattern, value)
{
  var items = value.split("/");
  var retval;

  switch(pattern)
  {
    case "yyyy/M/d":
    case "yyyy/MM/dd":
      retval = parseInt(items[0]);
      break;
    case "M/d/yy":
    case "M/d/yyyy":
    case "MM/dd/yy":
    case "MM/dd/yyyy":
      retval = parseInt(items[2]);
      break;
    default:
      retval = 0;
  }

  return retval;
}

function _getMonth(pattern, value)
{
  var items = value.split("/");
  var retval;

  switch(pattern)
  {
    case "yyyy/M/d":
    case "yyyy/MM/dd":
      retval = parseInt(items[1]);
      break;
    case "M/d/yy":
    case "M/d/yyyy":
    case "MM/dd/yy":
    case "MM/dd/yyyy":
      retval = parseInt(items[0]);
      break;
    default:
      retval = 0;
  }

  return retval;
}

function _getDay(pattern, value)
{
  var items = value.split("/");
  var retval;

  switch(pattern)
  {
    case "yyyy/M/d":
    case "yyyy/MM/dd":
      retval = parseInt(items[2]);
      break;
    case "M/d/yy":
    case "M/d/yyyy":
    case "MM/dd/yy":
    case "MM/dd/yyyy":
      retval = parseInt(items[1]);
      break;
    default:
      retval = 0;
  }

  return retval;
}

function fnConvertDateFormat(srcPattern, dateStr, targetPattern)
{
  if (dateStr == "" || dateStr == null) return '';
  var retval = '';
  var y = _getYear(srcPattern, dateStr);
  if (y < 100 && y > 70) y += 1900;
  if (y < 70) y += 2000;

  var m = _getMonth(srcPattern, dateStr);
  var d = _getDay(srcPattern, dateStr);

  switch(targetPattern)
  {
    case "yyyy/M/d":
      retval = "" + y + "/" + m + "/" + d;
      break;
    case "yyyy/MM/dd":
      retval = "" + y + "/" + _twoDigit(m) + "/" + _twoDigit(d);
      break;
    case "M/d/yy":
      retval = "" + m + "/" + d + "/" + (new String(y)).substring(2,4);
      break;
    case "M/d/yyyy":
      retval = "" + m + "/" + d + "/" + y;
      break;
    case "MM/dd/yy":
      retval = "" + _twoDigit(m) + "/" + _twoDigit(d) + "/" + (new String(y)).substring(2,4);
      break;
    case "MM/dd/yyyy":
      retval = "" + _twoDigit(m) + "/" + _twoDigit(d) + "/" + y;
      break;
    default:
      retval = dateStr;
  }

  return retval;
}

function _twoDigit(d)
{
  if (d == null) return '';
  var dd = '' + d;
  if (dd.length < 2) return "0" + dd;

  return dd;
}  