// ------------------------------------------------------------------------
// --   name: Client-side validators
// -- author: Bartosz Bankowski <bbankowski@gmail.com>
// --   date: May 5, 2006
// ------------------------------------------------------------------------
// -- History:
// -- May 9, 2006 Added form onSubmit event as action.
// ------------------------------------------------------------------------
// Usage example:
//  <form name="form" method="post" action="test.htm">
//    Name: <input type="text" name="name"/><br/>
//    Surname: <input type="text" name="surname"/></br>
//    Age: <input type="text" name="age"/></br>
//    Birthday: <input type="text" name="birthday"/></br>
//    Test: <input type="text" name="test"/></br>
//    <input type="button" name="btn" value="go"/></br>
//  </form>
// JavaScript code:
//   var v = new Validator('form')
//   v.addValidation('name', 'empty', 'Name is empty.');
//   v.addValidation('surname', 'empty', 'Surname is empty.');
//   v.addValidation('age', 'number', 'Age is not a number.');
//   v.addValidation('birthday', 'date', 'Birthday is not a valid date.');
//   v.addValidation('test', 'custom_regexp',
//                   'Test does not match 0.', new RegExp('0'));
//   v.addAction('btn', 'submit');
// ------------------------------------------------------------------------

// ------------------------------------------------------------------------
// -- Global variables
// ------------------------------------------------------------------------

// Error header for alert window. 
// It can be changed by setErrorHeader(text) method of Validator class.
var _error_header = 'Errors found:';

// Input boxes CSS style name for error fields and validated fields. 
// It can be changed by setBoxStyles(style1, style2) method of Validator
// class.
var _box_style_error = 'error';
var _box_style_ok = 'ok';

// ------------------------------------------------------------------------
// -- Actions
// ------------------------------------------------------------------------

function action_submit(form, submit) {
  if (submit) {
    form.submit();
  }
}

function action_check(form, submit) {
}

function action_form_submit(form, submit) {
  return submit;
}

// ------------------------------------------------------------------------
// -- Validators
// ------------------------------------------------------------------------

var numberRegExp = new RegExp('^[0-9]+$');
var dateRegExp = new RegExp('^[0-9]{4}-[0-9]{2}-[0-9]{2}$');

function validator_type_empty(field) {
  return !field || field.value.length < 1;
}

function validator_type_date(field) {
  return field.value ? !field.value.match(dateRegExp) : false;
}

function validator_type_number(field) {
  return field.value ? !field.value.match(numberRegExp) : false;
}

function validator_type_custom_regexp(field, regexp) {
  return field.value ? !field.value.match(regexp) : false;
}

function validator_type_between(field, min, max) {
  return !field.value || field.value.length > max || field.value.length < min;
}

function validator_type_length(field, len) {
  return !field.value || field.value.length != len;
}

function validator_type_min_length(field, min) {
  return field.value ? field.value.length < min : false;
}

function validator_type_max_length(field, max) {
  return field.value ? field.value.length > max : false;
}

function validator_type_select(field, value) {
  return !field.value || field.value == value;
}

function validator_type_relation_fill_one(field1, field2, field3, field4) {
  if (field4) {
    return (field1.value.length > 0 && field2.value.length > 0) ||
           (field1.value.length > 0 && field3.value.length > 0) ||
           (field2.value.length > 0 && field3.value.length > 0) ||
           (field1.value.length > 0 && field4.value.length > 0) ||
           (field2.value.length > 0 && field4.value.length > 0) || 
           (field3.value.length > 0 && field4.value.length > 0);
  } else if (field3) {
    return (field1.value.length > 0 && field2.value.length > 0) ||
           (field1.value.length > 0 && field3.value.length > 0) ||
           (field2.value.length > 0 && field3.value.length > 0);
  } else if (field2) {
    return field1.value.length > 0 && field2.value.length > 0;
  }
  return false;
}

