// NEED TO PHASE NCLAYOUT OUT
var ncLayout = { // Add to ap.ui
	activityIndicator: null,
	messageDiv: null,
	errorDiv: null,
	section: null,
	sideTabs: null,
	init: function()
	{
	},
	addSection: function(name, id)
	{
		ap.ui.sections.add(name, '#' + id);
	},
	addSideTab: function(name, id, disabled, callback)
	{
		if (id.length > 0) {
			id = '#' + id;
		}
		if (disabled !== false && disabled !== true) {
			disabled = false;
		}
		ap.ui.sideTabs.add(name, {
			selector: id,
			disabled: disabled,
			callback: callback
		});
	},
	deleteSideTab: function(name)
	{
		ap.ui.sideTabs.remove(name);
	},
	selectSideTab: function(name)
	{
		ap.ui.sideTabs.select(name);
	},
	unselectAllSideTags: function()
	{
		ap.ui.sideTabs.unselectAll();
	},
	enableSideTab: function(name, callback)
	{
		ap.ui.sideTabs.enable(name, callback);
	},
	disableSideTab: function(name)
	{
		ap.ui.sideTabs.disable(name);
	},
	disableAllTabs: function()
	{
		ap.ui.sideTabs.disableAll();
	},
	showActivityIndicator: function()
	{
		ap.ui.showActivityIndicator();
	},
	hideActivityIndicator: function()
	{
		ap.ui.hideActivityIndicator();
	},
	showMessage: function(message)
	{
		ap.ui.showMessage(message);
	},
	showError: function(message)
	{
		ap.ui.showError(message);
	},
	hideMessage: function()
	{
		ap.ui.hideMessage();
	},
	hideError: function()
	{
		ap.ui.hideError();
	},
	hideAll: function(exception)
	{
		return ap.ui.hideAll();
	},
	hideSection: function (section)
	{
		return ap.ui.sections.hide(section);
	},
	showSection: function(section, exceptions)
	{
		return ap.ui.sections.show(section, exceptions);
	},
	disableButtons: function(buttons)
	{
		ap.ui.disableButtons(buttons);
	},
	enableButtons: function(buttons)
	{
		ap.ui.enableButtons(buttons);
	},
	setupHideRightSidebar: function()
	{
	},
	deactivateTableActions: function()
	{
		ap.ui.table.deactivateTableActions();
	},
	activateTableActions: function()
	{
		ap.ui.table.activateTableActions();
	}
};

/**
*  Begin to convert all javascript files to this instead of the code above.
* Once all code is using this new object go back and change references to 'ncObj'
* to 'nc'
*/

