//#######################################################
// Add additional String methods
//#######################################################

if (String.prototype.format == null)
{
	String.prototype.format = function()
	{
		var txt = this;
		for (var i = 0; i < arguments.length ; i++)
		{
			var re = new RegExp('\\{' + i + '\\}','gm');
			txt = txt.replace(re, arguments[i]);
		}
		return txt;
	}	
}

if (String.format == null)
{
	String.format = function()
	{
		for (var i = 1; i < arguments.length; i++)
		{
			var re = new RegExp('\\{' + (i - 1) + '\\}', 'gm');
			arguments[0] = arguments[0].replace(re, arguments[i]);
		}
		return arguments[0];
	}
}

if (String.prototype.trim == null)
{
	String.prototype.trim = function()
	{
		var txt = this;
		return txt.replace(/^[\s\xA0]+/, '').replace(/[\s\xA0]+$/, '');
	}
}

if (String.prototype.startsWith == null)
{
	String.prototype.startsWith = function(text)
	{
	    var txt = this;
		return txt.indexOf(text) == 0;
	}
}

if (String.prototype.endsWith == null)
{
	String.prototype.endsWith = function(text)
	{
	    var txt = this;
		return txt.indexOf(text) == txt.length - text.length;
	}
}

if (String.prototype.isEmail == null)
{
	String.prototype.isEmail = function()
	{
		var txt = this;
		return /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.test(txt);
	}
}

//#######################################################
// Add additional Array methods
//#######################################################

if (Array.prototype.forEach == null)
{
	Array.prototype.forEach = function(method)
	{
		for (var i = 0; i < this.length; i++)
		{
			var item = this[i];
			method(item);
		}
	}
}

if (Array.prototype.indexOf == null)
{
	Array.prototype.indexOf = function(value, startAt)
	{
		var res = -1;
		
		if (startAt == null)
		{
			startAt = 0;
		}
		
		for (var i = startAt; i < this.length; i++)
		{
			if (this[i] == value)
			{
				res = i;
				break;
			}
		}
		
		return res;
	}
}

if (Array.prototype.contains == null)
{
	Array.prototype.contains = function(value, startAt)
	{
		return this.indexOf(value, startAt) >= 0;
	}
}

if (Array.prototype.remove == null)
{
	Array.prototype.remove = function(from, to)
	{
		var rest = this.slice((to || from) + 1 || this.length);
		this.length = from < 0 ? this.length + from : from;
		return this.push.apply(this, rest);
	}
}

//#######################################################
// Add additional Date methods
//#######################################################

Date.prototype.addDays = function(days)
{
	this.setDate(this.getDate() + days);
}

//#######################################################
// Client dimensions (window and scroll locations)
//#######################################################

function ClientDimensions()
{

	this.f_filterResults = function(n_win, n_docel, n_body)
	{
		var n_result = n_win ? n_win : 0;
		if (n_docel && (!n_result || (n_result > n_docel)))
			n_result = n_docel;
		return n_body && (!n_result /* || (n_result > n_body) */) ? n_body : n_result; // commented section doesn't work with IE8.
	}
	
	this.f_clientWidth = function() 
	{
		return this.f_filterResults(
			window.innerWidth ? window.innerWidth : 0,
			document.documentElement ? document.documentElement.clientWidth : 0,
			document.body ? document.body.clientWidth : 0
		);
	}
	
	this.f_clientHeight = function()
	{
		return this.f_filterResults (
			window.innerHeight ? window.innerHeight : 0,
			document.documentElement ? document.documentElement.clientHeight : 0,
			document.body ? document.body.clientHeight : 0
		);
	}
	
	this.f_scrollLeft = function()
	{
		return this.f_filterResults (
			window.pageXOffset ? window.pageXOffset : 0,
			document.documentElement ? document.documentElement.scrollLeft : 0,
			document.body ? document.body.scrollLeft : 0
		);
	}

	this.f_scrollTop = function()
	{
		return this.f_filterResults (
			window.pageYOffset ? window.pageYOffset : 0,
			document.documentElement ? document.documentElement.scrollTop : 0,
			document.body ? document.body.scrollTop : 0
		);
	}
	
	this.Refresh = function()
	{
		this.ClientWidth = this.f_clientWidth();
		this.ClientHeight = this.f_clientHeight();
		this.ScrollLeft = this.f_scrollLeft();
		this.ScrollTop = this.f_scrollTop();
		this.ScrollRight = this.ScrollLeft + this.ClientWidth;
		this.ScrollBottom = this.ScrollTop + this.ClientHeight;
	}
	
	this.ScrollTo = function(scrollTop)
	{
		var isDone = false;
		
		if (window.pageYOffset != null)
		{
			try
			{
				window.pageYOffset = scrollTop;
				isDone = true;
			}
			catch (err)
			{
			}
		}
		
		if (!isDone)
		{
			if (document.documentElement != null && document.documentElement.scrollTop != null)
			{
				document.documentElement.scrollTop = scrollTop;
			}
			else if (document.body != null && document.body.scrollTop != null)
			{
				document.body.scrollTop = scrollTop;
			}
		}
	}
	
	this.ToString = function()
	{
		return 'Width: {0}px, Height: {1}px, ScrollLeft: {2}px, ScrollTop: {3}px'.format(this.ClientWidth, this.ClientHeight, this.ScrollLeft, this.ScrollTop);
	}
	
	this.Refresh();
}

