// Copyright 2009 AZPixels, LLC. All Rights Resrved.

/**********************************
* Character Counting Object       *
***********************************/

// Object to hold function and methods related to counting characters
function charCount(counter) {

	// Save the counter span tag
	this.counter = counter;

	// Expression to get the max length
	var regex_number = /[0-9]+/;

	// Array of matches from the regular expression
	var $matches = $(counter).text().match(regex_number);
	
	if ($matches == null) {
		return;
	}

	// The jQuery wrapper of the field we are counting, retreived by remove the first 5 characters from the span id, which should alays be "count_"
	var $field = $('#' + $(counter).attr('id').substring(6));

	// The field element itself
	this.field = $field[0];

	// Set the maxlength
	this.field.maxlength = $matches[0];

	// Save the location of the counter object
	this.field.counter = this;

	// Bind to the various events we want to update after
	$(this.field).keyup(function() {
		this.counter.count();
	}).blur(function() {
		this.counter.count();
	}).change(function() {
		this.counter.count();
	});

	// Inital count
	this.count();

}

/**
 *	Count a field's characters, responding approriatly
 */
charCount.prototype.count = function() {

	// Correct for too long of values
	if (this.get_val().length > this.field.maxlength) {

		// For correcting the field length to the proper length, we need to know the difference in length betwee how MySQL will view newlines and how the browser does.
		var charOffset = this.get_val().length - $(this.field).val().length;

		// Get the substr of the maximum length the field can be
		$(this.field).val($(this.field).val().substr(0, this.field.maxlength-charOffset));

	}

	// Write the counter text and toggle styling
	$(this.counter).text(this.get_val().length + '/' + this.field.maxlength + ' Characters').toggleClass('form-char-count-on', this.get_val().length != 0);

}

/**
 *	Get the value of a field, adjusting for variations in newline characters
 */
charCount.prototype.get_val = function() {

	// Get the value of the field
	var val = $(this.field).val();

	// Adjust newlines so can do correct character counting for MySQL. MySQL counts a newline as 2 characters.
	if (val.indexOf('\r\n') != -1) {

		// this is IE on windows. Puts both characters for a newline, just what MySQL does. No need to alter

	} else if (val.indexOf('\r') != -1) {

		// This is IE on a Mac. Need to add the line feed
		val = val.replace(/\r/g, "\r\n");

	} else if (val.indexOf('\n') != -1) {

		// This is Firefox on any platform. Need to add carriage return
		val = val.replace(/\n/g, "\r\n");

	}

	//Return the value
	return val;
}



/**********************************
* Validation Object               *
**********************************/

// This object holds everything dealing with the validaiton of a particular form
function Validation(form) {

	var self = this;
	this.form = form;

	// Bind to the form's on submit
	$(this.form).submit(function() {

		// Initialize the errors array
		self.errors = Array();

		// Loop the form elements
		var elements = self.form.elements;
		$.each(elements, function(i) {

			// Check the element for errors
			self.check(elements[i]);
			$(this).blur();

		});

		// If we don't have any errors, let the form submit
		if (!self.errors.length) {
			return true;
		}

		// Loop errors, building a notice and highlighting forms
		var notice_message = '';
		$.each(self.errors, function(i) {
			notice_message += self.errors[i].message + "\r\n";
			self.errors[i].highlight();
		});

		// Display the notice
		display_notice(notice_message, 'notice-error');

		return false;
	});

}

/**
 *	Check an element against it's listed validation requirements
 */