function validator_type_relation_empty(field1, field2, field3, field4) {
  if (field4) {
    return field1.value.length == 0 && field2.value.length == 0 &&
           field3.value.length == 0 && field4.value.length == 0;
  } else if (field3) {
    return field1.value.length == 0 && field2.value.length == 0 &&
           field3.value.length == 0;
  } else if (field2) {
    return field1.value.length == 0 && field2.value.length == 0;
  }
  return false;
}

function validator_type_relation_date_older(field1, field2) {
  if (field1 && field2 && field1.value && field2.value) {
    var date1 = field1.value.split('-');
    var date2 = field2.value.split('-');
    if (date1.length == 3 && date2.length == 3) {
      for (x in date1) date1[x] = +date1[x];
      for (x in date2) date2[x] = +date2[x];
      return !((date1[0] > date2[0]) ||
             (date1[0] == date2[0] && date1[1] > date2[1]) ||
             (date1[0] == date2[0] && date1[1] == date2[1]
                                   && date1[2] > date2[2]));
    }
  }
  return false;
}

// ------------------------------------------------------------------------
// -- Error handling functions
// ------------------------------------------------------------------------

function show_errors(errors) {
  var errorMsg = _error_header + "\n\n";
  for (x in errors) {
    errorMsg += " - " + errors[x][1] + "\n";
    set_colors(false, errors[x][0]);
  }
  alert(errorMsg);
}

function check_errors(errors) {
  if (errors.length > 0) {
    show_errors(errors);
    return false;
  }
  return true;
}

function set_colors(error, fields) {
  var className = error ? _box_style_ok : _box_style_error;
  for (x in fields) {
    if (fields[x]) {
      fields[x].className = className;
    }
  }
}

// ------------------------------------------------------------------------
// -- Main functions
// ------------------------------------------------------------------------

function validate_form(validators, form, actionType) {
  var errors = new Array();

  for (x in validators) {
    var field = validators[x][0];
    var validator = validators[x][1];
    var comment = validators[x][2];
    var param1 = validators[x][3];
    var param2 = validators[x][4];
    var param3 = validators[x][5];

    var fields = new Array(field, param1, param2, param3)
    set_colors(true, fields);

    var result;
    var command = "result = validator_type_" + validator
                + "(field, param1, param2, param3);";
    eval(command);
    if (result) {
      errors.push(new Array(fields, comment));
    }
  }

  var result;
  var command = "result = action_" + actionType + "(form, check_errors(errors));";
  eval(command);
  return result;
}

function add_form_action(fieldName, actionType) {
  var field = this.formObj.elements[fieldName];
  var form = this.formObj;
  var validators = this.validators;

  if (field != form) {
    field.onclick = function() {
      validate_form(validators, form, actionType); 
    }
  } else {
    form.onsubmit = function() {
      return validate_form(validators, form, actionType); 
    }
  }
}

function add_field_validator(fieldName, type, comment, p1, p2, p3) {
  var field;
  if (typeof(fieldName) == 'string') {
    field = this.formObj.elements[fieldName];
  } else {
    for (x in fieldName) {
      if (x == 0) {
        field = this.formObj.elements[fieldName[x]];
      } else {
        var command = "p" + x + " = this.formObj.elements[fieldName[x]]";
        eval(command);
      }
    }
  }

  this.validators.push(new Array(field, type, comment, p1, p2, p3));
}

function set_error_header(text) {
  _error_header = text;
}

function set_box_styles(style1, style2) {
  _box_style_error = style1;
  _box_style_ok = style2;
}

// ------------------------------------------------------------------------
// -- Validator class
// ------------------------------------------------------------------------

function Validator(formName) {
  this.formObj = document.forms[formName];

  this.addValidation = add_field_validator;
  this.addAction = add_form_action;
  this.setErrorHeader = set_error_header;
  this.setBoxStyles = set_box_styles;
  
  this.validators = new Array();
}

