var CAPABLE;
CAPABLE = {};

CAPABLE.debug = false;

CAPABLE.w3cDom = (document.getElementById && document.createElement && document.getElementsByTagName);

CAPABLE.loadingDisplay = '<p style="text-align: center;"><br><br><img src="images/loading.gif" /></p>';

////////////////////////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////////////////////////////

// CAPABLE.Type (Type validation)

if (!CAPABLE.Type)
{
	CAPABLE.Type =
	{
		isElement: function (object)
		{
			return object && object.nodeType == 1;
		},
		isObject: function (object)
		{
			return typeof object === 'object';
		},
		isArray: function (object)
		{
			return object && object.constructor === Array;
		},
		isFunction: function (object)
		{
			return typeof object === 'function';
		},
		isString: function (object)
		{
			return typeof object === 'string';
		},
		isNumber: function (object)
		{
			return typeof object === 'number' || (object.length > 0 && !(/[^0-9.,eE]/gi.test(object)));
		},
		isInteger: function (object)
		{
			return this.isNumber(object) && Math.floor(object) === object;
		},
		isFloat: function (object)
		{
			return this.isNumber(object) && Math.floor(object) !== object;
		},
		isUndefined: function (object)
		{
			return typeof object == 'undefined';
		},
		isNull: function (object)
		{
			return object === null;
		},
		isBoolean: function (object)
		{
			return typeof object == 'boolean';
		},
		isDate: function (object)
		{
			return object instanceof Date;
		},
		isDateRange: function (object)
		{
			if (this.isArray(object) && object.length == 2)
			{
				if (this.isDate(object[0]) && this.isDate(object[1]))
				{
					return true;
				}
			}
			
			return false;
		},
		isValue: function (object)
		{
			return !(this.isNull(object) || this.isUndefined(object) || object === '');
		},
		isEmpty: function (object)
		{
			return !this.isValue(object);
		}, 
		hasOwnProperty: function (value, property)
		{
			if (Object.prototype.hasOwnProperty)
			{
				return value.hasOwnProperty(property);
			}
			else
			{
				return (!this.isUndefined(value[property]) && value.constructor.prototype[property] !== value[property]);
			}
		}
	};	
}

if (!CAPABLE.Element)
{
	CAPABLE.Element =
	{
		get: function (element)
		{
			return !CAPABLE.Type.isString(element) ? element : document.getElementById ? document.getElementById(element) : document.all ? document.all(element) : false;
		},
		create: function (tag)
		{
			return document.createElement(tag);
		},
		createTextNode: function (text)
		{
			return document.createTextNode(text);
		},
		remove: function (element)
		{
			element = this.get(element);
			return element.parentNode.removeChild(element);
		},
		
		setInner: function (element, data)
		{
			element = this.get(element);
			element.innerHTML = data;
		},
		prependInner: function (element, data)
		{
			element = this.get(element);
			element.innerHTML = data + element.innerHTML;
		},
		appendInner: function (element, data)
		{
			element = this.get(element);
			element.innerHTML += data;
		},
		getInner: function (element)
		{
			element = this.get(element);
			return element.innerHTML;
		},
		setOuter: function (element, data)
		{
			element = this.get(element);
			element.outerHTML = data;
		},
		getOuter: function (element)
		{
			element = this.get(element);
			return element.outerHTML;
		}
	};
}

if (!CAPABLE.Event)
{
	CAPABLE.Event =
	{
		addEventListener: function (element, eventType, action)
		{
			element = CAPABLE.Element.get(element);
			if (element.addEventListener)
			{
				element.addEventListener(eventType, action, false);
			}
			else if (element.attachEvent)
			{
				element.attachEvent('on' + eventType, action);
			}
		},
		removeEventListener: function (element, eventType, action)
		{
			element = CAPABLE.Element.get(element);
			if (element.removeEventListener)
			{
				element.removeEventListener(eventType, action, false);
			}
			else if (element.detachEvent)
			{
				element.detachEvent('on' + eventType, action);
			}
			else
			{
				this.legacyAttachEvent(element, eventType, action);
				element['on' + eventType] = function ()
				{
					CAPABLE.Event.legacyFireEvent(element, eventType);	
				};
			}
		},
		legacyAttachEvent: function (element, eventType, action)
		{
			element = CAPABLE.Element.get(element);
			if (!element.legacyEvents)
			{
				element.legacyEvents = {};
			}
			
			if (!element.legacyEvents[eventType])
			{
				element.legacyEvents[eventType] = [];
			}
				
			element.legacyEvents[eventType].push(action);
		},
		legacyFireEvent: function (element, eventType)
		{
			element = CAPABLE.Element.get(element);
			if (!element || !element.legacyEvents || !element.legacyEvents[eventType])
			{
				return;
			}
			else
			{
				var tempLegacyEvents = element.legacyEvents[eventType];
				for (var i = 0, iEnd = tempLegacyEvents.length; i < iEnd; ++i)
				{
					tempLegacyEvents[i]();
				}
			}
		}
	};	
}

