(function(jQuery){
	jQuery.fn.frClockCustom = function(options)
		{
		    var options = jQuery.extend(jQuery.fn.frClockCustom.defaults, options || {});

			return this.each(
				function()
				{
					var element = jQuery(this);
					element.options = options;
					element.timerID = null;

					jQuery.fn.frClockCustom.start(element);
				}
				);
		};
       
	jQuery.fn.frClockCustom.start = function(element)
		{
			jQuery.fn.frClockCustom.stop(element);
			jQuery.fn.frClockCustom.updateDisplay(element);
		};

	jQuery.fn.frClockCustom.stop = function(element)
		{
			if(element.timerID)
			{
				clearTimeout(element.timerID);
				element.timerID = null;
			}
		};

	jQuery.fn.frClockCustom.updateDisplay = function(element)
		{
			var now = new Date();

			var timeInfo = {
				timezoneOffset: now.getTimezoneOffset(),
				timestamp: now.valueOf(),
				weekDay: now.getDay(),
				day: now.getDate(),
				month: now.getMonth(),
				year: now.getFullYear(),
				hour: now.getHours(),
				minute: now.getMinutes(),
				second: now.getSeconds(),
				millisecond: now.getMilliseconds()
				};

			if(element.options.utc)
			{
				timeInfo.timestamp = now.UTC();
				timeInfo.weekDay = now.getUTCDay();
				timeInfo.day = now.getUTCDate();
				timeInfo.month = now.getUTCMonth();
				timeInfo.year = now.getUTCFullYear();
				timeInfo.hour = now.getUTCHours();
				timeInfo.minute = now.getUTCMinutes();
				timeInfo.second = now.getUTCSeconds();
				timeInfo.millisecond = now.getUTCMilliseconds();
			}

			var timeString = element.options.timeString;
			var text = '';

			var i = 0;

			while(i < timeString.length)
			{
				var currentChar = timeString.charAt(i);

				if(currentChar == '%')
				{
					var nextChar = (i < (timeString.length - 1)) ? timeString.charAt(i + 1) : '';

					if(nextChar == '%')
					{
						text += '%';
					}
					else if(nextChar == 'd')
					{
						text += (timeInfo.day < 10) ? ('0' + timeInfo.day) : timeInfo.day;
					}
					else if(nextChar == 'j')
					{
						text += timeInfo.day;
					}
					else if(nextChar == 'D')
					{
						text += element.options.weekdaysShort[timeInfo.weekDay];
					}
					else if(nextChar == 'l')
					{
						text += element.options.weekdaysLong[timeInfo.weekDay];
					}
					else if(nextChar == 'S')
					{
						text += element.options.daySuffix[(timeInfo.day > 3) ? 0 : timeInfo.day];
					}
					else if(nextChar == 'F')
					{
						text += element.options.monthsLong[timeInfo.month];
					}
					else if(nextChar == 'm')
					{
						text += (timeInfo.month < 10) ? ('0' + (timeInfo.month + 1)) : (timeInfo.month + 1);
					}
					else if(nextChar == 'M')
					{
						text += element.options.monthsShort[timeInfo.month];
					}
					else if(nextChar == 'n')
					{
						text += (timeInfo.month + 1);
					}
					else if(nextChar == 'Y')
					{
						text += timeInfo.year;
					}
					else if(nextChar == 'y')
					{
						var yearTemp = (timeInfo.year % 100);
						text += (yearTemp < 10) ? ('0' + yearTemp) : yearTemp;
					}
					else if((nextChar == 'a') || (nextChar == 'A'))
					{
						text += element.options.timeMeridium[(timeInfo.hour < 12) ? 0 : 1];
					}
					else if(nextChar == 'g')
					{
						text += ((timeInfo.hour % 12) + 1);
					}
					else if(nextChar == 'G')
					{
						text += timeInfo.hour;
					}
					else if(nextChar == 'h')
					{
						hourTemp = (timeInfo.hour % 12) + 1;
						text += (hourTemp < 10) ? ('0' + hourTemp) : hourTemp;
					}
					else if(nextChar == 'H')
					{
						text += (timeInfo.hour < 10) ? ('0' + timeInfo.hour) : timeInfo.hour;
					}
					else if(nextChar == 'i')
					{
						text += (timeInfo.minute < 10) ? ('0' + timeInfo.minute) : timeInfo.minute;
					}
					else if(nextChar == 's')
					{
						text += (timeInfo.second < 10) ? ('0' + timeInfo.second) : timeInfo.second;
					}
					else if(nextChar == 'u')
					{
						text += timeInfo.millisecond;
					}
					else if((nextChar == 'O') || (nextChar == 'P'))
					{
						offsetHours = Math.round(timeInfo.timezoneOffset / 60);

						text += (offsetHours >= 0) ? '+' : '-';

						if(nextChar == 'O')
						{
							text += ((offsetHours < 10) ? ('0' + offsetHours) : offsetHours) + '00';
						}
						else
						{
							text += ((offsetHours < 10) ? ('0' + offsetHours) : offsetHours) + ':00';
						}
					}
					else if(nextChar == 'U')
					{
						text += timeInfo.timestamp;
					}

					i += 2;
				}
				else
				{
					text += currentChar;
					i++;
				}
			}

			element.html(text);
			element.timerID = setTimeout(function() { jQuery.fn.frClockCustom.updateDisplay(element); }, element.options.delay);

			if(element.options.onUpdate)
			{
				element.options.onUpdate.call(this, element, timeInfo);
			}
		};

	// Default options
	jQuery.fn.frClockCustom.defaults =
		{
			timeString: '%l %j %F %Y %H:%i',
			delay: 1000,
	        utc: false,
			onUpdate: null,
			daySuffix: ['th', 'st', 'nd', 'rd'],
			weekdaysLong: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
			weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
			monthsLong: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
			monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
			timeMeridium: ['AM', 'PM']
		};
})(jQuery);