Validation.prototype.check = function(element) {

	/** VALUES AND VALIDATION INFORMATION ***********************/

	var self = this;
	var value = this.get_value(element);

	// Loop the catalog until we find the entry for this element
	var catalog_entry = null;
	$.each($validation_catalog, function(i) {
		if ($validation_catalog[i].id == $(element).attr('id')) {
			catalog_entry = $validation_catalog[i];
			return;
		}
	});

	// If this element doesn't have a validation entry, don't validate it
	if (catalog_entry == null) {
		return;
	}


	/** CHECK MATCHES ***********************/

	// Loop the comparison requirements for this element
	$.each(catalog_entry.compare, function(i) {

		// Get the other element
		var element2 = $('#' + catalog_entry.compare[i]);

		// Element [0] in the jquery object is the actual element
		element2 = element2[0];

		// Get the value
		var compare_value = self.get_value(element2);

		// If the values don't match, send an error
		if (compare_value != value) {
			self.errors.push(new Validation_Error(element, self.get_label(element).text() + ' must match ' + self.get_label(element2).text()));
		}

	});


	/** CHECK REQUIRED ***********************/

	// See if the value is required
	var required = false;
	$.each(catalog_entry.regex, function(i) {
		if (catalog_entry.regex[i] == 'required') {
			required = true;
			//catalog_entry.regex.splice(i, 1);
		}
	});

	// If the value isnt required, and the value doesn't exist, don't check it.
	if (!value.length && !required) {
		return;
	} else if (required && !value.length) {
		self.errors.push(new Validation_Error(element, self.get_label(element).text() + ': Value is Required'));
		return;
	}


	/** CHECK REGEX ***********************/

	// Loop the regular expressions this field requires
	$.each(catalog_entry.regex, function(i) {

		// Loop the regular expression list until we find the one we are looking for
		var validation = null;
		$.each($regular_expressions, function(j) {
			if ($regular_expressions[j].name == catalog_entry.regex[i]) {
				validation = $regular_expressions[j];
				return;
			}
		});

		// Create the regular expression
		var regexp = eval(validation.exp);

		// If the regular expression fails, send an error
		if (!regexp.test(value)) {
			self.errors.push(new Validation_Error(element, self.get_label(element).text() + ': ' + validation.error));
		}

	});

}


/**
 *	Get the label of an element
 */
Validation.prototype.get_label = function(element) {

	// If we havn't already, save the label into the elements DOM for easy access outside this class
	if (typeof element.label == "undefined") {
		element.label = $("label[for='" + $(element).attr('id') + "']");
	}

	// Return the label element
	return element.label;

}


/**
 *	Get the value of a field, taking into consideration checkboxes and radio buttons
 */
Validation.prototype.get_value = function(element) {

	// Checkboxe/radio are a special cases where we need thier "value" to exist if they are selected
	if ($(element).attr('type') == 'checkbox' || $(element).attr('type') == 'radio') {

		if ($(element).checked) {
			return $(element).val();
		}

	// Otherwise just return the elements value
	} else {

		// Trim whitespace if not a file field
		if ($(element).attr('type') != 'file') {
			$(element).val($.trim($(element).val()));
		}
		return $(element).val();

	}

	// By default, we return nothing
	return null;

}



/**********************************
* Validation Error Object         *
**********************************/

// The Validation_Error object provids a place to hold the parts of an error as well as error specific functions
function Validation_Error(element,message) {
	this.element = element;
	this.message = message;
}

/**
 *	Highlight the element, showing the user the error
 */
Validation_Error.prototype.highlight = function() {

	// Highlight the element
	this.element.label.css({backgroundColor:'#A32A1D', color:'#FFFFFF'});

	// Remove the highlight when the element comes into focus
	$(this.element).focus( function(){
		this.label.css({backgroundColor:'', color:''});
	});

}



/*************************************
* Initialization (on document ready) *
**************************************/


$(function(){

	/*** DATE PICKER **************************/

	// Loop datapicker elements, assigning datepicker jQuery UI to them
	$('.datepicker').datepicker({
		changeMonth: true,
		changeYear: true
	});


	/*** FORM FILL *****************************/

	// Make sure we have the $form_fill variable
	if (typeof $form_fill != 'undefined' && $form_fill != null) {

		// Loop the form fill
		$.each($form_fill, function($name, $value){

			// Find the field with that id, and set its value. jQuery handles setting checkboxes and radio buttons.
			$("[id='" + $name + "']").val([$value]);

		});

	}


	/*** CHARACTER COUNTERS *****************************/

	// Loop all the character counters, creating charCount objects for each
	$("span[rel='character_counter']").each( function(){
		new charCount(this);
	});


	/*** VALIDATION *****************************/

	// If the validation information exists
	if(typeof $validation_catalog != 'undefined' && typeof $regular_expressions != 'undefined'){

		// Loop forms, creating charCount objects for each
		$("form").each( function(){
			new Validation(this);
		});

	}

});