var urlHelpRoot = URL_CMSROOT + 'admin/help';

// making up for IE's lack of functionality
if (!Array.prototype.map) {
	Array.prototype.map = function(fun /*, thisp */) {
		var len = this.length;
		if (typeof fun != 'function') throw new TypeError();
		var res = new Array(len);
		var thisp = arguments[1];
		for (var i = 0; i < len; i++) {
			if (i in this) {
				res[i] = fun.call(thisp, this[i], i, this);
			}
		}
		return res;
	};
}
if (!Array.prototype.filter) {
	Array.prototype.filter = function(fun /*, thisp*/) {
		var len = this.length;
		if (typeof fun != "function") throw new TypeError();
		var res = new Array();
		var thisp = arguments[1];
		for (var i = 0; i < len; i++) {
			if (i in this) {
				var val = this[i]; // in case fun mutates this
				if (fun.call(thisp, val, i, this))
					res.push(val);
			}
		}
		return res;
	};
}

// create a scope to store overridden functions
(function($) {
	$._bazAdmin = $._bazAdmin || {};
})(jQuery);

(function($) {
	$.TabView = function(tv) {
		if (!tv.jquery) tv = $(tv);
		$('.tabHeader a.tab', tv).unbind('click').click(function() {
			var _tv = $(this).parents('.tabView')[0];

			/* Update the current class */
			$('.tabHeader a.tab', _tv).removeClass('current');
			$(this).addClass('current');

			var id = $(this).parent()[0].id.substring(9);
			$('.tabContentSection', _tv).hide();
			$('.'+id, _tv).show();

			this.blur();
			return false;
		});
	}
})(jQuery);


jQuery._bazAdmin.param = jQuery._bazAdmin.param || jQuery.param;
jQuery.extend({
	includeJs: function(file) {
		jQuery('<script></script>')
			.attr('type', 'text/javascript')
			.attr('src', file)
			.appendTo('head');
	},
	includeCss: function(file) {
		jQuery('<link />')
			.attr('rel', 'stylesheet')
			.attr('type', 'text/css')
			.attr('href', file)
			.appendTo('head');
	},
	/**
	 * Reverse parameterisation function.
	 * jQuery.param() takes an array/object and returns a query string.
	 * jQuery._param() takes a url/query string and returns an object.
	 */
	_param: function(str) {
		var data = {};
		if (str && str.indexOf) {
			/* strip off url (if exists) and split on & characters */
			var q = str.substring(str.indexOf('?')+1).split('&');
			for (var i = 0; i < q.length; i++) {
				var p = q[i].split('=');
				data[p[0]] = p[1];
			}
		}
		return data;
	},
	/* change the normal param to pass through array values with name[]=value
	 * rather than multiple name=value's which ends up with just the last one
	 * being used in php */
	param: function(a) {
		var s = [];

		// If an array was passed in, assume that it is an array
		// of form elements
		if ( a.constructor == Array || a.jquery )
			// Serialize the form elements
			jQuery.each( a, function(){
				s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) );
			});

		// Otherwise, assume that it's an object of key/value pairs
		else
			// Serialize the key/values
			for ( var j in a )
				// If the value is an array then the key names need to be repeated
				if ( a[j] && a[j].constructor == Array )
					jQuery.each( a[j], function(){
						s.push( encodeURIComponent(j) + "[]=" + encodeURIComponent( this ) );
					});
				else
					s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) );

		// Return the resulting serialization
		return s.join("&");
	}
});



/**
 * jquery dimension
 */

/* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * $LastChangedDate: 2007-12-20 08:46:55 -0600 (Thu, 20 Dec 2007) $
 * $Rev: 4259 $
 *
 * Version: 1.2
 *
 * Requires: jQuery 1.2+
 */

