
	Dialog = Class.create();
	Object.extend(Dialog,
	{
		responders : $A([]),
		overlay : false,
		container : false,
		current : false,
		IE : false,
		targetRegexp : /#(.+)$/,
		imgRegexp : /\.(jpe?g|gif|png|tiff?)$/,
	
		overlayStyles :
		{
			position : 'absolute',
			top : 0,
			left : 0,
			zIndex : 9998
		},
	
		load : function()
		{
			Dialog.IE = (navigator.appName == 'Microsoft Internet Explorer');
			Dialog.overlay = $(document.createElement('div'));
			Dialog.overlay.id = 'modal_overlay';
			Object.extend(Dialog.overlay.style, Dialog.overlayStyles);
			Dialog.overlay.hide();
			Dialog.container = $(document.createElement('div'));
			Dialog.container.id = 'modal_container';
			Dialog.container.hide();
			document.getElementsByTagName('body')[0].appendChild(Dialog.overlay);
			document.getElementsByTagName('body')[0].appendChild(Dialog.container);
		},
	
		close : function()
		{
			if(Dialog.current)
				Dialog.current.close();
		},
	
		attachEvents : function()
		{
			Event.observe(window,'load',Dialog.load);
			Event.observe(window,'unload',Event.unloadCache,false);
		},
	
		center : function()
		{
			element = this.container;
			if(!element._centered)
			{
				this.container.setStyle({position : 'absolute'});
				this.container._centered = true;
			}
			dimensions = Dialog.container.getDimensions();
			Position.prepare();
			offset_left = (Position.deltaX + Math.floor((Dialog.getWindowWidth() - dimensions.width) / 2));
			offset_top = (Position.deltaY + Math.floor((Dialog.getWindowHeight() - dimensions.height) / 2));
			modal_dimensions = Dialog.container.getDimensions();
			Dialog.container.setStyle(
			{
				top : ((modal_dimensions.height <= Dialog.getWindowHeight()) ? ((offset_top != null && offset_top > 0) ? offset_top : '0') + 'px' : 0),
				left : ((modal_dimensions.width <= Dialog.getWindowWidth()) ? ((offset_left != null && offset_left > 0) ? offset_left : '0') + 'px' : 0)
			});
		},
	
		getWindowWidth : function()
		{
			return (self.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0);
		},
	
		getWindowHeight : function()
		{
			return (self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0);
		},
	
		getDocumentWidth : function()
		{
			return Math.max(document.body.scrollWidth,Dialog.getWindowWidth());
		},
	
		getDocumentHeight : function()
		{
			return Math.max(document.body.scrollHeight,Dialog.getWindowHeight());
		},
	
		onKeyDown : function(event)
		{
			if(event.keyCode == Event.KEY_ESC)
				Dialog.close();
		},
	
		addResponder : function(responder)
		{
			Dialog.responders.push(responder);
		},
	
		removeResponder : function(responder)
		{
			Dialog.responders = Dialog.responders.without(responder);
		},
	
		//from Scriptaculous
		setOpacity : function(element, value)
		{
			element = $(element);
			if(value == 1)
			{
				Element.setStyle(element,
				{
					opacity : (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : null
				});
	
				if(/MSIE/.test(navigator.userAgent))
				{
					Element.setStyle(element,
					{
						filter : Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')
					});
				}
			}
			else
			{
				if(value < 0.00001) value = 0;
				Element.setStyle(element, {opacity: value});
				if(/MSIE/.test(navigator.userAgent))
				{
					Element.setStyle(element,
					{
						filter : Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + 'alpha(opacity='+value*100+')'
					});
				}
			}
		}
	});
	
	Object.extend(Dialog.prototype,
	{
		mode : '',
		html : false,
		href : '',
		link : false,
		src : false,
		imageLoaded : false,
		initialize : function(link, options)
		{
			this.link = $(link);
			this.options = $H({
				beforeOpen : Prototype.emptyFunction,
				afterOpen : Prototype.emptyFunction,
				beforeClose : Prototype.emptyFunction,
				afterClose : Prototype.emptyFunction,
				beforeLoad : Prototype.emptyFunction,
				onLoad : Prototype.emptyFunction,
				onFailure : Prototype.emptyFunction,
				onException : Prototype.emptyFunction,
				afterLoad : Prototype.emptyFunction,
				beforeImageLoad : Prototype.emptyFunction,
				afterImageLoad : Prototype.emptyFunction,
				contents : false,
				image : false,
				imageTemplate : new Template('<img src="#{src}" id="#{id}"/>'),
				imageAutoDisplay : true,
				imageCloseOnClick : true,
				hover : false,
				iframe : false,
				iframeTemplate : new Template('<iframe src="#{href}" width="100%" height="100%" frameborder="0" id="#{id}"></iframe>'),
				evalScripts : true, //for Ajax, define here instead of in requestOptions
				requestOptions : {}, //for Ajax.Request
				overlayClassName : '',
				containerClassName : '',
				opacity : 0.3,
				zIndex : 9998,
				width : null,
				height : null,
				offsetLeft : 0, //for use with 'relative'
				offsetTop : 0, //for use with 'relative'
				position : 'absolute' //'absolute' or 'relative'
			}).merge(options || {});

			target_match = Dialog.targetRegexp.exec(link.href);
			image_match = Dialog.imgRegexp.exec(link.href);

			if(this.options.contents)
			{
				this.mode = 'contents';
			}
			else if(this.options.image || image_match)
			{
				this.mode = 'image';
				this.src = link.href;
			}
			else if(target_match)
			{
				this.mode = 'named';
				x = $(target_match[1]);
				this.html = x.innerHTML;
				x.remove();
				this.href = target_match[1];
			}
			else
			{
				this.mode = (this.options.iframe) ? 'iframe' : 'ajax';
				this.href = link.href;
			}

			if(link)
			{
				link.onclick = function()
				{
					this.open();
					return false;
				}.bindAsEventListener(this);
			}

			targets = Dialog.targetRegexp.exec(window.location);
			this.position = function(){
				Dialog.overlay.setStyle({
					height : Dialog.getDocumentHeight() + 'px',
					width : Dialog.getDocumentWidth() + 'px'
				});
				if(this.options.position == 'absolute')
					Dialog.center();
				else{
					yx = Position.cumulativeOffset(this.link);
					Dialog.container.setStyle({
						position : 'absolute',
						top : yx[1] + this.options.offsetTop,
						left : yx[0] + this.options.offsetLeft
					});
				}
			}.bind(this);

			if(this.mode == 'image')
			{
				this.afterImageLoad = function()
				{
					if(this.options.imageAutoDisplay && !window.opera)
					{
						$('modal_image').show();
					}
					this.position();
					this.notifyResponders('afterImageLoad');
				}.bind(this);
			}
			if(this.options.hover)
			{
				this.link.observe('mouseover',this.open.bind(this));
				this.link.observe('mouseout',this.close.bind(this));
			}

			if(this.mode == 'named' && targets && targets[1] && targets[1] == this.href)
			{
				this.open();
			}
		},

		open : function()
		{
			if(!this.options.hover)
			{
				Event.observe($(document.getElementsByTagName('body')[0]),'keydown',Dialog.onKeyDown);
			}

			Dialog.current = this;
			this.notifyResponders('beforeOpen');

			if(!this.options.hover)
			{
				Dialog.overlay.setStyle(
				{
					zIndex : this.options.zIndex
				});
				Dialog.setOpacity(Dialog.overlay,this.options.opacity);
			}

			Dialog.container.setStyle(
			{
				zIndex : this.options.zIndex + 1,
				width : (this.options.width ? this.options.width + 'px' : ''),
				height : (this.options.height ? this.options.height + 'px' : '')
			});

			if(Dialog.IE && !this.options.hover)
			{
				$$('select').invoke('setStyle', {visibility : 'hidden'});
			}

			Dialog.overlay.addClassName(this.options.overlayClassName);
			Dialog.container.addClassName(this.options.containerClassName);
			switch(this.mode)
			{
				case 'image':
					this.imageLoaded = false;
					this.notifyResponders('beforeImageLoad');
					this.update(this.options.imageTemplate.evaluate({src : this.src, id : 'modal_image'}));
					this.position();
					if(this.options.imageAutoDisplay && !window.opera)
					{
						$('modal_image').hide();
					}
					if(this.options.imageCloseOnClick)
					{
						$('modal_image').observe('click',Dialog.close);
					}
					$('modal_image').observe('load',this.afterImageLoad);
					$('modal_image').observe('readystatechange',this.afterImageLoad);
					break;

				case 'ajax':
					this.notifyResponders('beforeLoad');
					new Ajax.Request(this.href, $H({

						method : 'get',

						onSuccess : function(request)
						{
							this.notifyResponders('onLoad',request);
							this.update(request.responseText);
							if(this.options.evalScripts)
							{
								request.responseText.evalScripts();
							}
							this.notifyResponders('afterLoad',request);
						}.bind(this),

						onFailure : this.options.onFailure,

						onException : this.options.onException
					}).merge(this.options.requestOptions));
					break;

				case 'iframe':
					this.update(this.options.iframeTemplate.evaluate({href : this.href, id : 'modal_iframe'}));
					this.position();
					break;

				case 'contents':
					this.update((typeof(this.options.contents) == 'function' ? this.options.contents.bind(this)() : this.options.contents));
					break;

				case 'named' :
					this.update(this.html);
					break;
			}

			if(!this.options.hover)
			{
				Dialog.overlay.observe('click',Dialog.close);
				Dialog.overlay.show();
			}
			this.options.afterOpen();
		},

		update : function(html)
		{
			Dialog.container.update(html);
			this.position();
			Dialog.container.show();
			Event.stopObserving(window,'resize',this.position,false);
			Event.stopObserving(window,'scroll',this.position,false);
			Event.observe(window,'resize',this.position,false);
			Event.observe(window,'scroll',this.position,false);
		},

		close : function()
		{
			response = this.notifyResponders('beforeClose');

			if(response == false && response != null)
			{
				return;
			}

			if(this.mode == 'image')
			{
				if(this.options.imageCloseOnClick)
					$('modal_image').stopObserving('click',Dialog.close);
				$('modal_image').stopObserving('load',this.afterImageLoad);
				$('modal_image').stopObserving('readystatechange',this.afterImageLoad);
			}

			if(Dialog.IE && !this.options.hover)
			{
				$$('select').invoke('setStyle',{visibility : 'visible'});
			}

			if(!this.options.hover)
			{
				Event.stopObserving(window,'keyup',Dialog.onKeyDown);
			}

			Dialog.current = false;
			Dialog.overlay.removeClassName(this.options.overlayClassName);
			Dialog.container.removeClassName(this.options.containerClassName);
			Event.stopObserving(window,'resize',this.position,false);
			Event.stopObserving(window,'scroll',this.position,false);

			if(!this.options.hover)
			{
				Dialog.overlay.stopObserving('click',Dialog.close);
				Dialog.overlay.hide();
			}

			Dialog.container.update('');
			Dialog.container.hide();
			this.notifyResponders('afterClose');
		},

		notifyResponders : function(event_name,argument)
		{
			Dialog.responders.each(function(responder)
			{
				if(responder[event_name])
				{
					responder[event_name](argument);
				}
			});

			response = this.options[event_name](argument);
			return response;
		}
	});

	Dialog.attachEvents();
