﻿var Common = {
	Testing : false,  // windows open normally when true
	ShowErrors: false, // js alerts on exceptions when true
	//########################################################################
	//                     W I N D O W
	//########################################################################
	 Window : {
		// window.open(url, windowName, directories=0|1,status=0|1,toolbar=0|1,location=0|1,menubar=0|1,resizable=0|1,scrollbars=0|1,height=pixels,width=pixels);
		// opens a window using the passed attribute string
		Open : function(url, name, attributes){
			if (attributes != "")
				return window.open(url, name, attributes);
			else
				return window.open(url, name);
		},
		// opens a DEFAULT SIZED window with all attributes enabled (less directories)
		OpenNormal : function(url, name){
			return Common.Window.OpenCustom(url, name, 0,1,1,1,1,1,1,1);
		},
		// opens a window with all attributes enabled (less directories)
		OpenSizedNormal : function(url, name, height, width, top, left){
			var handle = Common.Window.OpenCustom(url, name, 0,1,1,1,1,1,1,1, height, width);
			if (handle != null && left != null && top != null)
				handle.moveTo(left, top);
			return handle;
		},
		// opens a window with the passed attributes specified
		OpenCustom : function(url, name, dependent, directories, location, menubar, resizable, scrollbars, status, toolbar, height, width){
			var attributes =  'dependent=' + dependent +
							', directories=' + directories +
							', location=' + location +
							', menubar=' + menubar +
							', resizable=' + resizable +
							', scrollbars=' + scrollbars +
							', status=' + status +
							', toolbar=' + toolbar;
			if (height != null)
				attributes += ', height=' + height;
			if (width != null)
				attributes += ', width=' + width;

			return window.open(url, name, attributes);
		},
		// opens a resizeable window
		OpenBorderless : function(url, name, height, width , top, left){
			var handle = Common.Window.OpenCustom(url, name, 0,0,0,0,1,0,0,0, height, width);
			if (handle != null && left != null && top != null)
				handle.moveTo(left, top);
			return handle;
		},
		// opens a resizeable window with scrollbars
		OpenBorderlessScrolling : function(url, name, height, width, top, left){
			var handle = Common.Window.OpenCustom(url, name, 0,0,0,0,1,1,0,0, height, width);
			if (handle != null && left != null && top != null)
				handle.moveTo(left, top);
			return handle;
		},
		// returns a string of various window setting information
		GetInfo : function(){
			var s = 'HEIGHT:';
			if (window.innerHeight != null) s += '\n window.innerHeight = ' + window.innerHeight;
			if (window.outerHeight != null) s += '\n window.outerHeight = ' + window.outerHeight;
			if (document.body.clientHeight != null) s += '\n document.body.clientHeight = ' + document.body.clientHeight;
			if (document.body.offsetHeight != null) s += '\n document.body.offsetHeight = ' + document.body.offsetHeight;
			if (document.documentElement.clientHeight != null) s += '\n document.documentElement.clientHeight = ' + document.documentElement.clientHeight;
			if (document.documentElement.offsetHeight != null) s += '\n document.documentElement.offsetHeight = ' + document.documentElement.offsetHeight;
			s += '\n GetClientHeight() = ' + Common.Window.GetClientHeight();
			if (window.screen.availHeight) s += '\n window.screen.availHeight = ' + window.screen.availHeight;
			if (window.screen.height) s += '\n window.screen.height = ' + window.screen.height;

			s += '\n\nWIDTH:';
			if (window.innerWidth != null) s += '\n window.innerWidth = ' + window.innerWidth;
			if (window.outerWidth != null) s += '\n window.outerWidth = ' + window.outerWidth;
			if (document.body.clientWidth != null) s += '\n document.body.clientWidth = ' + document.body.clientWidth;
			if (document.body.offsetWidth != null) s += '\n document.body.offsetWidth = ' + document.body.offsetWidth;
			if (document.documentElement.clientWidth != null) s += '\n document.documentElement.clientWidth = ' + document.documentElement.clientWidth;
			if (document.documentElement.offsetWidth != null) s += '\n document.documentElement.offsetWidth = ' + document.documentElement.offsetWidth;
			s += '\n GetClientWidth() = ' + Common.Window.GetClientWidth();
			if (window.screen.availWidth) s += '\n window.screen.availWidth = ' + window.screen.availWidth;
			if (window.screen.width) s += '\n window.screen.width = ' + window.screen.width;

			s += '\n\nTOP:';
			if (window.screenY != null) s += '\n window.screenY = ' + window.screenY;
			if (window.screenTop != null) s += '\n window.screenTop = ' + window.screenTop;
			s += '\n GetClientTop() = ' + Common.Window.GetClientTop();
			if (window.screen.top) s += '\n window.screen.top = ' + window.screen.top;
			if (window.screen.availTop) s += '\n window.screen.availTop = ' + window.screen.availTop;

			s += '\n\nLEFT:';
			if (window.screenX != null) s += '\n window.screenX = ' + window.screenX;
			if (window.screenLeft != null) s += '\n window.screenLeft = ' + window.screenLeft;
			s += '\n GetClientLeft() = ' + Common.Window.GetClientLeft();
			if (window.screen.left) s += '\n window.screen.left = ' + window.screen.left;
			if (window.screen.availLeft) s += '\n window.screen.availLeft = ' + window.screen.availLeft;

			return s;
		},
		// returns the window's top position plus the passed offset
		GetClientTop : function(offset){
			var top = 0;
			if (window.screenY)
				top = window.screenY;
			else if (window.screenTop)
				top = window.screenTop;
			if (offset != null && offset != Number.NaN)
				top = top + offset;
			return top;
		},
		// returns the window's left position plus the passed offset
		GetClientLeft : function(offset){
			var left = 0;
			if (window.screenX)
				left = window.screenX;
			else if (window.screenLeft)
				left = window.screenLeft;
			if (offset != null && offset != Number.NaN)
				left = left + offset;
			return left;
		},
		// returns the window width plus the passed offset
		GetClientWidth : function(offset){
			var width = 0;
			// for FF, inner width includes the dynamic scroll bars
			if (window.innerWidth)
				width = window.innerWidth;
			// for IE, scroll bars become disabled, so it's a part of the offset
			else if (document.documentElement.clientWidth)
				width = document.documentElement.clientWidth;
			if (offset != null && offset != Number.NaN)
				width = width + offset;
			return width;
		},
		// returns the window height plus the passed offset
		GetClientHeight : function(offset){
			var height = 0;
			// for FF, inner height includes the dynamic scroll bars
			if (window.innerHeight)
				height = window.innerHeight;
			// for IE, scroll bars become disabled, so it's a part of the offset
			else if (document.documentElement.clientHeight)
				height = document.documentElement.clientHeight;
			if (offset != null && offset != Number.NaN)
				height = height + offset;
			return height;
		}
	},

	//########################################################################
	//                          T O G G L E
	//########################################################################
	Toggle : {
		// toggles the display of the passed element between none and block
		DisplayBlock : function(object){
			if (object == null) return;
			object.style.display = (object.style.display == 'block' || object.style.display == '') ? 'none' : 'block';
			return (object.style.display == 'block');
		},
		// toggles the display of the passed element between none and inline
		DisplayInline : function(object){
			if (object == null) return;
			object.style.display = (object.style.display == 'inline' || object.style.display == '') ? 'none' : 'inline';
			return (object.style.display == 'inline');
		},
		// toggles the passed class of the passed element
		Class : function(element, classname){
			if (!Common.Class.Contains(element, classname))
				Common.Class.Add(element, classname);
			else
				Common.Class.Remove(element, classname);
		},
		// toggles the visibility of the passed element
		Visibility : function(element){
			if (element == null) return;
			element.style.visibility = (element.style.visibility == '' || element.style.visibility == 'visible') ? 'hidden' : 'visible';
		},
		// toggles the disabled attribute of the passed element
		Disabled : function(object){
			if (object == null) return;
			object.disabled = (object.disabled) ? '' : 'disabled';
		}
	},

	//########################################################################
	//                        D O M
	// some DOM nodes are empty
	// these get valid nodes
	//########################################################################
	DOM : {
		// returns the first valid child node of the passed element
		GetValidChildNode : function(sender){
			try{
			if (!sender.hasChildNodes()) return null;
			var node = sender.childNodes[0];
			while ((node != null) && (node.nodeType != 1)){
				node = node.nextSibling;
			}
			return node;
			}catch(err){Common.Except(err, 'Common.DOM.GetValidChildNode');}
		},
		// returns the valid previous sibling of the passed element
		GetValidPreviousSibling : function(sender){
			try{
			var node = sender.previousSibling;
			while ((node != null) && (node.nodeType != 1)){
				node = node.previousSibling;
			}
			return node;
			}catch(err){Common.Except(err, 'Common.DOM.GetValidPreviousSibling');}
		},
		// returns the valid next sibling of the passed element
		GetValidNextSibling : function(sender){
			try{
			var node = sender.nextSibling;
			while ((node != null) && (node.nodeType != 1)){
				node = node.nextSibling;
			}
			return node;
			}catch(err){Common.Except(err, 'Common.DOM.GetValidNextSibling');}
		}
	},

	//########################################################################
	//                        S E L E C T
	//########################################################################
	Select : {
		// returns the value of the selected index
		SelectedValue : function(element){
			var result = '';
			try{
				result = element.options[element.selectedIndex].value;
			}catch(err){Common.Except(err, 'Common.Select.SelectedValue');}
			return result;
		},
		// returns the text of the selected index
		SelectedText : function(element){
			var result = '';
			try{
				result = element.options[element.selectedIndex].text;
			}catch(err){Common.Except(err, 'Common.Select.SelectedText');}
			return result;
		},
		// returns an array of option objects
		SelectedOptionsAsArray : function(element){
			var result = [];
			try{
				for (var i = 0; i < element.options.length; i++){
					var option = element.options[i];
					if (option.selected)
						result.push(option);
				}
			}catch(err){Common.Except(err, 'Common.Select.SelectedOptionsAsArray');}
			return result;
		},
		// returns an array of selected options.value
		SelectedValuesAsArray : function(element){
			var result = [];
			try{
				for (var i = 0; i < element.options.length; i++){
					var option = element.options[i];
					if (option.selected)
						result.push(option.value);
				}
			}catch(err){Common.Except(err, 'Common.Select.SelectedValuesAsArray');}
			return result;
		},
		// populates a select element with an array of text (no values are added)
		PopulateWithArray : function(element, array){
			Common.Select.Options.Clear(element);
			if (array.length == 0) return;
			for (var i = 0; i < array.length; i++){
				Common.Select.Options.Add(element, array[i], null, i);
			}
		},

		//########################################################################
		//                      S E L E C T . O P T I O N S
		//########################################################################
		Options : {
			// adds an option with the passed attributes to the passed select element at the passed index
			// will add to the end of the option list if index is not specified
			Add : function(element, text, value, index){
				if (element == null) return;

				if (index == null || index < -1 || index >= element.options.length)
					index = element.options.length;

				if (typeof index != 'number')
					index = Common.ParseInt(index);

				var opt = document.createElement('option');
				if (text != null && text != '')
					opt.text = text;
				if (value != null && text != '')
					opt.value = value;
				element.options.add(opt, index);
			},
			// adds an option element to the passed select element at the passed index
			// will add to the end of the option list if index is not specified
			AddOption : function(element, option, index){
				if (!element || !option) return;
				if (index == null || index < -1 || index >= element.options.length)
					index = element.options.length;

				if (typeof index != 'number')
					index = Common.ParseInt(index);
				// IE sucks and forgets that option is an option
				//element.options.add(option, index);
				// so, we have to create an option and add it
				Common.Select.Options.Add(element, option.text, option.value, index);
			},
			// adds option elements contained in an array to the passed select element starting at the passed index
			AddOptionArray : function(element, options, index){
				if (!element || !options) return;
				for (var i = 0; i < options.length; i++)
					Common.Select.Options.AddOption(element, options[i], index);
			},
			RemoveOptionArray : function(element, options){
				if (!element || !options) return;
				for (var i = 0; i < options.length; i ++)
					Common.Select.Options.RemoveOption(element, options[i]);
			},
			RemoveOption : function(element, option){
				if (!element || !option) return;
				for (var i = 0; i < element.options.length; i++){
					var candidate = element.options[i]
					if (candidate.text == option.text && candidate.value == option.value)
						element.remove(i);
				}
			},
			// removes the option with the specified index
			// if question is populated, prompts the user for confirmation
			Remove : function(element, index, question){
				if (element == null) return;
				if (element.length == -1) return;

				if (index == null)
					index = element.selectedIndex;
				if (index == -1) return;
				if (question != null && question != ''){
					//if (confirm(question + ' ' + element.options[index].text + '?')){
					if (confirm(Common.Format(question, element.options[index].text))){
						element.remove(index);
					}
				}
				else{
					element.remove(index);
				}
			},
			// removes all options from a select element
			Clear : function(element){
				while (element.options.length > 0)
					Common.Select.Options.Remove(element, 0);
			},
			// returns an array of options.value
			ValuesAsArray : function(element, sort){
				var result = [];
				if (element.options.length > 0){
					for (var i = 0; i < element.options.length; i++)
						result.push(element.options[i].value);
					if (sort)
						result.sort();
				}
				return result;
			},
			// returns an array of options.text
			TextAsArray : function(element, sort){
				var result = [];
				if (element.options.length > 0){
					for (var i = 0; i < element.options.length; i++)
						result.push(element.options[i].text);
					if (sort)
						result.sort();
				}
				return result;
			}
		}
	},

	//########################################################################
	//                        C L A S S
	//########################################################################
	Class : {
		// returns an array of elements with a given class and tagname
		Find : function(classname, tagname){
			var result = [];
			var elements = document.getElementsByTagName(tagname);
			for (var i = 0; i < elements.length; i++){
				var element = elements[i];
				if (Common.Class.Contains(element, classname))
					result.push(element);
			}
			return result;
		},
		// adds or removes a class to an element
		Set : function(element, classname, enable){
			if (!element) return;
			if (enable)
				Common.Class.Add(element, classname);
			else
				Common.Class.Remove(element, classname);
		},
		// returns an array of an element's class names
		AsArray : function(element){
			var result = [];
			if (element){
				result = element.className.split(' ');
			}
			return result;
		},
		// replaces one class name with another
		Replace : function(element, fromclass, toclass){
			if (element){
				var classnames = Common.Class.AsArray(element);
				if (classnames.indexOf(fromclass) > -1)
					Common.RemoveArrayItem(classnames, fromclass);
				if (classnames.indexOf(toclass) == -1)
					classnames.push(toclass);
				element.className = classnames.join(' ');
			}
		},
		// returns true if the element has the class name
		Contains : function(element, classname){
			return (Common.Class.AsArray(element).indexOf(classname) > -1);
			//return (element.className.indexOf(classname) > -1);
		},
		// adds a class name to an element
		Add : function(element, classname){
			if (element){
				var classnames = Common.Class.AsArray(element);
				if (classnames.indexOf(classname) == -1)
					classnames.push(classname);
				element.className = classnames.join(' ');
			}
		},
		// removes a class name to an element
		Remove : function(element, classname){
			if (element){
				var classnames = Common.Class.AsArray(element);
				if (classnames.indexOf(classname) > -1)
					Common.RemoveArrayItem(classnames, classname);
				element.className = classnames.join(' ');
			}
		}
	},
	
	//########################################################################
	//                       K E Y
	// all methods should be assigned as an onkeypress event handler
	//########################################################################
	Key : {
		// returns the key code of the key pressed
		GetCode : function(e){
			var code;
			if (window.event)
				code = window.event.keyCode;
			else if (e && e.which)
				code = e.which;
			else if (e && e.keyCode)
				code = e.keyCode;
			return code;
		},
		// returns true if the shift key was held during a key press
		UsingShift : function(e){
			var result = false;
			if (window.event)
				result = window.event.shiftKey;
			else if (e && e.shiftKey)
				result = e.shiftKey;
			return result;
		},
		// returns true if the ctrl key was held during a key press
		UsingCtrl : function(e){
			var result = false;
			if (window.event)
				result = window.event.ctrlKey;
			else if (e && e.ctrlKey)
				result = e.ctrlKey;
			return result;
		},
		// returns true if the alt key was held during a key press
		UsingAlt : function(e){
			var result = false;
			if (window.event)
				result = window.event.altKey;
			else if (e && e.altKey)
				result = e.altKey;
			return result;
		}
	},
	//########################################################################

	// assigns events to passed element to prevent the selection of text
	DisableTextSelection : function(elementid){
		var obj = document.getElementById(elementid);
		if (obj == null) return;
		obj.onselectstart = function(){return false;}
		obj.onmousedown = function(){return false;}
	},
	// returns an integer representation of the passed string
	ParseInt : function(string){
		var number = parseInt(string);
		if (number == Number.NaN)
			number = 0;
		return number;
	},
	// removes the first instance of the passed item from the passed array
	RemoveArrayItem : function(array, item){
		var index = array.indexOf(item);
		if (index > -1)
			array.splice(index, 1);
		return index;
	},
	// adds an "alt" class to all even rows in a table's tbody section (required)
	StripeTable : function(element){
		if (element == null) return;
		var tbodies = element.getElementsByTagName('tbody');
		for (var i = 0; i < tbodies.length; i++){
			var trs = tbodies[i].getElementsByTagName('tr');
			for (var j = 0; j < trs.length; j++){
				if (j % 2 == 1)
					Common.Class.Set(trs[j], 'alt', true);
			}
		}
	},
	// applies Common.StripeTable() to all tables with a "data" class
	StripeDataTables : function (){
		var tables = document.getElementsByTagName('table');
		for (var i = 0; i < tables.length; i++){
			if (!Common.Class.Contains(tables[i], 'data')) continue;
			Common.StripeTable(tables[i]);
		}
	},
	// returns true if json.js has not been included in the page
	JSONMethodsUnavailable : function(){
		return (!Object.toJSONString);
	},
	// Returns the class name of the argument or undefined if it's not a valid JavaScript object.
	GetObjectClass : function(obj){
		if (obj && obj.constructor && obj.constructor.toString){
			var arr = obj.constructor.toString().match(/function\s*(\w+)/);
			if (arr && arr.length == 2)
				return arr[1];
		}
		return undefined;
	},
	// Analog of String.Format
	Format : function(str){
		if (arguments.length == 0) return '';
		var result = str;
		for (var i = 0; i < arguments.length; i++){
			var re = new RegExp('\\{' + (i) + '\\}','gm');
			result = result.replace(re, arguments[i+1]);
		}
		return result;
	},
	// Sets an element to be enabled or disabled
	Disable : function(element, disable){
		if (!element) return;
		if (disable)
			element.disabled = 'disabled';
		else
			element.disabled = '';
	},
	// alerts the user with an error description
	Except : function(err, caller){
		if (Common.ShowErrors)
			alert('Error: ' + err.description + '\nCalled By: ' + caller);
	}
}
// Adds indexOf property to arrays for pathetic browsers that haven't fully implemented JavaScript 1.5 yet
// from http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf#Compatibility
if (!Array.prototype.indexOf){
  Array.prototype.indexOf = function(elt /*, from*/){
    var len = this.length;
    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from) : Math.floor(from);
    if (from < 0)
      from += len;
    for (; from < len; from++){
      if (from in this && this[from] === elt)
        return from;
    }
    return -1;
  };
}