PAMWF.Dialog = Class.create({
	/**
	 * Div that holds the dialog whether or not it is present in the DOM
	 *
	 * @var htmlobject
	 */
	_div: null,
	
	/**
	 * Class that is managing whatever form is in the dialog.
	 *
	 * @var object
	 */
	_form: null,
	
	/**
	 * Datagrid class present in the dialog (if any)
	 *
	 * @var object
	 */
	_grid: null,
	
	/**
	 * Div that masks the rest of the screen to draw focus to the dialog.
	 *
	 * @var htmlobject
	 */
	_mask: null,
	
	/**
	 * Calling class if any (this is the "parent")
	 *
	 * @var object
	 */
	_parent: null,
	
	/**
	 * Listener function for the close events.
	 *
	 * @var function (when active, inited null)
	 */
	_closeListener: null,
	
	/**
	 * Tooltips in the dialog, if any
	 *
	 * @var array
	 */
	_tips: new Array(),

	/**
	 * Settings of the dialog. PHP may alter these with a json header.
	 */
	_settings: {
		useMask: true,
		transitionTime: 0.3,
		maskOpacity: 0.5,
		draggable: true,
		fields: null
	},
	
	/**
	 * Flag to prevent removal of the dialog div on end of dialog - used for
	 * preloaded dialogs.
	 */
	_noRemoval: false,
	
	/**
	 * CONSTRUCT method.
	 * We accept either a div or url as an argument. If given a div we will pop
	 * it up as a dialog and destroy it afterward. This is primarily used for
	 * page launch messages such as 404 errors.
	 *
	 * If given a URL we will launch an ajax request for the div to display.
	 *
	 * @param target mixed (URL or DIV)
	 * @param parent object class that is launching this dialog - usually a grid object.
	 */
	initialize: function ( target, parent )
	{
		// Lock in the parent that called us if applicable.
		if (parent && typeof(parent) == 'object')
		{
			this._parent = parent;
			this._parent._requestInProgress = true;
		}
		
		// Create a close listener.
		this._closeListener = this._close.bindAsEventListener(this);
		
		// Now get our div.
		if ($(target)) // reference to a div already present in the dom, show it.
		{
			// We remove this first, the show method reinserts at document end.
			this._div = $(target).remove();
			this._noRemoval = true;
			this._settings.draggable = false;
			this._show();
		}
		else // Assume target is a url - attempt to fetch it.
		{
			new Ajax.Request( target, {
				method: 'get',
	  			onSuccess: this._success.bindAsEventListener(this),
				onFailure: this._failure.bindAsEventListener(this)
			});
		}
	},
	
	/**
	 * Responder to the ajax request for the div used when the request succeeds.
	 *
	 * @param object httpXMLRequest object
	 */
	_success: function (t)
	{	
		// Fetch PHP's response javascript, if any.
		try
		{
			var scripts = t.responseXML.getElementsByTagName('javascript');
		}
		catch ( e )
		{
			PAMWF.console.log( 'No javascript included in response.');
		}
		
		// Try to eval it.
		try
		{
			eval(scripts[0].firstChild.nodeValue);
		}
		catch ( e )
		{
			PAMWF.console.warn( 'Included Javascript failed to parse!');
			PAMWF.console.dir( e );
		}
		
		// Notify the parent the request has finished (if there is a parent).
		if(this._parent)
		{
			this._parent._requestInProgress = false;
		}

		// Load the div
		try
		{
			var response = t.responseXML.getElementsByTagName('response');
			this._div = new Element('div').update(response[0].firstChild.nodeValue);
			this._div = this._div.down();		
		}
		catch (e)
		{
			PAMWF.console.error('Invalid or non-existant XML response');
		}
		
		this._show();
	},
	
	/**
	 * Show the dialog and if necessary it's mask, plus set up the behaviors
	 * of the dialog
	 */
	_show: function()
	{
		// Create the mask if required.
		if ( this._settings.useMask )
		{
			this._mask = PAMWF.drawMask(false);
		}
		
		// Now write the div into the dom.
		$$('BODY')[0].insert({bottom: this._div});

		// Hide and Center it up
		this._div.center( 50, 50 );
		this._div.hide();
		
		// Appear them.
		new Effect.Appear(this._mask, 
			{duration: this._settings.transitionTime, from:0.0, to: this._settings.maskOpacity }, 
			{queue: {position:'end', scope: this._div.identify() }}
		);

		new Effect.Appear(this._div, 
			{duration: this._settings.transitionTime }, 
			{queue: {position:'end', scope: this._div.identify() }}
		);
		
		// Set object as draggable.
		if ( this._settings.draggable == true )
		{
			new Draggable(this._div);
		}
		
		// Register close listeners.
		this._div.select('.Close').each(function(s){
			Event.observe( s, 'click', this._closeListener);
		}.bindAsEventListener(this));
		
		// Activate Tooltips
		if (PAMWF.Tooltip)
		{
			this._div.select('.Tooltip').each(function(s){
				var a = s.ancestors();
				
				for (var i = 0; i<a.length; i++)
				{
					if (a[i].hasClassName('DataObject'))
					{
						return;
					}
				}
				
				this._tips.push(new PAMWF.Tooltip(s));
			}.bindAsEventListener(this));
		}
		
		this._afterShow();
	},
	
	/**
	 * Actions to take after dialog is shown. This is a placeholder,
	 * usually PHP will rewrite this function.
	 */
	_afterShow: function() {},
	
	/**
	 * Close event handler - check for unfinished business.
	 *
	 * @var event object
	 */
	_close: function ( event )
	{
		if (this._form && this._form._changed)
		{
			if( confirm( "You have made changes to this form. Are you sure you want to close it?"))
			{
				if (confirm ( "Do you want to save the changes now?"))
				{
					this._div.select('submit').click();
				}
				else
				{
					this._doClose();
				}
			}
		}
		else
		{
			this._doClose();
		}
	},
	
	/**
	 * Actually commit the close
	 */
	_doClose: function()
	{
		new Effect.Fade(this._div, {duration: this._settings.transitionTime }, {queue: {position:'end', scope: this._div.identify() }});
		new Effect.Fade(this._mask, {duration: this._settings.transitionTime, afterFinish: this.destroy.bindAsEventListener(this)}, {queue: {position:'end', scope: this._div.identify() }});
	},
	
	/**
	 * DESTRUCTOR method.
	 *
	 */
	destroy: function()
	{	
		// the mask
		if (this._mask)
		{
			this._mask.remove();
		}

		// any contained form.
		if (this._form)
		{
			this._form.destroy();
		}
		
		// any contained grid.
		if (this._grid)
		{
			this._grid.destroy();
		}
		
		// Destroy our div unless we loaded a div already in the page instead of an ajax request.
		if (!this._noRemoval)
		{
			this._div.remove();
		}
		
		// Have our parent destroy it's reference to us if we have a parent
		if (this._parent )
		{
			this._parent._clearDialog();
		}
		
		// Clear out our tips.
		this._tips.each(function(s) { s.destroy() });
	},
	
	/**
	 * Finally alert the user to a failure of the ajax call
	 */
	_failure: function (t) 
	{
		if (this._parent )
		{
			this._parent._requestInProgress = false;
		}
		
		alert(t.responseText);
	}
});