/****************************************
* FILE: validation.js			*
* NAME: Mick Thomure                    *
* DESC: Functions for validating form	*
*	field data.			*
****************************************/


/**** VARIABLES *****************/

  var V_FIELDS, V_FUNCS, V_REQUIRED, V_INT, V_EMAIL, V_DATE, V_MAX_TYPE;

  V_REQUIRED = 0;
  V_INT      = 1;
  V_EMAIL    = 2;
  V_DATE     = 3;
  V_MAX_TYPE = 3;

  // Init [V_FIELDS] array
  V_FIELDS = Array(V_MAX_TYPE + 1);
  V_FUNCS  = Array(V_MAX_TYPE + 1);
  V_FUNCS[ V_REQUIRED ] = v_check_req;
  V_FUNCS[ V_INT      ] = v_check_int;
  V_FUNCS[ V_EMAIL    ] = v_check_email;
  V_FUNCS[ V_DATE     ] = v_check_date;


/**** v_check_* FUNCTIONS *****************/

  /**************************************************************
  * PARAM:							*
  *   f - (HTMLField) form field				*
  * DESC: Check that [f] exists.				*
  * RETURN: (bool) true if [f] exists, else false		*
  **************************************************************/
  function v_check_req(f) {
    if (f.type == 'radio' || f.type == 'checkbox') {
      if (!f.checked)
	return 0;

    } else if (f.type == 'select-one') {
      if (f.options[ f.selectedIndex ].value == '')
	return 0;

    } else if (f.value == '')
      return 0;

    return 1;
  }

  /**************************************************************
  * PARAM:							*
  *   f - (HTMLField) form field				*
  * DESC: Check that [f] is an integer.				*
  * RETURN: (bool) true if [f] is an integer, else false	*
  **************************************************************/
  function v_check_int(f) {
    return !isNaN(f.value);
  }

  /**************************************************************
  * PARAM:							*
  *   f - (HTMLField) form field				*
  * DESC: Check that [f] is an email address.			*
  * RETURN: (bool) true if [f] is an email address, else false	*
  **************************************************************/
  function v_check_email(f) {
    // Following regular expression matches email address formats
    //   match 1 or more word characters (alphanumeric and _)
    //   match 0 or more strings of a '.' and 1 or more word chars
    //   match an '@'
    //   match 1 or more word chars
    //   match 1 or more strings of a '.' and 1 or more word chars
    if (f.value.match("^[\\w\\-]+(\\.[\\w\\-]+)*\\@[\\w\\-]+(\\.[\\w\\-]+)+$"))
      return true;

    return false;
  }

  /**************************************************************
  * PARAM:							*
  *   f - (HTMLField) form field				*
  * DESC: Check that [f] is a date.				*
  * RETURN: (bool) true if [f] is a date, else false		*
  **************************************************************/
  function v_check_date(f) {
    if (u_parse_date(f.value))
      return 1;

    return 0;
  }

  /**************************************************************
  * PARAM:							*
  *   f - (HTMLField) form field				*
  * DESC: Check that [f] is a date in mysql format (Y-M-D).	*
  * RETURN: (bool) true if [f] is a date, else false		*
  **************************************************************/
  function v_check_date_mysql(f) {
    if (u_parse_date_mysql(f.value))
      return 1;

    return 0;
  }

  /******************************************************
  * PARAM:                                              *
  *   f - (HTMLField) form field			*
  *   p - (array) list of values to compare against     *
  * DESC: Decide if [v] is equal to any element of [p]. *
  * RETURN:
  ******************************************************/
  function v_check_list(f, p) {
    var v = f.value;
    var i;

    // Check that [p] is actually set
    if (!p)
      return false;

    for (i=0; i < p.length; i++) {
      if (v == p[i])
        return true;
    }

    return false;
  }

  /******************************************************
  * PARAM:                                              *
  *   f   - (HTMLField) form field			*
  *   min - (int) minimum bound				*
  *   max - (int) maximum bound				*
  * DESC: Decide if [v] is at least [min] and no        *
  *       greater than [max].                           *
  * RETURN:
  ******************************************************/
  function v_check_range(f, min, max) {
    var v = f.value;

    if (isNaN(v) || v < min || v > max)
      return false;

    return true;
  }

  /******************************************************
  * PARAM:                                              *
  *   f   - (HTMLField) value to check			*
  *   min - (int) minimum bound                         *
  *   max - (int) maximum bound                         *
  *   p   - (array) list of values to compare against   *
  * DESC: Decide if [v] is at least [min] and no        *
  *       greater than [max] or in [p].                 *
  * RETURN:
  ******************************************************/
  function v_check_range_or_list(f, min, max, p) {
    if (!(v_check_range(f, min, max) || v_check_list(f, p)))
      return false;

    return true;
  }

  /******************************************************
  * PARAM:                                              *
  *   f   - (HTMLField) value to check			*
  *   min - (int) minimum bound                         *
  *   max - (int) maximum bound                         *
  * DESC: Decide if [v] is at least [min] and no        *
  *       greater than [max] or the empty string.       *
  * RETURN:
  ******************************************************/
  function v_check_range_or_null(f, min, max) {
    if (!(v_check_range(f, min, max) || f.value == ''))
      return false;

    return true;
  }