(function($){
	
$.dimensions = {
	version: '1.2'
};

// Create innerHeight, innerWidth, outerHeight and outerWidth methods
$.each( [ 'Height', 'Width' ], function(i, name){
	
	// innerHeight and innerWidth
	$.fn[ 'inner' + name ] = function() {
		if (!this[0]) return;
		
		var torl = name == 'Height' ? 'Top'    : 'Left',  // top or left
		    borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
		
		return this.is(':visible')
			? this[0]['client' + name]
			: num( this, name.toLowerCase() )
				+ num(this, 'padding' + torl)
				+ num(this, 'padding' + borr);
	};
	
	// outerHeight and outerWidth
	$.fn[ 'outer' + name ] = function(options) {
		if (!this[0]) return;
		
		var torl = name == 'Height' ? 'Top'    : 'Left',  // top or left
		    borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
		
		options = $.extend({ margin: false }, options || {});
		
		var val = this.is(':visible') ? 
				this[0]['offset' + name] : 
				num( this, name.toLowerCase() )
					+ num(this, 'border' + torl + 'Width')
					+ num(this, 'border' + borr + 'Width')
					+ num(this, 'padding' + torl)
					+ num(this, 'padding' + borr);
		
		return val + (options.margin ? (num(this, 'margin' + torl) + num(this, 'margin' + borr)) : 0);
	};
});

// Create scrollLeft and scrollTop methods
$.each( ['Left', 'Top'], function(i, name) {
	$.fn[ 'scroll' + name ] = function(val) {
		if (!this[0]) return;
		
		return val != undefined ?
		
			// Set the scroll offset
			this.each(function() {
				this == window || this == document ?
					window.scrollTo( 
						name == 'Left' ? val : $(window)[ 'scrollLeft' ](),
						name == 'Top'  ? val : $(window)[ 'scrollTop'  ]()
					) :
					this[ 'scroll' + name ] = val;
			}) :
			
			// Return the scroll offset
			this[0] == window || this[0] == document ?
				self[ (name == 'Left' ? 'pageXOffset' : 'pageYOffset') ] ||
					$.boxModel && document.documentElement[ 'scroll' + name ] ||
					document.body[ 'scroll' + name ] :
				this[0][ 'scroll' + name ];
	};
});

$.fn.extend({
	position: function() {
		var left = 0, top = 0, elem = this[0], offset, parentOffset, offsetParent, results;
		
		if (elem) {
			// Get *real* offsetParent
			offsetParent = this.offsetParent();
			
			// Get correct offsets
			offset       = this.offset();
			parentOffset = offsetParent.offset();
			
			// Subtract element margins
			offset.top  -= num(elem, 'marginTop');
			offset.left -= num(elem, 'marginLeft');
			
			// Add offsetParent borders
			parentOffset.top  += num(offsetParent, 'borderTopWidth');
			parentOffset.left += num(offsetParent, 'borderLeftWidth');
			
			// Subtract the two offsets
			results = {
				top:  offset.top  - parentOffset.top,
				left: offset.left - parentOffset.left
			};
		}
		
		return results;
	},
	
	offsetParent: function() {
		var offsetParent = this[0].offsetParent;
		while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') )
			offsetParent = offsetParent.offsetParent;
		return $(offsetParent);
	}
});

function num(el, prop) {
	if (el.jquery) el = el[0];
	if (el == document.defaultView) return 0;
	return parseInt($.curCSS(el,prop,true))||0;
};

})(jQuery);

/** 
 * End jquery dimension
 **/
 
