Fresh.Date = function () {
	var _formats = [],
		_activeFormat,
		slashRegexp =  /^(\d+)\/(\d+)\/(\d+)$/,
		dashRegexp = /^(\d+)\-(\d+)\-(\d+)$/,
		now = new Date(),
		sYr = now.getFullYear(),
		Cent = Math.round(sYr / 100),
		lastCent = Cent - 1;

	// Reformats 2 digit years.
	var _adjustShortYear = function (year) {
		if (year > 2000) {
			year = year.substring(2);
		}
		return (year > 50) ? lastCent + year : Cent + year;
	}
	
	var _adjustLongYear = function (year) {
		return (year < 100) ? Cent + year : year;
	}

	//Format 0
	_formats.push({
		parser: slashRegexp,
		stringFormat: 'mm/dd/yy',
		map: function (pieces) {
			pieces[3] = _adjustShortYear(pieces[3]);
			return {'month': pieces[1], 'day': pieces[2], 'year': pieces[3]};
		},
		toDate: function (pieces) {
			pieces[3] = _adjustShortYear(pieces[3]);
			return new Date(pieces[3], pieces[1] - 1, pieces[2]);
		},
		toString: function (date) {
			return (
				Fresh.Date.padZero((date.getMonth() + 1), 2) + "/" +
				Fresh.Date.padZero(date.getDate(), 2) + "/" +
				String(date.getFullYear()).substr(2, 4)
			);
		}
	});

	// Format 1
	_formats.push({
		parser: slashRegexp,
		stringFormat: 'mm/dd/yyyy',
		map: function (pieces) {
			pieces[3] = _adjustLongYear(pieces[3]);
			return {'month': pieces[1], 'day': pieces[2], 'year': pieces[3]};
		},
		toDate: function (pieces) {
			return new Date(pieces[3], pieces[1] - 1, pieces[2]);
		},
		toString: function (date) {
			return (
				Fresh.Date.padZero(date.getMonth() + 1, 2) + "/" +
				Fresh.Date.padZero(date.getDate(), 2) + "/" +
				date.getFullYear()
			);
		}
	});

	//format 2
	_formats.push({
		parser: slashRegexp,
		stringFormat: 'dd/mm/yy',
		map: function (pieces) {
			pieces[3] = _adjustShortYear(pieces[3]);
			return {'month': pieces[2], 'day': pieces[1], 'year': pieces[3]};
		},
		toDate: function (pieces) {
			pieces[3] = _adjustShortYear(pieces[3]);
			return new Date(pieces[3], pieces[2] - 1, pieces[1]);
		},
		toString: function (date) {
			return (
				Fresh.Date.padZero(date.getDate(), 2) + "/" +
				Fresh.Date.padZero(date.getMonth() + 1, 2) + "/" +
				String(date.getFullYear()).substr(2, 4)
			);
		}
	});

	//format 3
	_formats.push({
		parser: slashRegexp,
		stringFormat: 'dd/mm/yyyy',
		map: function (pieces) {
			pieces[3] = _adjustLongYear(pieces[3]);
			return {'month': pieces[2] , 'day': pieces[1], 'year': pieces[3]};
		},
		toDate: function (pieces) {
			return new Date(pieces[3], pieces[2] - 1, pieces[1]);
		},
		toString: function (date) {
			return (
				Fresh.Date.padZero(date.getDate(), 2) + "/" +
				Fresh.Date.padZero(date.getMonth() + 1, 2) + "/" +
				date.getFullYear()
			);
		}
	});

	//format 4
	_formats.push({
		parser: dashRegexp,
		stringFormat: 'yy-mm-dd',
		map: function (pieces) {
			pieces[1] = _adjustShortYear(pieces[1]);
			return {'month': pieces[2], 'day': pieces[3], 'year': pieces[1]};
		},
		toDate: function (pieces) {
			pieces[1] = _adjustShortYear(pieces[1]);
			return new Date(pieces[1], pieces[2] - 1, pieces[3]);
		},
		toString: function (date) {
			return (
				String(date.getFullYear()).substr(2, 4) + "-" +
				Fresh.Date.padZero(date.getMonth() + 1, 2) + "-" +
				Fresh.Date.padZero(date.getDate(), 2)
			);
		}
	});

	var _defaultFormat = {
		parser: dashRegexp,
		stringFormat: 'yyyy-mm-dd',
		map: function (pieces) {
			pieces[1] = _adjustLongYear(pieces[1]);
			return {'month': pieces[2], 'day': pieces[3], 'year': pieces[1]};
		},
		toDate: function (pieces) {
			return new Date(pieces[1], pieces[2] - 1, pieces[3]);
		},
		toString: function (date) {
			return (
				date.getFullYear() + "-" +
				Fresh.Date.padZero((date.getMonth() + 1), 2) + "-" +
				Fresh.Date.padZero(date.getDate(), 2)
			);
		}
	};

	/*
	uses the dateFormat ints to change the active formatter
	*/
	var _setActiveFormat = function (dateFormat) {
		if (_formats[dateFormat]) {
			_activeFormat = _formats[dateFormat];
		} else {
			_activeFormat = _defaultFormat;
		}
	}

	//public methods.
	return {
	/*
	Convert a date string into a Date object

	@param String dateString - Date string to be converted to Date object
	@param int dateFormat - Format number
	*/
		toDate: function (dateString, dateFormat) {
			_setActiveFormat(dateFormat);
			var pieces = _activeFormat.parser.exec(dateString);
			if (!pieces || !pieces.length) {
				return false;
			}
			return _activeFormat.toDate(pieces);
		},
	/*
	Convert a Date into a formatted string

	@param Date - Date object to convert
	@param int - format desired
	*/
		toString: function (date, dateFormat) {
			_setActiveFormat(dateFormat);
			return _activeFormat.toString(date);
		},
	
	/*
	Convert a date string into a hash containing month, year, and day parts
	
	@param String dateString - Date string to be converted
	@param int dateFormat - Format number
	*/
		toHash: function (dateString, dateFormat) {
			_setActiveFormat(dateFormat);
			var pieces = _activeFormat.parser.exec(dateString);
			if (!pieces || !pieces.length) {
				return false;
			}
			return _activeFormat.map(pieces);
		},
	/*
	Reformats a date string from one of the formats into an ISO datestring

	@param string dateString - Date string to be reformatted.
	@param int dateFormat - Format dateString is in.
	*/
		isoDate: function (dateString, dateFormat) {
			var date = Fresh.Date.toDate(dateString, dateFormat);
			if (!date) {
				return false;
			}
			return (
				date.getFullYear() + '-' +
				Fresh.Date.padZero(date.getMonth() + 1, 2) + '-' +
				Fresh.Date.padZero(date.getDate(), 2)
			);
		},
	/*
	Check if a datestring is valid for the current systemFormat
	*/
		valid: function (dateString) {
			var format = Fresh.Preferences.get('date_format');
			_setActiveFormat(format);
			var pieces = _activeFormat.parser.exec(dateString);
			if (!pieces || !pieces.length) {
				return false;
			}
			var mapped = _activeFormat.map(pieces);

			if (mapped.year.length > 4) {
				return false;
			}

			var dateTest = new Date(mapped.year, mapped.month - 1, mapped.day);
			var mappedResult = mapped.year + '-' + mapped.month + '-' + mapped.day;
			var testResult = (
				dateTest.getFullYear() + '-' +
				Fresh.Date.padZero(dateTest.getMonth() + 1, 2) + '-' +
				Fresh.Date.padZero(dateTest.getDate(), 2)
			);

			if (mappedResult !== testResult) {
				return false;
			}
			return true;
		},
	/*
	Get the active system format.
	*/
		systemFormat: function () {
			var format = Fresh.Preferences.get('date_format');
			_setActiveFormat(format);
			return _activeFormat.stringFormat;
		},
	/*
	Check the form element with inputId, and ensure its value is a valid datestring
	alert() an error message if its not.
	*/
		alertOnInvalidDate: function (inputId) {
			var date = document.getElementById(inputId).value;

			if (!Fresh.Date.valid(date)) {
				alert("Please verify that you have entered a valid date format (" + Fresh.Date.systemFormat() + "). " +
					  "We recommend using the date picker provided.");
				return false;
			}
			return true;
		},
	/*
	Pad a string with leading 0's until it is newLength
	*/
		padZero: function (string, newLength) {
			var pad = "",
				len = newLength - String(string).length,
				i;

			for (i = 0; i < len; i++) {
				pad += "0";
			}
			return pad + string;
		}
	};
}();

