(function($) {
	$.customAlert = function(opts) {
		// options
		var options = $.extend({
			// main options
			html: '<div></div>', // the html of the alert box
			message: '', // what to put in the alert box as the message; can also be put into options.html
			messageContainer: false, // the container to append options.message to
			
			// animation options
			customAnimationOpen: false, // a custom animation to use when opening
			customAnimationClose: false, // a custom animation to use when closing
			
			// misc options
			z: 1000, // the z-index of the alert box will be 1 above this
			preventClicks: true, // will prevent the user from clicking on anything but the alert box
			closeOnClick: true, // will attempt to close the alert window when one of the option buttons are clicked; overrides each buttons' 'closeOnClick' option
			
			// custom positioning if it can't be set through css
			customTop: false,
			customLeft: false,
			
			// buttons
			buttons: false, // a default button will be set if one is not given; these can also be defined in the 'html' option
			buttonContainer: false
		}, opts);
		// the defaults to be used when the options aren't defined in the buttons
		var buttonDefaults = {
			html: '<input type="button" />', // the html of the button
			selector: false,
			container: false,
			closeOnClick: true // closes the alert when clicked; will be overridden by the main closeOnClick
		};
		var obj; // holds a reference to the alert box html
		var msg; // hold a reference to the message html
		var preventer; // holds the reference to the div that prevents clicks on the page while the alert is active
		
		// initiate the alert box, click preventer and actions
		function _init() {
			// create the click preventer if wanted
			if (options.preventClicks) {
				preventer = $('<div></div>');
				_setPreventer();
				preventer.prependTo('body');
			}
			
			// create the alert box
			obj = $(options.html).prependTo('body').hide();
			
			// if a message is passed, insert it in to the specified container or append it to the inside of the alert box if no container is given
			if (options.message)
				msg = (options.messageContainer) ? $(options.messageContainer).append(options.message) : obj.append(options.message);
			
			// if a className is set, use it
			if (options.className)
				obj.addClass(options.className);
			
			// if no button is set, create a default one
			if (!options.buttons) {
				options.buttons = {
					Ok: {}
				}
			}
			// for each button set its attributes and actions
			for (var i in options.buttons) {
				// set the default options for the button if they are undefined
				for (var bo in buttonDefaults)
					if (typeof(options.buttons[i][bo]) === 'undefined')
						options.buttons[i][bo] = buttonDefaults[bo];
				
				var b;
				if (options.buttons[i].selector)
					b = $(options.buttons[i].selector).click(_setClick(i));
				else if (options.buttons[i].container)
					b = $(options.buttons[i].html).appendTo(options.buttons[i].container).click(_setClick(i));
				else if (options.buttonContainer)
					b = $(options.buttons[i].html).appendTo(options.buttonContainer).click(_setClick(i));
				else
					b = $(options.buttons[i].html).appendTo(obj).click(_setClick(i));
				
				// check to see if the button is an input
				if (options.buttons[i].html.match(/<input.*>/)) {
					// if so set the value attribute if it is set
					if (!b.val())
						b.val(i);
				// otherwise assume we can set the html() of the element
				} else {
					// if the html option is set use that
					if (options.buttons[i].html)
						b.html(options.buttons[i].html);
					else // if not use the button's name
						b.html(i);
				}
			}
			
			// when the window is resized, reset positions
			$(window).resize(_setAll).scroll(_setAll);
		};
		
		// set the click actions
		// must be done this way due to an issue when using the .click(function() {}) in the for in loop
		function _setClick(i) {
			var returnFunc = function() {
				if (typeof(options.buttons[i].click) !== 'undefined') {
					options.buttons[i].click();
				}
				// if the buttons closeOnClick option is set to true, then close the alert
				if (options.buttons[i].closeOnClick) {
					_close();
				// if false, check to see if the main option for closing the alert when a button is clicked is set to true
				} else if (options.closeOnClick) {
					_close();
				}
			}
			return returnFunc;
		}
		
		// ALERT!!
		function _alert() {
			// setObj() is done because we need to set it's position after all of the text and things have been appended to it
			_setObj();
			
			if (options.customAnimationOpen)
				options.customAnimationOpen(obj);
			else
				obj.show();
		};
		
		// closes the alert box
		function _close() {
			if (options.customAnimationClose) {
				options.customAnimationClose(obj);
				obj.queue(function() {
					obj.remove();
				});
			} else
				obj.remove();
			preventer.remove();
			$(window).unbind('scroll', _setAll).unbind('resize', _setAll);
		}
		
		// sets the click preventer's position
		function _setPreventer() {
			if (preventer.length > 0) {
				preventer.width($.pageSize(0)).height($.pageSize(1)).css({
					backgroundColor: '#fff',
					opacity: 0,
					position: 'absolute',
					left: 0,
					top: 0,
					zIndex: options.z
				});
			}
		};
		
		// sets the alert box's position
		function _setObj() {
			var top, left;
			
			if (obj.length > 0) {
				if (isNaN(parseInt(obj.css('width'))))
					obj.width($.pageSize(2) / 2);
				
				if (options.customTop)
					top = options.customTop;
				else
					top = ($.pageSize(3) / 2) - (obj.height() / 2) + $.pageScroll('y');
					
				if (options.customLeft)
					left = options.customLeft;
				else
					left = ($.pageSize(2) / 2) - (obj.width() / 2) + $.pageScroll('x');
					
				obj.css({
					position: 'absolute',
					zIndex: options.z+1,
					'top': top,
					'left': left
				});
			}
		};
		
		// sets everything that might need to be set at one time; just a shortcut
		function _setAll() {
			_setPreventer();
			_setObj();
		};
		
		// calling these here make using this function easier
		_init(); // initiate
		_alert(); // and alert
	};
})(jQuery);