/**
 * Automagical form validation class.
 * @author Ryan Sandor Richards
 * @copyright 2009 FreeCause, Inc.
 */
var Validator = {
  /**
   * Built-in Validator Rules and their handlers.
   */
  rules: {
    ':required': {
    	handler: /^.+$/,
    	type: 'regex'
    },
    ':number': {
    	handler: /^[0-9]+$/,
    	type: 'regex'
    },
    ':email': {
    	handler: /^[\w\-\+\._]+\@[a-zA-Z0-9][-a-zA-Z0-9\.]*\.[a-zA-Z]+$/,
    	type: 'regex'
    },
    ':zipcode': {
    	handler: /^\d{5}$|^\d{5}\-\d{4}$/,
    	type: 'regex'
    },
    ':length\\(([0-9]+)\\)': {
    	handler: function (params) { return new RegExp('^.{' + params[1] + '}$'); },
    	type: 'function'
  },
    ':max-length\\(([0-9]+)\\)': {
    	handler: function (params) { return new RegExp('^.{0,' + params[1] + '}$'); },
    	type: 'function'
    },
    ':min-length\\(([0-9]+)\\)': {
    	handler: function (params) { return new RegExp('^.{' + params[1] + ',}$'); },
    	type: 'function'
   	},
    ':regex\\(\/([^\/]*)\/\\)': {
    	handler: function (params) { return new RegExp('^'+params[1]+'$'); },
    	type: 'function'
    },
    ':toolbar-name': {
    	handler: /^[a-zA-Z0-9][a-zA-Z0-9_ ]*$/,
    	type: 'regex'
    },
    ':url': {
    	handler: /([A-Za-z][A-Za-z0-9+.-]{1,120}:[A-Za-z0-9\/](([A-Za-z0-9$_.+!*,;/?:@&~=-])|%[A-Fa-f0-9]{2}){1,333}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*,;/?:@&~=%-]{0,1000}))?)|()/,
    	type: 'regex'
    },
    ':png': {
    	handler: /^.+\.png$/,
    	type: 'regex'
    },
    ':name': {
    	handler: /^[a-zA-Z\. ]+$/,
    	type: 'regex'
    },
    ':site-name': {
    	handler: /^[a-zA-Z0-9_ ]+$/,
    	type: 'regex'
    },
    ':friendly-url': {
    	handler: /^[a-z0-9_]+$/,
    	type: 'regex'
    }
  },

  /**
   * Because Safari is dubious you must enter function type rules in this list or they will not
   * be processed correctly. Danke!
   */
  funcs: [':length', ':max-length', ':min-length', ':regex'],

  /**
   * Initializes validation for child inputs and text areas of a given selector.
   * @param sel Selector for which to perform field validation.
   */
  init: function(sel) {
    $inputs = $(sel + ' input, ' + sel + ' textarea');
    for (var i = 0; i < $inputs.size(); i++) 
      Validator.parseRules($($inputs.get(i)));
  },
  
  /**
   * Parses rules for a given input and assigns handlers to the input
   * for each valid rule parsed.
   * @param $input Input for which to parse vald rules.
   */
  parseRules: function($input) {
    var classes = $input.attr('class').match(/(:[^ ]+)/g);
    var vald_rules = [];
    for (var i=0; classes != null && i < classes.length; i++) {
      for (var rule in Validator.rules) {
      	var type = Validator.rules[rule].type
        var handler = Validator.rules[rule].handler;
        var matches = classes[i].match(new RegExp(rule));
        if (matches != null) {
          if (type == 'regex') {
            vald_rules.push(handler);
          }
          else if (type == 'function') { 
            vald_rules.push(handler(matches));
          }
        }
      }
    }

    $input.data('vald_rules', vald_rules);
    $input.keyup(function () {
      Validator.validateField($(this));
    });
    $input.keyup();
  },

  /**
   * Validation routine for a single field.
   */
  validateField: function($input) {
    var rules = $input.data('vald_rules');
    if (typeof(rules) != "undefined" && rules != null && rules.length == 0)
      return true;
    for (var j = 0; j < rules.length; j++) {
      if (rules[j] == null) {
        continue;
      } 
      
      if ($input.val().match(rules[j]) == null) {
        $input.addClass('invalid');
        return false;
      }
    }
    $input.removeClass('invalid');
    return true;
  },

  /**
   * Performs validation on child inputs of the given selector.
   * @param Selector over which to perform validation.
   */
  validate: function(sel) {
    var valid = true;
    $inputs = $(sel + ' input, ' + sel + ' textarea');
    for (var i = 0; i < $inputs.size(); i++) { 
      if (!Validator.validateField($($inputs.get(i)))) { 
        valid = false;
      }
    }
    return valid;
  }
};