(function () {
	var exports = {
		'padZero': Fresh.Date.padZero,
		'str2dt': Fresh.Date.toDate,
		'dt2dtstr': Fresh.Date.toString,
		'str2dtstr': Fresh.Date.isoDate,
		'validDateString': Fresh.Date.valid,
		'alertOnInvalidDate': Fresh.Date.alertOnInvalidDate,
		'systemDateFormat': Fresh.Date.systemFormat
	};
	for (var alias in exports) {
		window[alias] = exports[alias];
	}
})();

/*
 Generates an event handler that can be used to verify a valid
 date range for a formset.  Ensure that the startDate is after the endDate
*/
function generateDateRangeValidator(startField, endField, message) {
	if (message == undefined) {
		message = 'Please ensure that the selected start date is before the selected end date.';
	}
	return function (event) {
		try {
			$(startField + ', ' + endField).
				removeClass('errorInput').
				each(function () {
					if (!Fresh.Date.valid($(this).val())) {
						$(this).addClass('errorInput').focus();
						throw 'Invalid date selected';
					}
				}
			);
			var start = Fresh.Date.toDate($(startField).val(), Fresh.Preferences.get('date_format'));
			var end = Fresh.Date.toDate($(endField).val(), Fresh.Preferences.get('date_format'));
			if (start > end) {
				alert(message);
				throw 'Invalid date range chosen';
			}
		} catch (e) {
			event.stopPropagation();
			event.preventDefault();
		}
	};
}