if (!CAPABLE.Validation)
{
	CAPABLE.Validation =
	{
		replacePattern: function (value, pattern, patternModifiers, replacement)
		{			
			var tempPattern = new RegExp(pattern, patternModifiers);			
			var tempValue, newValue;
			tempValue = newValue = value;
			
			var matched = true;			
			var replaced = false;
			
			while (matched)
			{
				newValue = tempValue.replace(tempPattern, replacement);
				
				if (newValue === tempValue)
				{
					matched = false;
				}
				else
				{
					matched = true;
					replaced = true;
					tempValue = newValue;
				}
			}
			
			return {replaced: replaced, value: newValue};
		},
		matchPattern: function (value, pattern, patternModifiers)
		{
			var tempPattern = new RegExp(pattern, patternModifiers);
			
			return (value.match(tempPattern) !== null);
		},
		replaceVariables: function (value, variables)
		{
			for (var j = 0, jEnd = variables.length; j < jEnd; ++j)
			{
				value = this.replacePattern(value, '\\\{\\[\\{' + variables[j][0] + '\\}\\]\\}', 'gi', variables[j][1]).value;
			}
			
			return value;
		},
		
		checkedOptions: function (checkListOptions)
		{
			var checkListOptionTotal = checkListOptions.length;
			var count = 0;
			var checkedOptions = [];			
			
			for (var i = 0; i < checkListOptionTotal; ++i)
			{
				if (checkListOptions[i].checked)
				{
					checkedOptions.push(checkListOptions[i]);
					++count;
				}
			}
			
			return checkedOptions;
		},
		selectedOptions: function (selectBox)
		{
			var selectBoxOptionTotal = selectBox.options.length;
			var selectBoxOptions = selectBox.options;
			var selected = 0;
			var selectedOptions = [];
			
			for (var i = 0; i < selectBoxOptionTotal; ++i)
			{
				if (selectBoxOptions[i].selected)
				{
					selectedOptions.push([i, selectBoxOptions[i]]);
					++selected;
				}
			}
			
			return selectedOptions;
		}
	};
}


if (!CAPABLE.Tools)
{
	CAPABLE.Tools =
	{
		// Returns a string without any leading or trailing whitespace
		// If the input is not a string it is returned untouched
		trim: function (value)
		{
			try
			{
				return value.replace(/^\s+|\s+$/g, '');
			}
			catch (e	)
			{
				return value;
			}
		},
		// Use this when you don't want the expression to access or interfere with any local variables
		eval: function (value)
		{
			return eval(value);	
		},
		getElementsByTagNames: function (tagList, element)
		{
			if (!element)
			{
				element = document;
			}
			
			var tagNames = tagList.split(',');
			var resultArray = [];
			
			for (var i = 0, iEnd = tagNames.length; i < iEnd; ++i)
			{
				var tags = element.getElementsByTagName(this.trim(tagNames[i]));
				
				for (var j = 0, jEnd = tags.length; j < jEnd; ++j)
				{
					resultArray.push(tags[j]);
				}
			}
			
			var testNode = resultArray[0];
			if (!testNode)
			{
				return [];
			}
			if (testNode.sourceIndex)
			{
				resultArray.sort(function (a,b) { return a.sourceIndex - b.sourceIndex; });
			}
			else if (testNode.compareDocumentPosition)
			{
				resultArray.sort(function (a,b) { return 3 - (a.compareDocumentPosition(b) & 6); });
			}
			
			return resultArray;
		},
		getElementsByClass: function (className, node, tag)
		{
			var result = [];
			
			if (!node)
			{
				node = document;
			}
			
			if (!tag)
			{
				tag = '*';
			}
			
			var elements = node.getElementsByTagName(tag);
			
			for (var i = 0, iEnd = elements.length; i < iEnd; ++i)
			{
				if (CAPABLE.Element.hasClassName(elements[i], className))
				{
					result.push(elements[i]);
				}
			}
			
			return result;
		},
		createUniqueID: function ()
		{
			return (Math.round((Math.random() * 1000)) + '_' + (new Date()).getTime());
		},
		delay: function (callBack, delay)
		{
			if (!delay)
			{
				delay = 1000;
			}
			
			setTimeout(callBack, delay);
		}
	};
}