(function($) {
	$._bazAdmin.cookie = $._bazAdmin.cookie || $.cookie;
	$.extend({
		toJSON: function(value, forceType) {
			var type = (undefined == forceType) ? typeof value : forceType;
			var r = {
				'\b'	: '\\b',
				'\t'	: '\\t',
				'\n'	: '\\n',
				'\f'	: '\\f',
				'\r'	: '\\r',
				'"'		: '\\"',
				'\\'	: '\\\\'
			};
			switch (type)
			{
				case 'string':
					if (/[\"\\\x00-\x1f]/.test(value)) {
						value = value.replace(
							/([\x00-\x1f\\"])/g,
							function(a, b) {
								var c = r[b];
								if (c) return c;
								c = b.charCodeAt();
								return '\\u00'
									+ Math.floor(c / 16).toString(16)
									+ (c % 16).toString(16);
							}
						);
					}
					return '"' + value + '"';

				case 'number':
					return isFinite(value) ? String(value) : 'null';

				case 'boolean':
					return String(value);

				case 'null':
					return 'null';

				case 'array':
					var a = ['['], i, l = value.length;
					for (i = 0; i < l; i += 1) {
						if (value[i] !== undefined) {
							if (b) a[a.length] = ',';
							a.push($.toJSON(value[i]));
							b = true;
						}
					}
					a[a.length] = ']';
					return a.join('');

				case 'object':
					if (value) {
						if (value instanceof Array) {
							return $.toJSON(value, 'array');
						}
						var a = ['{'], b, i;
						for (i in value) {
							if (value[i] !== undefined) {
								if (b) a[a.length] = ',';
								a.push(
									$.toJSON(i),
									':',
									$.toJSON(value[i])
								);
								b = true;
							}
						}
						a[a.length] = '}';
						return a.join('');
					}
					return 'null';
			}
		},
		parseJSON: function(value) {
			if (/^("(\\.|[^\"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(value))
				return eval('('+value+')');
		},
		/* Setup cookies to automatically JSON encode anything that is put into
		 * them.  This allows us to store arrays etc in cookies (not just
		 * strings and numbers) */
		cookie: function(name, value, options) {
			if (value != undefined) {
				$._bazAdmin.cookie(name, $.toJSON(value), options);
			} else {
				return $.parseJSON($._bazAdmin.cookie(name));
			}
		}
	});
})(jQuery);


/**
 * Attach event calls to specific events.
 */
jQuery._bazAdmin = jQuery._bazAdmin || {};
jQuery._bazAdmin.show = jQuery._bazAdmin.show || jQuery.fn.show;
jQuery._bazAdmin.hide = jQuery._bazAdmin.hide || jQuery.fn.hide;
jQuery._bazAdmin.remove = jQuery._bazAdmin.remove || jQuery.fn.remove;
jQuery.fn.extend({
	
	show: function() {
		this.trigger('show');
		return $._bazAdmin.show.apply(this, arguments);
	},
	hide: function() {
		this.trigger('hide');
		return $._bazAdmin.hide.apply(this, arguments);
	},
	remove: function() {
		this.trigger('remove');
		return $._bazAdmin.remove.apply(this, arguments);
	},

	setupAjaxLinks: function() {
		$('a.ajax', this).click(function() {
			var href = this.href;
			var params = {};
			if (this.target) {
				params = { '_target' : this.target };
			}
			$.post(href, params);
			return false;
		});
		$('form.ajax', this).submit(function() {
			$.post(this.action, $(':input', this).serialize());
		});
	},

	/* This was meant for triggering auto commit on resizing.  Some browsers,
	 * mainly IE insist on triggering the resize event continuously while
	 * resizing.  This of course is very bad for CPU and memory usage.
	delayedAutofit: function() {
		clearTimeout(jQuery.autofitTimerId);
		jQuery.autofitTimerId = setTimeout(
			'jQuery(\'div.popup\').autofit();', 1000
		);
	},
	*/

	/* Attempt to auto stretch out particular entities to fill up the available
	 * space.  The elements to be expanded should have one of the following
	 * classes assigned to them: expand, expandY, expandX. */
	autofit: function() {
		return this.each(function() {
			var that = this;

			/* Short circuit digging into tinymce blocks */
			if ($(this).is('.mceEditorContainer')) return;

			/* To make things easier, im asuming mce editor boxes will always
			 * be expanded */
			var expandY = jQuery(
				'/.expand:visible,/.expandY:visible,/.mceEditor', this);
			/* Dont worry about checking to resize mce editor boxes in the X
			 * direction as they will already do that themselves */
			var expandX = jQuery('/.expand:visible,/.expandX:visible', this);

			/* Base level popup */
			if (jQuery(this).is('div.popup')) {
				if (expandY.length) {
					jQuery(this).css({
						'width'		: (jQuery(window).width() * 0.8) + 'px',
						'left'		: (jQuery(window).width() * 0.1) + 'px'
					});
				}
				if (expandX.length) {
					jQuery(this).css({
						'height'	: (jQuery(window).height() * 0.8) + 'px',
						'top'		: Math.floor($(window).scrollTop()
							+ (jQuery(window).height() * 0.1)) + 'px'
					});
				}

				/* add resize event */
				/*
				jQuery(window).resize(function() {
					// Need to have a timer/clear around this for IE and safari
					// which both continuously fire the resize event while
					// resizing...
					jQuery(that).delayedAutofit();
				});
				*/
			}

			/* Auto fit height */
			if (expandY.length) {
				var height = jQuery(this).innerHeight();
				var count = expandY.length;
				var offsetY = undefined;
				
				jQuery(this).children().each(function() {
					if ('absolute' == jQuery(this).css('position')) return;
					if (jQuery(this).is(':hidden')) return;
					if ('block' != jQuery(this).css('display')) return;
					if (!jQuery(this).is(
						'.expand,.expandY,:hidden,.mceEditor'))
					{
						height = height - jQuery(this).outerHeight()
							- (parseInt(jQuery(this).css("marginBottom")) || 0)
							- (parseInt(jQuery(this).css("marginTop")) || 0);
					}
					if (jQuery(this).is(
						'.expand:visible,.expandY:visible,.mceEditor'))
					{
						var oY = jQuery(this).scrollTop();
						if (offsetY == oY) count--;
						offsetY = oY;
					}
				});

				height = Math.floor(height / count);
				expandY.each(function() {

					var h = height
						- jQuery(this).outerHeight()
						+ jQuery(this).innerHeight();

					/* Special case for mce editor resizing */
					if (jQuery(this).is('textarea.mceEditor')) {
						var inst = tinyMCE.getInstanceById(this.id);
						if (inst) {
							// firefox fix
							if ($.browser.mozilla) {
								var h2 = $(this).parent().innerHeight()
									+ $('#' + inst.editorId).innerHeight()
									- $('#' + inst.editorId + '_parent table').outerHeight();
								ifr = $('#'+this.id+'_ifr');
								ifr.css('height', h2 + 'px');
							}

							// everyone else
							h = h + $('#' + inst.editorId).innerHeight()
								- $('#' + inst.editorId + '_parent table').outerHeight();
							$('#' + inst.editorId).css('height', h + 'px');
						}
					}
					jQuery(this).css('height', h + 'px');
				});
			}

			/* Auto fit width */
			if (expandX.length) {
				/* Safari has a wierd bug where any floating elements return
				 * the width of the containing element, even if they do
				 * actually have a width set... thus it is safer to just use
				 * 100%, even if this doesn't take into count any margins etc
				 * that may cause it to look slightly wrong. */
				if (jQuery.browser.safari) {
					expandX.each(function() {
						jQuery(this).css('width', '100%');
					});
				} else {
					var width = jQuery(this).innerWidth();
					expandX.each(function() {
						var w = width
							- jQuery(this).outerWidth()
							+ jQuery(this).innerWidth();
						jQuery(this).css('width', w + 'px');
					});
				}
			}

			/* Loop over children */
			return jQuery(this).children().autofit();
		});
	},
	loadHelp: function(file) {
		var helpNode = this;
		if (file == undefined) {
			file = jQuery.cookie('helpFile');
			if (null == file) {
				file = urlHelpRoot;
			}
		}

		jQuery.cookie('helpFile', file, {path: '/'});
		helpNode.load(file, { _overlay : false }, function() {
			jQuery('a.help', helpNode).click(function() {
				helpNode.loadHelp(this.href);
				return false;
			});
		});
	}
});

/**
 * Override the ajax call as everything ajax gets run through here...
 * We can add in a check to make sure we are logged in, an all the auto data
 * handling here.
 */
jQuery._bazAdmin.ajax = jQuery._bazAdmin.ajax || jQuery.ajax;
jQuery.extend({

	popupCount: 0,
	popupActiveList: [],

	/**
	 * Creates a popup window.
	 *
	 * @param string msg - this is what will be displayed in the popup.  If no
	 *    message is defined, it will display the 'Please Wait' loading screen
	 * @param boolean showOverlay - this can be used to turn the overlay effect
	 *    off.  It will be shown by default.
	 * @param function callback - this is a function that will be executed when
	 *    the popup is removed.
	 */
	addPopup: function(msg, showOverlay, callback) {

		var pId = jQuery.popupCount++;
		var zIndex = 0;
		var wWidth = jQuery(window).innerWidth();
		var wHeight = jQuery(window).innerHeight();
		
		/* Figure out what is the current highest popup */
		jQuery('div.popup').each(function() {
			if (!isNaN(jQuery(this).css('z-index'))) {
				zIndex = Math.max(zIndex, jQuery(this).css('z-index'));
			}
		});

		/* Create overlay and popup */
		jQuery('body').append(
			'<div id="_o'+pId+'" class="overlay"></div>' +
			'<div id="_p'+pId+'" class="popup wait"></div>'
		);

		var popup = jQuery('#_p'+pId);
		var overlay = jQuery('#_o'+pId);

		/* If this popup has content, add it and remove the wait class */
		if (msg && msg != undefined) {

			var waitPopup = false;
			if (jQuery.browser.mozilla && showOverlay) {
				var waitPopup = jQuery.addPopup();
			}

			popup.html(msg).removeClass('wait').setupAjaxLinks();

			/* Attach close events to close links etc... */
			jQuery('a.close,input.close', popup).click(function() {
				popup.remove();
				return false;
			});
			jQuery('form.close', popup).submit(function() {
				/* TODO: add something to submit the form maybe */
				popup.remove();
				return false;
			});

			/* Attach hide events to hide links etc... */
			jQuery('a.hide,input.hide', popup).click(function() {
				popup.hide();
				return false;
			});

		} else if (showOverlay) {
			popup.html('<div style="text-align: center">Please Wait</div>');
		}

		/**
		 * Juggle overlays so that we only ever have 1 at a time on the top
		 * level. also remove multiple popups if it is the waiting popup
		 */
		if (showOverlay) {
			jQuery('div.overlay:visible').not('#_o'+pId).each(function()
			{
				var o = this;
				jQuery(o).hide();
				jQuery('#_p'+pId).bind('remove', function() {
					jQuery(o).show();
				});
			});
			jQuery('div.popup:visible').not('#_p'+pId).each(function()
			{
				if (jQuery(this).is('div.wait')) {
					var p = this;
					jQuery(p).hide();
					jQuery('#_p'+pId).bind('remove', function() {
						jQuery(p).show();
					});
				}
			});

			/* Size and position the overlay and popup */
			overlay.css({
				'display'	: 'block',
				'position'	: 'absolute',
				'width'		: '100%',
				'height'	: Math.max($(window).height(), $('body').height()),
				'top'		: 0,
				'left'		: 0,
				'z-index'	: zIndex + 99,
				'opacity'	: 0.75,
				'background-color'	: '#999'
			});
		}

		popup.css({
			'display'	: 'block',
			'position'	: 'absolute'
		});

		/* Top/left placement */
		popup.css({
			'top'		: Math.floor($(window).scrollTop() + ((wHeight - popup.height())/2))+'px',
			'left'		: ((wWidth - popup.width())/2)+'px',
			'z-index'	: zIndex + 100
		});

		popup.autofit();

		/* Add event binding to remove the overlay when the popup is removed */
		popup.bind('remove', function() {
			overlay.remove();
			if (typeof callback != 'undefined') {
				callback();
			}
		});

		/* Add hide event binding */
		popup.bind('hide', function() {
			jQuery('#_o'+pId).hide();
		});
		popup.bind('show', function() {
			jQuery('#_o'+pId).show();
		});

		/* Execute scripts and pull out styles if we need to */
		if (typeof msg != 'undefined') {
			/* add styles to header for safari */
			if (jQuery.browser.safari) {
				popup.find('style').appendTo('head');
			}

			if (waitPopup) {
				jQuery.removePopup(waitPopup);
			}
		}

		/* Add popup to active list and Increment the counter */
		jQuery.popupActiveList.push(pId);

		return pId;
	},

	hidePopup: function(pId) {
		// TODO: remove from the jQuery.popupActiveList
		jQuery('#_p'+pId).hide();
	},
	showPopup: function(pId) {
		// TODO: addfrom the jQuery.popupActiveList
		// TODO: bring to the top

		var popup = jQuery('#_p'+pId);

		var zIndex = 0;
		var wWidth = jQuery(window).innerWidth();
		var wHeight = jQuery(window).innerHeight();

		/* Figure out what is the current highest popup */
		jQuery('div.popup').each(function() {
			if (!isNaN(jQuery(this).css('z-index'))) {
				zIndex = Math.max(zIndex, jQuery(this).css('z-index'));
			}
		});

		/* Top/left placement */
		popup.css({
			'top'		: Math.floor($(window).scrollTop() + ((wHeight - popup.height())/2))+'px',
			'left'		: ((wWidth - popup.width())/2)+'px',
			'z-index'	: zIndex + 100
		});
		
		popup.show();
	},

	/**
	 * safely remove a popup dialog.
	 */
	removePopup: function(pId) {
		if (typeof pId == 'undefined') {
			pId = jQuery.popupActiveList.pop();
		}

		var popup = jQuery('#_p'+pId);

		// check for any tinyMCE boxes and remove them properly... otherwise
		// bad things can happen
		jQuery('textarea.mceEditor', popup).each(function() {
			tinyMCE.execCommand('mceRemoveControl', false, this.id);
		});
		
		popup.remove();
	},

	/* Figure out what the most recent popup is so that we can do something
	 * with it */
	getLastPopupId: function() {
		if (jQuery.popupActiveList.length) {
			return jQuery.popupActiveList[jQuery.popupActiveList.length-1];
		}
	},

	/**
	 * s.url : only needs to be the ajax action to execute
	 *
	 * Extra options:
	 *    s.target   : target #ID for response.
	 *    s.response : none|replace|prepend|append (default=replace).
	 */
	ajax: function(s) {

		/* Load default settings */
		s = jQuery.extend({}, jQuery.ajaxSettings, s);

		/* Prepend ajax root path if it is not an absolute url */
		s.action = s.url;
		if (!s.url.match(/^(http|https):\/\//)) {
			s.url = URL_CMSROOT + 'ajax/' + s.url;

		} else {
			// check the protocol being requested.  may have retrieved https
			// out of a cookie but currently be on a http page -- resulting in
			// a 'Permission denied to call method XMLHttpRequest.open' error.
			var proto = URL_CMSROOT.match(/^https?:/i);
			if (proto) s.url = s.url.replace(/^https?:/i, proto);
		}

		/* extract extra data information */
		var extraData = jQuery._param(s.url);
		if (s.data && typeof s.data == 'object') {
			extraData = jQuery.extend(extraData, s.data);
		} else {
			extraData = jQuery.extend(jQuery._param(s.data), extraData);
		}
		
		if (extraData.ajaxType != undefined) s.dataType = extraData.ajaxType;
		if (extraData._target != undefined) s.target = extraData._target;
		if (extraData._response != undefined) s.response = extraData._response;
		if (extraData._overlay != undefined)
			s.overlay = (extraData._overlay && 'true' == extraData._overlay);

		/* Default to type HTML if not specified */
		if (s.dataType == undefined || s.dataType.toLowerCase() == 'html') {
			s.dataType = 'rawhtml';
		}

		/* Default to showing the overlay/loading text */
		if (s.overlay == undefined) s.overlay = true;

		/**
		 * Append extra data to the query string or data depending on what is
		 * currently in data.
		 *
		 * (ie.. if data is a string then append extra information to the url
		 * as data may be XML or something else that is not a query string.  If
		 * data is not a string, then it is an object of data being passed in
		 * that we can just append to).
		 */
		if (extraData.ajaxType != undefined) {
			extraData = { ajaxSrc : location.href };
		} else {
			extraData = {
				ajaxSrc		: location.href,
				ajaxType	: ('rawhtml' == s.dataType) ? 'html' : s.dataType
			};
		}
		if (s.data && typeof s.data == 'object') {
			s.data = jQuery.extend(s.data, extraData);
		} else {
			if (s.url && s.url.indexOf) {
				s.url += ((s.url.indexOf("?") > -1) ? "&" : "?")
					+ jQuery.param(extraData);
			}
		}

		/**
		 * Setup popup/overlay
		 */
		if (typeof s._popupId != 'undefined') {
			jQuery.removePopup(s._popupId);
		}
		s._popupId = jQuery.addPopup(null, s.overlay);

		/* Append our own default handling to the success callback function. */
		s._baz_success = s.success;
		s.success = function(msg) {
			/* Automatic handling of the response */
			switch (s.dataType.toLowerCase()) {
				case 'xml':
				case 'json':
				case 'script':
					/* Call origional success method */
					if (typeof s._baz_success == 'function') {
						s._baz_success(msg);
					}
					jQuery.removePopup(s._popupId);
					break;

				/**
				 * If the response is html, it should be appended/replaces etc
				 * to the target location.
				 */
				case 'html':
				case 'rawhtml':
				default:
					// if a target ID is set, place the response html into the
					// target location.
					if (s.target) {
						switch (s.response) {
							case 'none':
								break;
							case 'prepend':
								jQuery('#'+s.target).prepend(msg);
								break;
							case 'append':
								jQuery('#'+s.target).append(msg);
								break;
							default:
								jQuery('#'+s.target).html(msg);
								break;
						}

						/* add styles to header for safari */
						if (jQuery.browser.safari) {
							jQuery('<div>').html(msg).find('style')
								.appendTo('head');
						}

						if (s.target) {
							jQuery('#'+s.target).setupAjaxLinks();
						}

					/**
					 * If no target location is set, and the response type is
					 * not set to 'none' (ie. ignore), then treat the response
					 * as a popup.
					 */
					} else if ('none' != s.response && -1 != msg.search(/\S/)) {

						jQuery.removePopup(s._popupId);
						s._popupId = jQuery.addPopup(msg, s.overlay, s._login);
					}

					/* Call origional success method */
					if (typeof s._baz_success == 'function') {
						s._baz_success(msg);
					}

					/* Remove popup waiting message and overlay if we haven't
					 * produced a popup */
					if (s.target
						|| 'none' == s.response
						|| -1 == msg.search(/\S/))
					{
						jQuery.removePopup(s._popupId);
					}
					break;
			}
		}

		/**
		 * Append our own default handling to the error handling.
		 * Account for 401 (Unauthorized) responses.
		 */
		s._baz_error = s.error;
		s.error = function(xml, status, e) {

			if (e) {
			}

			switch (xml.status) {
				/**
				 * Note: We need to use 403 rather than 401 if we want to get
				 * opera to work properly.
				 */
				case 401:
				case 403:
					// not logged in.
					jQuery.ajax({
						type	: 'POST',
						url		: 'AdminLogin',
						_login	: function() {
							jQuery.ajax(s);
						}
					});
					// stop any further error handling here.
					break;

				case 450:
					if (typeof s._baz_error != 'undefined') {
						s._baz_error(xml, status, e);
					} else {
						alert('AJAX: ' + xml.statusText);
					}
					break;

				case 404:
					// action not found.
					alert('Ajax Command Failed');
					// fall through to error handler

				default:
					if (typeof s._baz_error != 'undefined') {
						s._baz_error(xml, status, e);
					}
					break;
			}
			/* remove the overlay if this was not a success */
			if (200 !== xml.status && typeof s._popupId != 'undefined') {
				jQuery.removePopup(s._popupId);
			}
		}

		$._bazAdmin.ajax.apply(this, arguments);
	}
});
// jQuery 1.3.x also overrides load() with an alias of _load
jQuery._bazAdmin.load = jQuery._bazAdmin.load || jQuery.fn.load;
jQuery.fn.extend({
	load: function(url, params, callback, ifModified) {
		if (url && url.indexOf) {
			url += ((url.indexOf("?") > -1) ? "&" : "?") + '_response=none';
		}
		$._bazAdmin.load.apply(this, arguments);
	}
});

jQuery.extend({
	dechex: function(dec) {
		return ((dec < 16) ? "0" : "") + dec.toString(16);
	},
	zebraDecay: function(x) {
		return parseInt(Math.max(x - 16, 0, x * 0.8));
	}
});
jQuery.fn.extend({
	// highlight alternative table rows
	applyZebra: function() {
		if (jQuery(this).hasClass('noZebra')) return;
		
		jQuery('tr:nth-child(odd)', this).each(function(){
			var row = jQuery(this);
				
			if (row.hasClass('odd') || row.hasClass('even')) return true;
			
			var rowBg = row.css('background-color');
			
			// TODO: determine which browsers will say if tds are transparent
			// and allow us skip processing those tds
			row.children('td').each(function(){
				
				var cell = jQuery(this);
					
				if (cell.hasClass('footer') || cell.hasClass('noZebra')) return true;
					
				var r=-1, g=-1, b=-1;
				
				// get colour from cell
				var oc = cell.css('background-color');
				if (typeof oc=="undefined" || oc == "transparent" || oc == 'rgba(0, 0, 0, 0)') {
					// try to get colour from row
					oc = rowBg;
				}
				if (typeof oc=="undefined" || oc == "transparent" || oc == 'rgba(0, 0, 0, 0)') {
					r = g = b = 255;
					
				} else {
					
					if (oc.length == 4 && oc.substr(0,1) == '#') { // handle short values
						oc = "#"+oc.charAt(1)+oc.charAt(1)+oc.charAt(2)+
							oc.charAt(2)+oc.charAt(3)+oc.charAt(3);
					}
					if (oc.length == 7 && oc.substr(0,1) == '#') {
						r=parseInt(oc.substr(1,2),16);
						g=parseInt(oc.substr(3,2),16);
						b=parseInt(oc.substr(5,2),16);
				
					} else if (oc.substr(0,4) == 'rgb(') {
						var rgb = oc.substr(4,oc.length-5).split(",");
						r = rgb[0];
						g = rgb[1];
						b = rgb[2];
					} else {
						/* if it's a named colour, we don't know how to interpret it
						*  so will do nothing to it
						*
						*  Note that Firefox will store named colours as their RGB values
						*  but IE & opera won't
						*/
						//alert(oc);
					}
				}
				
				if (r >= 0 && g >= 0 && b >= 0) {
					// get darker colour from original
					r = jQuery.zebraDecay(r);
					g = jQuery.zebraDecay(g);
					b = jQuery.zebraDecay(b);
					cell.css('background-color', "#"+jQuery.dechex(r)+jQuery.dechex(g)+jQuery.dechex(b));
				}
			});
		});
	}
});

$(function() {
	$('body').setupAjaxLinks();
	
	// zebra-ise tables with class data
	$('table.data').applyZebra();
});

// vim: syntax=javascript st=4 ts=4 sw=4 tw=79