/********************************************************************/


  /**************************************************************
  * PARAM:                                                      *
  *   func - (func) test function                               *
  *   name - (str) field name                                   *
  *   msg  - (str) error message                                *
  * DESC: Register [func] to test [name], with error message    *
  *       [msg].                                                *
  * RETURN: (bool) true on success, else false                  *
  **************************************************************/
  function v_add_field(type, name, msg) {
    if (type < 0 || type > V_MAX_TYPE || !(name && msg))
      return null;

    V_FIELDS[ type ][ name ] = msg;

    return 1;
  }

  /**************************************************************
  * PARAM:                                                      *
  * DESC: Clear all registered tests.                           *
  * RETURN: (bool) true                                         *
  **************************************************************/
  function v_clear_fields(type) {
    var i;

    if (type == null) {
      // Clear all fields from each type
      for (i = 0; i <= V_MAX_TYPE; i++)
	V_FIELDS[ i ] = Object();

    } else if (type >= 0 && type <= V_MAX_TYPE)
      // Clear field from [type]
      V_FIELDS[ type ] = Object();

    return 1;
  }

  /**************************************************************
  * PARAM:                                                      *
  *   name - (str) field name                                   *
  * DESC: Remove all tests for [name].                          *
  * RETURN: (bool) true on success, else false.                 *
  **************************************************************/
  function v_clear_field(name, type) {
    var i;

    if (name == null)
      return null;

    if (type == null) {
      // Clear field from each type
      for (i = 0; i <= V_MAX_TYPE; i++)
	delete V_FIELDS[ i ][ name ];

    } else if (type >= 0 && type <= V_MAX_TYPE)
      // Clear field from [type]
      delete V_FIELDS[ type ][ name ];

    return 1;
  }

  /**************************************************************
  * PARAM:                                                      *
  *   form - (obj) HTML form                                    *
  * DESC: Run checks on fields added with v_add_field(),        *
  *       displaying alert box on error.                        *
  * RETURN: (bool) true if all fields pass check, else false    *
  **************************************************************/
  function v_check_fields(form) {
    var i, rmess, req, name;
    rmess = Array();
    req   = Object();

    if (!(form = u_get_form(form)))
      return v_error(u_error());

    // Process each type
    for (i = 0; i <= V_MAX_TYPE; i++) {
      for (name in V_FIELDS[ i ]) {

	// if required test or required test doesn't exist or field is non-null
	// XXX: assumes non-null message string
	if (!i || !V_FIELDS[0][ name ] || req[ name ]) {

	  // Run the test function
	  if (!V_FUNCS[ i ](form[ name ]))
	    rmess[ rmess.length ] = V_FIELDS[i][ name ];

	  // Cache required fields that are valid
	  // these values are used when checks of other types are run against the same field
	  // because if the field didn't pass the required test, no other tests should be run on it
	  else if (!i)
	    req[ name ] = 1;

	} // END-IF

      } //END-FOR [name]
    } //END-FOR [i]

    if (rmess.length) {
      alert(rmess.join("\n"));
      return false;
    }

    return true;
  }

  /**************************************************************
  * PARAM:
  *   msg - (str) error message
  * DESC:
  * RETURN:
  **************************************************************/
  function v_error(msg) {
    if (msg != null) {
      V_ERROR = msg;
      return null;
    }

    return V_ERROR;
  }


/*******************************************************/


  // Init [V_FIELDS] elements
  v_clear_fields();


/*******************************************************/
