/***********************************************************************************
* Quantum Utility Class                                                            *
* © 2011 Robot Scott LLC                                                           *
***********************************************************************************/
var Quantum =
{
	/***********************************************************************************
	* Options                                                                          *
	***********************************************************************************/
	Options : function (options, defaults)
	{
		var opts = {};

		if (typeof defaults != 'undefined')
		{
			for (var key in defaults)
			{
				opts[key] = defaults[key];
			}
		}

		if (typeof options !== 'undefined')
		{
			for (var key in options)
			{
				opts[key] = options[key];
			}
		}

		return opts;
	},
	/**********************************************************************************/


	/***********************************************************************************
	* Object                                                                           *
	***********************************************************************************/
	Object :
	{
		/***********************************************************************************
		* Is Array                                                                         *
		***********************************************************************************/
		IsArray : function (obj)
		{
			return !!(obj && obj.constructor == Array);
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Check Interface                                                                  *
		***********************************************************************************/
		CheckInterface : function (obj, intrf)
		{
			var fails   = false;
			var message = "Object failed to implement the following interfaces:";

			for (var member in intrf)
			{
				if ( (typeof obj[member] != typeof intrf[member]) )
				{
					message = message + member + "(" + typeof intrf[member] + " != " + typeof obj[member] + ")\n";
					fails = true;
				}
			}

			if (fails)
			{
				alert(message);
			}

			return (!fails);
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Clean                                                                            *
		***********************************************************************************/
		Clean : function (obj)
		{
			var result = false;

			if (obj)
			{
				/***********************************************************************************
				* Strings                                                                          *
				***********************************************************************************/
				if (typeof obj == 'string')
				{
					if (obj == 'true')
					{
						result = true;
					}
					else if (obj == 'false')
					{
						result = false;
					}
					else
					{
						result = unescape(obj);
					}
				}
				/**********************************************************************************/


				/***********************************************************************************
				* Arrays                                                                           *
				***********************************************************************************/
				else if (Quantum.Object.IsArray(obj))
				{
					result = [];

					for (var i = 1; i < obj.length; i++)
					{
						result.push(Quantum.Object.Clean(obj[i]));
					}
				}
				/**********************************************************************************/


				/***********************************************************************************
				* Objects                                                                          *
				***********************************************************************************/
				else if (typeof obj == 'object')
				{
					result = {};

					for (var key in obj)
					{
						result[key] = Quantum.Object.Clean(obj[key]);
					}
				}
				/**********************************************************************************/
			}

			return result;
		}
		/**********************************************************************************/
	},
	/**********************************************************************************/


	/***********************************************************************************
	* Session                                                                          *
	***********************************************************************************/
	Session :
	{
		Expired : function ()
		{
			alert("Your session has expired.\n\nPlease log out and log back in to continue.");
		}
	},
	/**********************************************************************************/


	/***********************************************************************************
	* Event Manager                                                                    *
	***********************************************************************************/
	EventManager :
	{
		/***********************************************************************************
		* Add Event Handler                                                                *
		***********************************************************************************/
		AddEventHandler : function()
		{
			return function (evt, func)
			{
				if (this.DOMNode)
				{
					var e = evt.toLowerCase();
					var AddFunc = true;

					if (!this.Events[e])
					{
						this.Events[e] = [];
						Browser.Events.AddEventHandler(this.DOMNode, e, this.GetEventHandler(this.Events[e]));
					}

					for (var i = 0; i < this.Events.length; i++)
					{
						if (this.Events[i] === func)
						{
							AddFunc = false;
							break;
						}
					}

					if (AddFunc)
					{
						this.Events[e].push(func);
					}
				}
			};
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Remove Event Handler                                                             *
		***********************************************************************************/
		RemoveEventHandler : function ()
		{
			return function (evt, func)
			{
				if (this.DOMNode)
				{
					var e = evt.toLowerCase();

					if (this.Events[e])
					{
						for (var i = 0; i < this.Events[e].length; i++)
						{
							if (this.Events[e][i].toString() == func)
							{
								this.Events[e].splice(i, 1);
								break;
							}
						}
					}
				}
			};
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Get Event Handler                                                                *
		***********************************************************************************/
		GetEventHandler : function ()
		{
			return function (handlers)
			{
				return function ()
				{
					for (var i = 0; i < handlers.length; i++)
					{
						handlers[i].call(this);
					}
				};
			};
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Fire Event                                                                       *
		***********************************************************************************/
		FireEvent : function ()
		{
			return function (evt)
			{
				if (typeof this.Events[evt] != 'undefined')
				{
					var handlers = this.Events[evt];

					for (var i = 0; i < handlers.length; i++)
					{
						handlers[i].call(document.getElementById(this.Id));
					}
				}
			};
		}
		/**********************************************************************************/
	},
	/**********************************************************************************/


	/***********************************************************************************
	* Format                                                                           *
	***********************************************************************************/
	Format :
	{
		/***********************************************************************************
		* Currency                                                                         *
		***********************************************************************************/
		Currency : function (num)
		{
			num = num.toString().replace(/\$|\,/g,'');

			if(isNaN(num))
			{
				num = "0";
			}

			var sign = (num == (num = Math.abs(num)));
			num = Math.floor(num*100+0.50000000001);

			var cents = num % 100;

			num = Math.floor(num / 100).toString();

			if(cents < 10)
			{
				cents = "0" + cents;
			}

			for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
			{
				num = num.substring(0,num.length-(4*i+3))+','+ num.substring(num.length-(4*i+3));
			}

			return (((sign)?'':'-') + '$' + num + '.' + cents);
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Phone                                                                            *
		***********************************************************************************/
		Phone : function (num)
		{
			var result = false;

			if (num)
			{
				result    = num.toString().replace(/\D/g, '');

				var regex = /^\d{10}$/;

				if(regex.test(result))
				{
					result = '(' + result.substring(0,3) + ') ' + result.substring(3,6) + '-' + result.substring(6,10);
				}
				else
				{
					result = num;
				}
			}

			return result;
		}
		/**********************************************************************************/
	},
	/**********************************************************************************/


	/***********************************************************************************
	* Forms                                                                            *
	***********************************************************************************/
	Forms :
	{
		/***********************************************************************************
		* Validate                                                                         *
		***********************************************************************************/
		Validate :
		{
			/***********************************************************************************
			* Required Fields                                                                  *
			***********************************************************************************/
			RequiredFields : function (el, req)
			{
				var message   = "";
				var oForm     = (typeof el == 'string') ? document.getElementById(el) : el;
				var oRequired = (typeof req ==  'object') ? req : false;

				if ((typeof(oForm) == 'object') && (oRequired))
				{
					for (var field in oRequired)
					{
						var name = oRequired[field];
						var obj = oForm.elements[field];

						if (obj)
						{
							switch(obj.type)
							{
								case "select-one" :
									if (obj.selectedIndex == -1 || obj.options[obj.selectedIndex].text == "")
									{
										message += " - " + name + "\n";
									}
								break;

								case "select-multiple" :
									if (obj.selectedIndex == -1)
									{
										message += " - " + name + "\n";
									}
								break;

								case "text"     :
								case "hidden"   :
								case "textarea" :
									if (obj.value == "" || obj.value == null)
									{
										message += " - " + name + "\n";
									}
								break;

								default :
									if ((obj.value == "") || (obj.value == null))
									{
										message += " - " + name + "\n";
									}
								break;
							}
						}
					}

					if (message.length > 0)
					{
						message = "Please complete the following fields:\n" + message;
					}
				}

				return (message);
			},
			/**********************************************************************************/


			/***********************************************************************************
			* Is Guid (Globally Unique Identifier                                              *
			***********************************************************************************/
			IsGuid: function (val)
			{
				if ((val) && (val.length != 0))
				{
					var re = /^[abcdefABCDEF0123456789]{8}\-[abcdefABCDEF0123456789]{4}\-[abcdefABCDEF0123456789]{4}\-[abcdefABCDEF0123456789]{4}\-[abcdefABCDEF0123456789]{12}$/i;
					return re.test(val);
				}

				return false;
			},
			/**********************************************************************************/


			/***********************************************************************************
			* Is Email                                                                         *
			***********************************************************************************/
			IsEmail: function (val)
			{
				if ((val) && (val.length != 0))
				{
					var re = /^[^\s()<>@,;:\/]+@\w[\w\.-]+\.[a-z]{2,}$/i;
					return re.test(val);
				}

				return false;
			},
			/**********************************************************************************/


			/***********************************************************************************
			* Is Phone Number                                                                  *
			***********************************************************************************/
			IsPhoneNumber: function(val)
			{
				if ((val) && (val.length != 0))
				{
					var re = /^\D?\d{3}\D?\s?\D?\d{3}\D?\d{4}$/;
					return re.test(val);
				}

				return false;
			},
			/**********************************************************************************/


			/***********************************************************************************
			* Is Number                                                                        *
			***********************************************************************************/
			IsNumber: function(val)
			{
				if ((val) && (val.length != 0))
				{
					var re = /^[-+]?[0-9]+(\.[0-9]+)?$/;
					return re.test(val);
				}
				return false;
			},
			/**********************************************************************************/


			/***********************************************************************************
			* Is Card Number                                                                   *
			***********************************************************************************/
			IsCardNumber: function(val)
			{
				if ((val) && (val.length != 0))
				{
					var re = /^\d{15,16}$/;
					return re.test(val);
				}
				return false;
			},
			/**********************************************************************************/


			/***********************************************************************************
			* Is CVV                                                                           *
			***********************************************************************************/
			IsCVV: function(val)
			{
				if ((val) && (val.length != 0))
				{
					var re = /^\d{3,4}$/;
					return re.test(val);
				}
				return false;
			},
			/**********************************************************************************/


			/***********************************************************************************
			* Is Zip Code                                                                      *
			***********************************************************************************/
			IsZipCode: function(val)
			{
				if ((val) && (val.length != 0))
				{
					var reA = /^\d{5}(-\d{4})?$/;
					var reC = /^[a-zA-Z]\d[a-zA-Z] ?\d[a-zA-z]\d$/;
					return reA.test(val); // || reC.test(val));
				}

				return false;
			},
			/**********************************************************************************/


			/***********************************************************************************
			* Is Even                                                                          *
			***********************************************************************************/
			IsEven: function(val)
			{
				if (this.IsNumber(val))
				{
					return (val % 2 == 0) ? true : false;
				}
				return false;
			}
			/**********************************************************************************/
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Set Selected Index (select box)                                                  *
		***********************************************************************************/
		SetSelectedIndex : function (el, val)
		{
			var obj = (typeof el == 'string') ? document.getElementById(el) : el;

			if (obj)
			{
				for (var i = 0; i < obj.options.length; i++)
				{
					if (obj.options[i].value == val)
					{
						obj.selectedIndex = i;
						return;
					}

					obj.selectedIndex = -1;
				}
			}
		}
		/**********************************************************************************/

	},
	/**********************************************************************************/


	/***********************************************************************************
	* Tables                                                                           *
	***********************************************************************************/
	Tables :
	{
		DeleteRows : function (id, blDeleteHeader) //--> Leaves a header row by default
		{
			var obj = (typeof id == 'string') ? document.getElementById(id) : id;

			if ((obj) && (obj.rows))
			{
				blDeleteHeader = (typeof blDeleteHeader == 'undefined') ? false : blDeleteHeader;

				var limit = (!!blDeleteHeader) ? 0 : 1;
				var rows  = obj.rows;

				if (rows.length > limit)
				{
					for(; rows.length > limit; )
					{
						obj.deleteRow(limit);
					}
				}
			}
		}
	},
	/**********************************************************************************/


	/***********************************************************************************
	* Date Time                                                                        *
	***********************************************************************************/
	DateTime :
	{
		/***********************************************************************************
		* Current Unix GMT Time                                                            *
		***********************************************************************************/
		CurrentUnixGMT : function ()
		{
			return (Date.parse((new Date()).toGMTString()) / 1000);
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Convert Unix GMT to current timezone                                             *
		***********************************************************************************/
		ConvertUnixGMT : function (val)
		{
			var result = false;

			if ((val) && (Quantum.Forms.Validate.IsNumber(val)) && (val > 0))
			{
				result = new Date(val * 1000);
			}

			return result;
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Format                                                                           *
		***********************************************************************************/
		Format :
		{
			/***********************************************************************************
			* Time                                                                             *
			***********************************************************************************/
			Time : function (val, sec)
			{
				val = ((val) && (val.getHours)) ? val : new Date();
				sec = (sec) ? true : false;

				var hours   = val.getHours();
				var minutes = val.getMinutes();
				var seconds = val.getSeconds();
				var ampm    = (hours > 11) ? 'pm' : 'am';

				if (hours > 12)
				{
					hours = hours - 12;
				}
				else if (hours == 0)
				{
					hours = 12;
				}

				hours = hours + "";
				if (hours.length == 1)
				{
					hours = "0" + hours;
				}

				minutes = minutes + "";
				if (minutes.length == 1)
				{
					minutes = "0" + minutes;
				}

				seconds = seconds + "";
				if (seconds.length == 1)
				{
					seconds = "0" + seconds;
				}

				 var result = (sec) ? hours + ':' + minutes + ':' + seconds + ' ' + ampm : hours + ':' + minutes + ' ' + ampm;
				 return result;
			},
			/**********************************************************************************/


			/***********************************************************************************
			* Date                                                                             *
			***********************************************************************************/
			Date : function (val, full)
			{
				val  = ((val) && (val.getHours)) ? val : new Date();
				full = (full) ? true : false;

				var months    = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
				var ab_months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
				var days      = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
				var ab_days   = ['Sun', 'Mond', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

				var result    = days[val.getDay()] + ' ' + months[val.getMonth()] + ' ' + val.getDate() + ', ' + val.getFullYear();

				if (!full)
				{
					var day = val.getDate();
					day = day + "";
					if (day.length == 1)
					{
						day = "0" + day;
					}

					result = day + ' ' + ab_months[val.getMonth()] + ' ' + val.getFullYear();
				}

				return result;
			}
			/**********************************************************************************/
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Formatted                                                                        *
		***********************************************************************************/
		Formatted : function (val, sep)
		{
			val = ((val) && (val.getHours)) ? val : new Date();
			sep = ((sep) && (typeof sep == 'string')) ? sep : ' ';

			var result = Quantum.DateTime.Format.Date(val) + sep + Quantum.DateTime.Format.Time(val);

			return result;
		}
		/**********************************************************************************/
	},
	/**********************************************************************************/


	/***********************************************************************************
	* Element                                                                          *
	***********************************************************************************/
	Element :
	{
		TimeToFade : 1000.0,

		/***********************************************************************************
		* Fade                                                                             *
		***********************************************************************************/
		Fade : function (el)
		{
			/***********************************************************************************
			* Set the element appropriately                                                    *
			***********************************************************************************/
			if (!el) { el = this; }
			if (typeof el == 'string') { el = document.getElementById(el) }
			/**********************************************************************************/

			if (el != null)
			{
				/***********************************************************************************
				* Add the FadeState property as needed                                             *
				***********************************************************************************/
				if (el.FadeState == null)
				{
					if ((el.style.opacity == null) || (el.style.opacity == '') || (el.style.opacity == '1'))
					{
						el.FadeState = 2;
					}
					else
					{
						el.FadeState = -2;
					}
				}
				/**********************************************************************************/


				/***********************************************************************************
				* Start Fading                                                                     *
				***********************************************************************************/
				if ((el.FadeState == 1) || (el.FadeState == -1))
				{
					el.FadeState    = (el.FadeState == 1) ? -1 : 1;
					el.FadeTimeLeft = TimeToFade - el.FadeTimeLeft;
				}
				else
				{
					el.FadeState    = (el.FadeState == 2) ? -1 : 1;
					el.FadeTimeLeft = Quantum.Element.TimeToFade;

					setTimeout("Quantum.Element.AnimateFade(" + new Date().getTime() + ",'" + el.id + "')", 33);
				}
				/**********************************************************************************/
			}
		},
		/**********************************************************************************/


		/***********************************************************************************
		* Animate Fade (private)                                                           *
		***********************************************************************************/
		AnimateFade : function (LastTick, ElementId)
		{
			var currentTick  = new Date().getTime();
			var elapsedTicks = currentTick - LastTick;

			var el = document.getElementById(ElementId);

			if (el)
			{
				if (el.FadeTimeLeft <= elapsedTicks)
				{
					el.style.opacity = (el.FadeState == 1) ? '1' : '0';
					el.style.filter  = 'alpha(opacity = ' + (el.FadeState == 1 ? '100' : '0') + ')';
					el.FadeState     = (el.FadeState == 1) ? 2 : -2;
				}
				else
				{
					el.FadeTimeLeft -= elapsedTicks;

					var newOpVal = (el.FadeState == 1) ? (1 - (el.FadeTimeLeft / Quantum.Element.TimeToFade)) : (el.FadeTimeLeft / Quantum.Element.TimeToFade);

					el.style.opacity = newOpVal;
					el.style.filter  = 'alpha(opacity = ' + (newOpVal * 100) + ')';

					setTimeout("Quantum.Element.AnimateFade(" + currentTick + ",'" + el.id + "')", 33);
				}
			}
		}
		/**********************************************************************************/
	}
	/**********************************************************************************/
};
/**********************************************************************************/