//#######################################################
// General helper functions
//#######################################################

function ShowHide(elementId, show)
{
	var el = document.getElementById(elementId);
	
	if (el == null)
	{
		return;
	}
	
	if (show == true)
	{
		show = '';
	}
	else if (show == false)
	{
		show = 'none';
	}
	else
	{
		show = (el.style.display == 'none') ? '' : 'none';
	}
	
	el.style.display = show;
}

function IterateItems(elementName, willProcessItem, itemProcessor)
{
	var items = document.getElementsByTagName(elementName);
	
	for (var i = 0; i < items.length; i++)
	{
		var item = items[i];
		if (willProcessItem(item))
		{
			var doContinue = itemProcessor(item);
			if (doContinue != null && !doContinue)
			{
				break;
			}
		}
	}
}

//#######################################################
// Cookie manipulation functions
//#######################################################

function GetCookie(name) 
{
	var res = '';
	var cookie = document.cookie;
	var nameLen = name.length + 2;
	var start = cookie.indexOf(' ' + name + "=");
	
	if (start == -1)
	{
		start = cookie.indexOf(';' + name + '=');
	}
	
	if (start == -1 && cookie.indexOf(name + '=') == 0)
	{
		nameLen--;
		start = 0;
	}
	
	if (start >= 0)
	{
		var len = start + nameLen;
		var end = cookie.indexOf(";", len);
	
		if (end == -1) 
		{
			end = cookie.length;
		}
		
		res = unescape(cookie.substring(len, end));
	}
	
	// Debug('Cookies[' + name + '] retrieved: "' + res + '"');
	return res;
}

function SetCookie(name, value, expires, path, domain, isSecure)
{
	var cookie = name + '=' + escape(value);
	
	if (expires != null)
	{
		if (expires.toGMTString == null && !isNaN(expires))
		{
			var date = new Date();
			date.addDays(expires);
			expires = date;
		}

		if (expires.toGMTString != null)
		{
			cookie += '; expires=' + expires.toGMTString();
		}
	}
	
	if (path != null)
	{
		cookie += '; path=' + path;
	}
	
	if (domain != null)
	{
		cookie += '; domain=' + domain;
	}
	
	if (isSecure)
	{
		cookie += '; secure';
	}
	
	// Debug('Cookies[' + name + '] set to: "' + cookie + '"');
	
	document.cookie = cookie;
}


//#######################################################
// Error logging for Javascript errors.
//#######################################################

function FinExErrorLog(clientName)
{
	this.isFirstError = true;
	this.clientName = clientName;
	document.errorLog = this;
	return this;
}

FinExErrorLog.prototype.enable = function()
{
	window.onerror = function reportError(msg, url, line)
	{
		var errorLog = document.errorLog;

		if (!errorLog.isFirstError)
		{
			return;
		}

		errorLog.isFirstError = false;
		var stackTrace = "";
		
// This will always be null because it's an event from the User Agent.
// Perhaps if we called it directly in a catch clause it may be useful.
//		for (var a = reportError.caller; a != null; a = a.caller)
//		{
//			// Show function inputs.
//			if (a.arguments.length > 0)
//			{
//				stackTrace += "arguments [";
//				for (var n = 0; n < a.arguments.length; n++)
//				{
//					stackTrace += a.arguments[n] + ",";
//				}
//				stackTrace = stackTrace.slice(0, stackTrace.length - 1);
//				stackTrace += "]";
//			}

//			var funcText = a.toString().replace("function ", "");
//			stackTrace += " at " + funcText.split('{')[0] + " ";
//		}

		var re = /http\:\/\/[^\/]+/g;
		var errUrl = document.location.href.match(re) + '/ClientsV21/Core/Webservices/RemoteLogging.asmx/LogError?client={0}&msg={1}&url={2}&line={3}&stack={4}';
		errUrl = errUrl.format(errorLog.clientName, escape(msg), escape(url), line, escape(stackTrace));
		errorLog.postData(errUrl);
	}
}

FinExErrorLog.prototype.postData = function(errUrl)
{
	var req = new XMLHttpRequest();
	errUrl += '&rnd=' + Math.random(); // Ensure that it's unique; else we'll lose log items.
	req.open("GET", errUrl, true);
	req.send(null);
}