(function($){
	// Sets both the keyup and change event handler function for the matched elements
	$.fn.ncTextChange = function(keyUpFn, changeFn) {
		changeFn = changeFn || keyUpFn;
		if (keyUpFn instanceof Function && changeFn instanceof Function) {
			$(this).keyup(keyUpFn).change(changeFn);
		}
		return this;
	};
	// Empty a select box. If length is passed that many options will be left
	$.fn.emptySelect = function(length) {
		length = length || 0;
		return this.each(function(){
			if (this.tagName == 'SELECT') this.options.length = length;
		});
	};
	// Empty and then fill a select box. If length is passed that many options will be left before the new ones are added.
	$.fn.loadSelect = function(optionsDataArray, length) {
		return this.emptySelect(length).each(function(){
			if (this.tagName == 'SELECT') {
				var select = this;
				$.each(optionsDataArray, function (index, data) {
					var option = new Option(data.caption, data.value);
					if ($.browser.msie) {
						select.add(option);
					} else {
						select.add(option, null);
					}
				});
			}
		});
	};
	$.fn.addSelectOption = function(value, caption) {
		return this.each(function(){
			var option = new Option(caption, value);
			if ($.browser.msie) {
				this.add(option);
			} else {
				this.add(option, null);
			}
		});
	};
	$(document).ready(function(){
		ap.init();
	});

	var ap, nc;

	nc = window.nc = ap = window.ap = {
		/**
		* Holds the height and width of the window
		*/
		window: {},

		init: function()
		{
			this.ui.init();
			this.ui.admin.init();
			this.ui.sections.init();
			this.ui.sideTabs.init();
			ncLayout.init();
			this.getWindowSize();
			this.module.init();
			if ($.validator) {
				$.validator.messages.required = 'Required';
			}
			this.myModulesNav.init();
			this.myAccount.init();
			this.sites.init();
		},
		focus: function(el)
		{
			$(el).focus();
		},
		loadFCKEditor: function(instanceName, width, height, toolbarSet, value)
		{
			if (height == undefined) {
				height = '500';
			}
			if (toolbarSet == undefined) {
				if (fckEditorToolBar != undefined) {
					toolbarSet = fckEditorToolBar;
				} else {
					toolbarSet = 'ncDefault';
				}
			}
			var editor = new FCKeditor(instanceName, width, height, toolbarSet, value);
			editor.BasePath = ncJsBasePath + 'fckeditor/' ;
			editor.DisplayErrors = false;
			editor.Config['CustomConfigurationsPath'] = ncJsBasePath + 'fckeditor/nc-fckconfig.js';
			return editor;
		},
		saveUserConfig: function(group, configName, configValue)
		{
			var data = 'group=' + group + '&name=' + configName + '&value=' + configValue;
			$.post(ncAdminBaseUrl + 'myaccount/saveConfig', data);
		},
		/**
		* Sets links with a rel attribute of "external" to open in a new window.
		* Adapted from Sitepoint.com (http://www.sitepoint.com/article/standards-compliant-world)
		*/
		externalLinks: function() {
//			$('a[rel=external]').attr('target', '_blank').after(' <img src="/nc/interface/admin/default/images/external.png" alt="External link" height="10" width="10">');
			$('a').filter(function() {
				return (this.href && this.hostname != undefined && this.hostname.split(':')[0] != location.hostname) || (this.rel == 'external');
			})
			.attr('target', '_blank')
			.filter(function() {
				return this.rev != 'externalSkip';
			})
			.after(' <img src="/nc/interface/admin/default/images/external.png" alt="External link" height="10" width="10">');
		},
		/**
		* Helper function to get the correct window height and width
		*/
		getWindowSize: function() {
			this.window = {
				height: $(window).height(),
				width: $(window).width()
			};
		},
		/**
		* Debuging helper function.
		* Will send a message to the console (Firebug) if it exists. If not,
		* Then it'll do a simple alert box.
		*/
		debug: function() {
			if (window.console && window.console.log && $.browser.safari === false) {
				window.console.log('[debug] ' + Array.prototype.join.call(arguments,''));
			} else {
				alert('[debug] ' + Array.prototype.join.call(arguments,''));
			}
		},
		/**
		* DEPRECATED
		* USE ap.ui.block()
		*/
		blockUI: function(text)
		{
			ap.ui.block(text);
		},
		/**
		* DEPRECATED
		* USE ap.ui.uploadBlock()
		*/
		uploadBlockUI: function()
		{
			ap.ui.uploadBlock();
		}
	};



	// User Interface methods
	ap.ui = {
		activityIndicator: null,
		messageDiv: null,
		errorDiv: null,
		init: function()
		{
			//Set the default container for messages and error messages
			this.activityIndicator = $('#activityIndicator');
			this.errorDiv = $('#errorMessages');
			this.messageDiv = $('#messages');
			this.setupHideRightSidebar();
			this.setupFloatingButtons();
		},
		setupHideRightSidebar: function()
		{
			$('a.showHideRSidebar').click(function(){
				var self = $(this);
				if (self.hasClass('showSidebar')) {
					//The sidebar is currently being hidden and needs to be shown
					self.removeClass('showSidebar');
					self.html('Hide sidebar');
					$('#tdRightContent').show();
				} else {
					//The sidebar is currently being shown and needs to be hidden
					self.addClass('showSidebar');
					self.html('Show sidebar');
					$('#tdRightContent').hide();
				}
				$('td.tdRight').toggleClass('tdRightCollapsed');
				$('div.tdLeftMainBottom').toggleClass('tdLeftMainBottomFull');
				ap.ui.admin.windowResize(); //in case there was a scroll bar and now it's gone, or vise versa
				this.blur();
				return false;
			});
		},
		setupFloatingButtons: function()
		{
			var buttons = $('div.submit:first');
			if (buttons.length > 0) {
				buttonPos = buttons.offset();
				var buttonClone = buttons.clone().removeClass('submit').addClass('submit-floating').css({display: 'none', opacity: 0.95}).insertAfter('div.submit:first');
				$(window).scroll(function(){
					if ($(this).scrollTop() > buttonPos.top) {
						buttonClone.show();
					} else {
						buttonClone.hide();
					}
				});
			}
		},
		// Blocks the UI with the specific text
		block: function(text) {
			var loadingMsg = $('#loadingMessage');
			if (text) {
				$('p:first', loadingMsg).html(text);
			}
			$.blockUI({message: loadingMsg, baseZ: 3000});
		},
		// Convenience function to block the UI and show the same text
		uploadBlock: function(options) {
			var uploadOptions = {
				setSaveButton: false,
				saveButtonName: 'save',
				form: null
			};
			$.extend(uploadOptions, options);
			if (true === uploadOptions.setSaveButton && null !== uploadOptions.form) {
				$('<input type="hidden" name="' + uploadOptions.saveButtonName + '" value="yes" />').appendTo(uploadOptions.form);
			}
			this.block('Please wait while the information is submitted...');
		},
		showActivityIndicator: function()
		{
			this.activityIndicator.show();
		},
		hideActivityIndicator: function()
		{
			this.activityIndicator.hide();
		},
		/**
		* Gets the message dom object
		* @param string message The message text
		*/
		getMessage: function(message) {
			var c = this.messageDiv.clone(true);
			c.html(message).css('backgroundColor', '#c2ebc3').removeClass('errorMsg').addClass('message');
			return c;
		},
		/**
		* Gets the error message dom object
		* @param string message The error message text
		*/
		getErrorMessage: function(message) {
			var c = this.errorDiv.clone(true);
			c.html(message).css('backgroundColor', '#fcbdc4').removeClass('message').addClass('errorMsg');
			return c;
		},
		showMessage: function(message)
		{
			this.hideActivityIndicator();
			if (message != undefined) {
				this.hideError();
				this.messageDiv.html(message).css('backgroundColor', '#c2ebc3').removeClass('errorMsg').addClass('message').show().animate({backgroundColor: '#E2F9E3'}, 1500);
				//this.messageDiv.html(message).css('backgroundColor', '#c2ebc3').removeClass('errorMsg').addClass('message').show();
				ap.ui.admin.windowResize(); //Because the message could push down the content and create a scroll bar which would affect the window width
			}
		},
		showError: function(message)
		{
			this.hideActivityIndicator();
			if (message != undefined) {
				this.hideMessage();
				this.errorDiv.html(message).css('backgroundColor', '#fcbdc4').removeClass('message').addClass('errorMsg').show().animate({backgroundColor: '#FFEDEF'}, 1500, 'linear');
				ap.ui.admin.windowResize(); //Because the message could push down the content and create a scroll bar which would affect the window width
			}
		},
		hideMessage: function()
		{
			if (this.messageDiv != undefined) {
				this.messageDiv.hide();
			}
		},
		hideError: function()
		{
			if (this.errorDiv != undefined) {
				this.errorDiv.hide();
			}
		},
		hideMessageAndError: function() {
			this.hideMessage();
			this.hideError();
		},
		hideAll: function(exception)
		{
			this.hideActivityIndicator();
			if (exception == undefined || typeof exception == 'string') {
				if (exception != 'message') this.hideMessage();
				if (exception != 'error') this.hideError();
			} else if (exception instanceof Array) {
				if ($.inArray('message', exception) == -1) this.hideMessage();
				if ($.inArray('error', exception) == -1) this.hideError();
			}
			ap.ui.sections.hideAll(exception);
			return false;
		},
		disableButtons: function(buttons)
		{
			$(buttons).attr('disabled', 'disabled');
		},
		enableButtons: function(buttons)
		{
			$(buttons).removeAttr('disabled');
		}
	};
	/**
	* Handles the My Account link
	*/
	ap.myAccount = {
		init: function() {
			var self = this;
			$('#myAccount').click(function() {
				var dialog = new ap.ui.dialog({title: 'My Account'}, {
					load: function(box) {
						$('#myAccountTabs', box).tabs();
						ap.focus('#IDEditUsername');
					}
				});
				dialog.open(ncAdminBaseUrl + 'myaccount/ajax');
				return false;
			});
		}
	};
	
	/**
	* Handles the Microsite link
	*/
	ap.sites = {
		init: function() {
			var self = this;
			$('#apSites').click(function() {
				var dialog = new ap.ui.dialog({title: 'Sites &amp; Microsites'});
				dialog.open(ncAdminBaseUrl + 'site/browser');
				return false;
			});
		}
	};
	
	/**
	* Create a dialog box on the fly that can handle forms and
	* display form messages.

	* The options for the jQuery UI dialog and this object are kept separate
	* so that with future versions of jQuery UI there isn't a possibility of
	* using a option name internally that is used in the jQuery UI dialog options.
	*
	* @param object dialogOptions The options for the jQuery UI dialog box
	* @param object options The general options for this box
	*/
	ap.ui.dialog = function(dialogOptions, options) {
		// Holds the dialog dom object
		this.box = null;

		// Holds the URL to be loaded
		this.url = null;

		var self = this;

		// Holds the options for the dialog box
		this.dialogOptions = {
			height: '90%',
			width: '75%',
			minHeight: 200,
			minWidth: 300,
			modal: true,
			position: 'center',
			open: function() {self.load(); },
			close: function() {self.close(); }
		};
		$.extend(this.dialogOptions, dialogOptions);

		// Holds the general options
		this.options = {
			load: null // Callback function for after the content is loaded
		};
		$.extend(this.options, options);

		// If the height and width are percents then get the pixel height
		if (typeof this.dialogOptions.height == 'string' && this.dialogOptions.height.indexOf('%') > -1) {
			this.dialogOptions.height = (parseInt(this.dialogOptions.height) / 100) * ap.window.height;
		}
		if (typeof this.dialogOptions.width == 'string' && this.dialogOptions.width.indexOf('%') > -1) {
			this.dialogOptions.width = (parseInt(this.dialogOptions.width) / 100) * ap.window.width;
		}

	};

	ap.ui.dialog.prototype = {
		open: function(url) {
			this.url = url;
			var html = '<div class="apuiDialog"><div class="apuiDialogMsg"></div><div class="apuiDialogContent"><div class="apuiDialogLoading"></div></div></div>';
			this.box = $(html).appendTo('body').dialog(this.dialogOptions);
			$('.apuiDialogLoading', this.box).height(this.box.height()).css('minHeight', this.box.css('minHeight'));
		},
		load: function() {
			var self = this;
			var saving = $('<div class="apuiDialogSave">Saving</div>');
			$('.apuiDialogContent', this.box).load(this.url, null, function(responseText, textStatus, XMLHttpRequest) {
				if ($.isFunction(self.options.load)) {
					self.options.load.call(this, self.box, self.options, responseText, textStatus, XMLHttpRequest);
				}
				var submit = $('.submit', self.box);
				$('form', self.box).ajaxForm({
					dataType: 'json',
					beforeSubmit: function() {
						saving.appendTo(self.box).insertAfter(submit).show();
						submit.hide()
					},
					success: function(response) {
						if (response.error == undefined) {
							if (response.msg != undefined) {
								$('.apuiDialogMsg', self.box).html(ap.ui.getMessage(response.msg));
							}
						} else {
							$('.apuiDialogMsg', self.box).html(ap.ui.getErrorMessage(response.error));
						}
						$('.apuiDialogSave', self.box).remove();
						submit.show();
					}
				});
				$('a.cancel', self.box).click(function (){
					self.box.dialog('close');
					return false;
				});
			});
		},
		close: function() {
			this.box.remove();
		}
	};


	ap.ui.sections = {
		sections: null,
		init: function()
		{
			this.sections = {};
		},
		add: function(name, selector)
		{
			selector = selector || '#' + name;
			this.sections[name] = $(selector);
		},
		tabSetup: function(selector)
		{
			// Find all divs with the class name of selector
			selector = selector || 'div.tabSections';
			$(selector).each(function(i){
				// Get the id and parse of "Section" text
				if (this.id.length > 0) {
					// The id should be in the form of idSection
					// Remove "Section" from the id
					var id = this.id.replace('Section', '');
					// Find the tab that matches the section
					// Tabs should have ids in the form of idTab
					// 'id' comes from the modified section id
					var tabId = '#' + id + 'Tab';
					var name = 'nc' + id;
					// If this is the first section, show it, otherwise hide it
					if (i > 0) {
						this.style.display = 'none';
					} else {
						this.style.display = 'block';
					}
					ap.ui.sections.add(name, '#' + this.id);
					ap.ui.sideTabs.add(name, tabId);
				}
			});
		},
		hide: function (section)
		{
			this.sections[section].hide();
			ap.ui.admin.windowResize(); //in case there was a scroll bar and now it's gone, or vise versa
			return false;
		},
		show: function(section, exceptions)
		{
			if (exceptions instanceof Array) {
				exceptions.push(section);
				this.hideAll(exceptions);
			} else {
				this.hideAll(section);
			}
			this.sections[section].show();
			ap.ui.admin.windowResize(); //in case there was a scroll bar and now it's gone, or vise versa
			return false;
		},
		hideAll: function(exception)
		{
			for (var x in this.sections) {
				var hideThis = true;
				if (typeof exception == 'string' && exception == x) {
					hideThis = false;
				} else if (exception instanceof Array && $.inArray(x, exception) != -1) {
					hideThis = false;
				}
				if (true === hideThis) {
					this.sections[x].hide();
				}
			}
		},
		exists: function(name)
		{
			var set = false;
			if (null != this.sections) {
				if (this.sections[name] != undefined) {
					set = true;
				}
			}
			return set;
		}
	};
	/**
	* Create vertical tabs.
	* Requires the jquery UI Tabs
	* The selector shoudd be a div around a ul, which will
	* be converted to tabs.  Each tab panel will be a div
	* within the selector. The divs will be given a width of
	* 100% - 160px and floated right. The tabs will be floated
	* left. A clearing div will be added right after the
	* floated panels.
	*/
	ap.ui.verticalTabs = {
		init: function(selector) {
			selector = $(selector);
			if (selector.length > 0) {
				selector.tabs({
					deselectableClass: 'ap-vtabs-deselectable',
					disabledClass: 'ap-vtabs-disabled',
					hideClass: 'ap-vtabs-hide',
					idPrefix: 'ap-vtabs',
					loadingClass: 'ap-vtabs-loading',
					navClass: 'ap-vtabs-nav ap-vtabs-widget-header',
					panelClass: 'ap-vtabs-panel',
					selectedClass: 'ap-vtabs-selected ap-vtabs-state-active'
				}).addClass('ap-vtabs');
				var panel = $('.ap-vtabs-panel:first', selector);
				var tabs = $('.ap-vtabs-nav', selector);
				var tabHeight = tabs.height();
				var width = selector.width() - tabs.width() - (panel.outerWidth() - panel.innerWidth()) - parseInt(panel.css('borderLeftWidth')) - parseInt(panel.css('borderRightWidth'));
				$('.ap-vtabs-panel', selector).each(function() {
					// Make sure that the panel isn't shorter than the tabs
					var p = $(this);
					if (p.height() < tabHeight) {
						p.css('minHeight', tabHeight);
						/**
						* Test again to see if the height is the same as the tabs. If it is not then
						* min-height is not supported (IE). The 'height' css property should be used
						* instead.
						*/
						if (p.height() < tabHeight) {
							p.height(tabHeight);
						}
					}
				});
				// Add class for the last tab
				$('li:last', tabs).addClass('ap-vtabs-last');
			}
		}
	};
	ap.ui.sideTabs = {
		tabs: null,
		init: function()
		{
			this.tabs = {};
		},
		add: function(name, options)
		{
			var tabOptions = {
				selector: null,
				disabled: false,
				callback: null
			}
			if (options.constructor == Object) {
				$.extend(tabOptions, options);
			} else if (options.constructor == String) {
				// If options is a string assume that it's the selector
				tabOptions.selector = options;
			}
			tabOptions.selector = tabOptions.selector || '#' + name;
			this.tabs[name] = $(tabOptions.selector);
			if (true === tabOptions.disabled) {
				this.tabs[name].addClass('disabled').click(function(){
					return false;
				});
			} else if (null != tabOptions.callback) {
				this.tabs[name].click(function(){
					this.blur();
					ap.ui.sideTabs.select(name);
					tabOptions.callback();
					return false;
				});
			} else {
				this.tabs[name].click(function(){
					this.blur();
					ap.ui.sideTabs.select(name);
					if (ap.ui.sections.exists(name)) {
						ap.ui.sections.show(name);
					}
					return false;
				});
			}
		},
		remove: function(name)
		{
			delete this.tabs[name];
		},
		select: function(name)
		{
			this.unselectAll();
			this.tabs[name].addClass('active');
		},
		unselectAll: function()
		{
			$.each(this.tabs, function(i, tab){
				ap.ui.sideTabs.tabs[i].removeClass('active');
			});
		},
		enable: function(name, callback)
		{
			this.tabs[name].removeClass('disabled').unbind('click').click(function(){
				this.blur();
				callback();
				ap.ui.sideTabs.select(name);
				return false;
			});
		},
		disable: function(name)
		{
			this.tabs[name].addClass('disabled').unbind('click').click(function() {this.blur();return false;});
		},
		disableAll: function()
		{
			$.each(this.tabs, function(i, tab) {
				ap.ui.sideTabs.tabs[i].addClass('disabled').unbind('click').click(function(){this.blur();return false;});
			});
		}
	};
	ap.ui.table = {
		form: null,
		table: null,
		idCheckboxes: null,
		selectAll: null,
		actionLinks: null,
		options: {
			tableSelector: 'table.tblList',
			formSelector: '#listForm',
			deleteSelector: '#delete',
			sort: true,
			sortHeaders: {},
			singular: '',
			plural: '',
			deleteMsg: '',
			basePath: '',
			deletePath: 'delete',
			deleteCallback: null
		},
		init: function(options)
		{
			$.extend(this.options, options);
			this.form = $(this.options.formSelector);
			// Cancel the form submission
			this.form.submit(function(){
				return false;
			});
			this.table = $(this.options.tableSelector);
			this.setupActionLinks();
			this.setupIdCheckboxes();
			this.setupSelectAll();
			this.deactivateTableActions();
			this.setupDelete();
			if (true === this.options.sort) {
				this.sort()
			}
		},
		setupActionLinks: function()
		{
			this.actionLinks = $('a.actionLink', $('div.tblActions'));
		},
		setupDelete: function()
		{
			var self = this;
			$(this.options.deleteSelector).click(function(){
				var count = self.countCheckboxes();
				if (count > 0) {
					var item = count > 1 ? 'these ' + count + ' ' + self.options.plural : 'this ' + self.options.singular;
					if (confirm('Are you sure you want to delete ' + item + '? ' + self.options.deleteMsg)) {
						var data = self.deleteRows();
						if (data.length > 0) {
							ap.ui.showActivityIndicator();
							$.post(self.options.basePath + self.options.deletePath, data, function(response) {
								if (response.error == undefined) {
									ap.ui.showMessage(response.msg);
								} else {
									ap.ui.showError(response.error);
								}
								if (self.options.deleteCallback != undefined) {
									self.options.deleteCallback(response);
								}
							}, 'json');
						}
						self.applyWidgets();
					}
				} else {
					alert('You must click the checkbox next to at least one ' + self.options.singular);
				}
				this.blur();
				return false;
			});
		},
		setupSelectAll: function()
		{
			var self = this;
			this.selectAll = $('a.selectAll', this.form);
			this.selectAll.click(function(){
				if ($(this).html() == 'select all') {
					self.selectAllCheckboxes();
				} else {
					self.unselectAllCheckboxes();
				}
				this.blur();
				return false;
			});
		},
		selectAllCheckboxes: function()
		{
			this.idCheckboxes.attr('checked', 'checked');
			if (this.countCheckboxes() > 0) {
				this.selectAll.html('unselect');
				this.activateTableActions();
			}
		},
		unselectAllCheckboxes: function()
		{
			this.selectAll.html('select all');
			this.idCheckboxes.removeAttr('checked');
			this.deactivateTableActions();
		},
		setupIdCheckboxes: function()
		{
			var self = this;
			this.idCheckboxes = $(':checkbox[name="id[]"]', $('td.col_1', this.form));
			if (this.idCheckboxes.length > 0) {
				$('td.col_1', this.form).click(function() {
					var checkbox = $(':checkbox', this);
					if (true == checkbox.attr('checked')) {
						checkbox.removeAttr('checked');
					} else {
						checkbox.attr('checked', 'checked');
					}
					self.handleCheckboxClick(checkbox);
				});
			}
			this.idCheckboxes.click(function(e){
				self.handleCheckboxClick(this);
				e.stopPropagation();
				//                if (true === this.checked) {
				//                    self.activateTableActions();
				//                } else {
				//                    if (self.countCheckboxes() == 0) {
				//                        self.deactivateTableActions();
				//                    }
				//                }
			});
		},
		handleCheckboxClick: function(checkbox)
		{
			checkbox = $(checkbox);
			if (true === checkbox.checked || checkbox.attr('checked')) {
				ap.ui.table.activateTableActions();
			} else {
				if (ap.ui.table.countCheckboxes() == 0) {
					ap.ui.table.deactivateTableActions();
				}
			}
		},
		countCheckboxes: function()
		{
			return this.idCheckboxes.filter(':checked').length;
		},
		/**
		* Handles deleting items from a table list
		*/
		deleteRows: function()
		{
			data = '';
			this.idCheckboxes.filter(':checked').each(function(i){
				if (data.length > 0) {
					data += '&';
				}
				data += 'id%5B%5D=' + this.value;
				var tr = this.parentNode.parentNode;
				$(tr).remove();
			});
			this.setupIdCheckboxes();
			this.unselectAllCheckboxes();
			return data;
		},
		getRowIdQuery: function()
		{
			data = '';
			this.idCheckboxes.filter(':checked').each(function(i){
				if (data.length > 0) {
					data += '&';
				}
				data += 'id%5B%5D=' + this.value;
			});
			return data;
		},
		deactivateTableActions: function()
		{
			if (null === this.actionLinks) {
				this.setupActionLinks();
			}
			this.actionLinks.addClass('disabled');
		},
		activateTableActions: function()
		{
			if (null === this.actionLinks) {
				this.setupActionLinks();
			}
			this.actionLinks.removeClass('disabled');
		},
		sort: function(sorting)
		{
			if (sorting == undefined) {
				this.table.tablesorter({
					headers: this.options.sortHeaders,
					widgets: ['zebra', 'rowover']
				});
			} else {
				this.table.trigger('sorton', [sorting]);
			}
		},
		applyWidgets: function()
		{
			this.table.trigger('applyWidgets');
		},
		update: function()
		{
			this.table.trigger('update');
			this.applyWidgets();
		},
		addRow: function(row, tbody)
		{
			tbody = tbody || $('tbody', this.table);
			tbody.append(row);
			domRow = $('tr:last', tbody);
			this.setupIdCheckboxes();
			this.update();
			return domRow;
		}
	};
	// Admin specific methods.
	ap.ui.admin = {
		init: function() {
			this.setupFormFocus();
			ap.externalLinks();
			this.setupMainNavigation();
			this.setupSubNavigation();
			$(window).resize(function() {
				ap.ui.admin.windowResize();
			});
		},
		windowResize: function()
		{
			ap.getWindowSize();
			//this.setupSubNavigation();
			ap.myModulesNav.setup();
		},
		/**
		* Sets the display for form fields when they receive focus
		*/
		setupFormFocus: function() {
			//$(':text', 'textarea', ':password').each(function(){
			$(':text, textarea, :password').each(function(){
				var el = $(this);
				var bgColor = el.css('background-color');
				el.blur(function() {
					this.style.backgroundColor = bgColor;
				}).focus(function() {
					this.style.backgroundColor = '#ffffbb';
				});
			});
		},


		/**
		* Adds the hover functionality to the li items so that the dropdowns can be displayed.
		* That functionality is for IE as it doesn't support :hover on anything but links.
		* This also will hide the current dropdown sub navigation if it exists while the other
		* main navigation items are moused over.
		*/
		setupMainNavigation: function() {
			var nav = $('#nav > ul:first');
			var liActive = $('li.active', nav);

			nav.children().each (function(i){
				var el = $(this);
				el.mouseover(function() {
					if (!el.hasClass('active')) {
						liActive.addClass('activeOut');
					}
					el.addClass('over');
				});
				el.mouseout(function() {
					if (!el.hasClass('active')) {
						liActive.removeClass('activeOut');
					}
					el.removeClass('over');
				});
			});
		},
		/**
		* For some reason IE won't keep the width of nested UL tags at 100%. It will
		* respect pixel widths, though.  So we'll set the width of all the sub nav items
		* to be the width of the window
		*/
		setupSubNavigation: function() {
			var windowWidth = $(window).width();
			$('li > ul', $('#nav')).each(function(){
				this.style.width = windowWidth + 'px';
			});
		}
	};
	// String filters.  Not the same as javascript dom filters
	ap.filter = {
		// Filters the string
		key: function(text) {
			text = $.trim(text.toLowerCase());
			text = text.replace(/\W+/g, ' ');
			text = text.replace(/\s+|_+|-{2,}/g, '-');
			return text;
		}
	};
	/**
	* Module specific code. This would be defined in the javascript for the
	* specific module.
	*/
	ap.module = {
		init: function(){}
	};

	ap.myModulesNav = {
		btn: null,
		wrapper: null,
		wrapperHeight: null,
		hoveringBtn: false,
		hoveringWrapper: false,
		json: null,
		columnWidth: 200,
		numColumns: 0,
		init: function() {
			this.btn = $('#myModulesBtn');
			var self = this;
			if (this.btn.length > 0) {
				this.wrapper = $('#myModulesWrapper');
				this.setup();
				this.btn.hoverIntent({
					over: function() {self.hoveringBtn = true; self.show(); },
					out: function() {self.hoveringBtn = false; self.hide(); },
					timeout: 0
				});
				this.wrapper.hover(
				function() {self.hoveringWrapper = true; self.show(); },
				function() {self.hoveringWrapper = false; self.hide(); }
				);
			}
		},
		setup: function() {
			// Get the window height
			var windowHeight = $(window).height();
			if (this.btn != undefined && this.btn.length > 0) {
				// Get the position of the MyModules button
				var btnTop = this.btn.offset().top;
				var btnHeight = this.btn.height();
				// Set the position and height of the My Modules Wrapper
				var wrapperY = btnTop + btnHeight;
				this.wrapperHeight = windowHeight - btnTop - btnHeight;
				this.wrapper.css({top: wrapperY, height: this.wrapperHeight});
				var wrapperWidth = this.wrapper.width();
				// Set the height of the container
				$('#myModulesContainer').css({height: this.wrapperHeight - 10, width: wrapperWidth - 42});
				this.calculateColumns(wrapperWidth);
				this.setText();
			}
		},
		calculateColumns: function(wrapperWidth) {
			this.numColumns = Math.floor(wrapperWidth / this.columnWidth);
		},
		setText: function() {
			if (this.json == undefined) {return;}
			var self = this;
			var html = '<table cellspacing="0"><tbody>';
			var column = 1;
			$.each(self.json, function(n, data) {
				if (column > self.numColumns) {
					html += '</tr>';
					column = 1;
				}
				if (column == 1) {
					html += '\n<tr>';
				}
				html += '\n<td width="' + self.columnWidth + '">';
				html += '<h2><a href="' + data.url + '">' + data.text + '</a></h2>';
				if (data.subs != undefined) {
					html += '<ul>';
					$.each(data.subs, function() {
						html += self.setSubText(this);
					});
					html += '</ul>';
				}
				html += '</td>';
				column ++;
			});
			if (column <= self.numColumns) {
				while (column <= self.numColumns) {
					html += '<td width="' + self.columnWidth + '">&nbsp;</td>';
					column ++;
				}
				html += '</tr>';
			}
			html += '</tbody></table>';
			$('#myModulesContainer').html(html);
		},
		setSubText: function(data) {
			var self = this;
			var html = '<li>';
			html += '<a href="' + data.url + '">' + data.text + '</a>';
			if (data.subs != undefined) {
				html += '<ul>';
				$.each(data.subs, function() {
					html += self.setSubText(this);
				});
				html += '</ul>';
			}
			html += '</li>';
			return html;
		},
		show: function() {
			this.wrapper.fadeIn(100);
		},
		hide: function() {
			setTimeout(function() {
				ap.myModulesNav.testHide();
			}, 200);
		},
		testHide: function() {
			// Only hide if not hovering on the button or wrapper
			if (this.hoveringBtn == false && this.hoveringWrapper == false) {
				this.wrapper.fadeOut(200);
			}
		}
	};

})(jQuery);