if (!CAPABLE.Ajax)
{
	CAPABLE.Ajax =
	{
		createXMLHttpRequest: function ()
		{
			var request = null;
				
			if (window.XMLHttpRequest)
			{
				request = new XMLHttpRequest();	
				if (CAPABLE.debug)
				{
					alert('ERROR > CAPABLE.AJAX.createXMLHttpRequest: Used XMLHttpRequest object: "XMLHttpRequest"');
				}
				if (request.overrideMimeType)
				{
					request.overrideMimeType('text/xml');	
				}
			}
			else if (window.ActiveXObject)
			{
				var msProgIDs =
				[
					'MSXML3.XMLHTTP',
					'MSXML2.XMLHTTP.6.0',
					'MSXML2.XMLHTTP.5.0',
					'MSXML2.XMLHTTP.4.0',
					'MSXML2.XMLHTTP.3.0',
					'MSXML2.XMLHTTP',
					'Microsoft.XMLHTTP'
				];
				
				while (!request && msProgIDs.length)
				{
					try
					{
						request = new ActiveXObject(msProgIDs[0]);
						if (CAPABLE.debug)
						{
							alert('ERROR > CAPABLE.AJAX.createXMLHttpRequest: Used XMLHttpRequest object: "' + msProgIDs[0] + '"');
						}
					}
					catch (e	)
					{
						request = null;
					}
					
					if (!request)
					{
						msProgIDs.splice(0, 1);	
					}
				}
			}
			
			if (!request)
			{
				if (CAPABLE.debug)
				{
					alert('ERROR > CAPABLE.AJAX.createXMLHttpRequest: Unable to create an XMLHttpRequest object!');
				}
			}
			
			return request;
		},
		execute: function (uri, data, target, method, delivery)
		{
			var request = this.createXMLHttpRequest();
			if (!request)
			{
				return;
			}
			request.onreadystatechange = function	()
			{
				
				if ((request.readyState === 4 || request.readyState === 'complete') === false)
				{
					return;
				}
				if (request.status >= 200 || request.status <= 299)
				{
					if (delivery === 'text' || delivery === 'JSON')
					{
						eval(target + '(request.responseText)');	
					}
					else if (delivery === 'XML')
					{
						eval(target + '(request.responseXML)');
					}
					else if (delivery === 'element')
					{
						CAPABLE.Element.setInner(target, request.responseText);
					}
					else if (delivery === 'nothing')
					{
						// ...
					}
					if (CAPABLE.debug)
					{
						alert('ERROR > CAPABLE.AJAX.execute: Completed');
					}
				}
				else
				{
					if (CAPABLE.debug)
					{
						alert('ERROR > CAPABLE.AJAX.execute: While loading "' + uri + '" (HTTP status code: ' +  request.status + ')');	
					}
				}
				delete request;
			};
			
			if (data !== '')
			{
				data += '&';
			}
			
			data += 'antiCache=' + CAPABLE.Tools.createUniqueID();	
			
			try
			{
				if (method === 'get')
				{
					request.open('GET', uri + '?' + data, true);
					this.setHeaders(request, data.length);
					request.send(null);
				}
				else
				{
					request.open('POST', uri, true);
					this.setHeaders(request, data.length);
					request.send(data);
				}
			}
			catch (exception)
			{
				if (CAPABLE.debug)
				{
					alert('ERROR > CAPABLE.AJAX.execute: While loading "' + uri + '" (' +  exception.message + ')');
				}
			}
		},
		setHeaders: function (request, dataLength)
		{
			request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
			request.setRequestHeader('Content-length', dataLength);
			request.setRequestHeader('Accept-Charset', 'utf-8');
			request.setRequestHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
			request.setRequestHeader('Connection', 'close');
		},
		getTo: function (uri, data)
		{
			this.execute(uri, data, 'void', 'get', 'nothing');
		},
		postTo: function (uri, data)
		{
			this.execute(uri, data, 'void', 'post', 'nothing');
		},
		getToElement: function (uri, data, target)
		{
			this.execute(uri, data, target, 'get', 'element');
		},
		postToElement: function (uri, data, target)
		{
			this.execute(uri, data, target, 'post', 'element');
		},
		getTextToFunction: function (uri, data, target)
		{
			this.execute(uri, data, target, 'get', 'text');
		},
		postTextToFunction: function (uri, data, target)
		{
			this.execute(uri, data, target, 'post', 'text');
		},
		getXMLToFunction: function (uri, data, target)
		{
			this.execute(uri, data, target, 'get', 'XML');
		},
		postXMLToFunction: function (uri, data, target)
		{
			this.execute(uri, data, target, 'post', 'XML');
		},
		getJSONToFunction: function (uri, data, target)
		{
			this.execute(uri, data, target, 'get', 'JSON');
		},
		postJSONToFunction: function (uri, data, target)
		{
			this.execute(uri, data, target, 'post', 'JSON');
		}
	};	
}
