/**
 * Root form management class.  PHP needs to send the code that actually activates
 * this class as a part of the response to the javascript query for a dialog or
 * new row (or other event).
 */
PAMWF.Form = Class.create({
	/**
	 * Reference to the form element
	 */
	_form: null,
	
	/**
	 * Grid class associated with the form, if any.
	 */
	_grid: null,
	
	/**
	 * Dialog class associated with the form, if any.
	 */
	_dialog: null,
	
	/**
	 * Information about the fields on the form.
	 */
	_fields: null,
	
	/**
	 * Field that currently has focus.
	 */
	_hasFocus: null,
	
	/**
	 * Whether the form has changed.
	 */
	_changed: null,

	/**
	 * Input elements of the form.
	 */
	_inputs: new Array(),
	
	/**
	 * Missing Fields.
	 */
	_missingFields: new Array(),
	
	/**
	 * Required Fields
	 */
	_requiredFields: new Array(),
	
	/**
	 * Whether the form is executing a request.
	 */
	_requestInProgress: false,
	
	/**
	 * Errors encountered on the submit attempt.
	 */
	_errors: false,
	
	/**
	 * Listeners
	 */
	_listeners: {
		submit: null,
		change: null,
		succeed: null,
		fail: null,
		complete: null,
		focus: null
	},
	
	/**
	 * Form Observer
	 */
	_observer: null,
	
	
	/**
	 * CONSTRUCTOR
	 */
	initialize: function ( options )
	{
		// Set Options
		this._grid = options.grid;
		this._dialog = options.dialog;
		this._form = $(options.form);
		this._fields = $H(options.fields);
		
		// Build Listeners.
		this._buildListeners();
		
		// Observe for changes
		this._observer = new Form.Observer(this._form, 0.3, this._listeners.change );
		
		// Bind the submit observer
		Event.observe(this._form, 'submit', this._listeners.submit );
		
		// Gather the element names.
		this._form.getElements().each( function(s){ 
				this._inputs.push(s.name.split('[')[0]); 	
				Event.observe(s, 'focus', this._listeners.focus );
			}.bind(this));
		
		// Check for missing and required fields.
		this._fields.each( function(s){
			var fieldName = s[0];
			var fieldData = $H(s[1]);
			
			if (!this._inputs.include(fieldName) && !this._flashInputs.include(fieldName))
			{
				this._missingFields.push(fieldName);
			}
		
			if (fieldData.get('require') == true)
			{
				this._requiredFields.push(fieldName)
			}
			
		}.bind(this) );	
		
		// Throw alert to designer if in debug mode.
		if (this._missingFields.length > 0 && PAMWF.debug )
		{
			alert("DESIGNER ALERT! \n The following fields are missing: \n" + PAMWF.implode( this._missingFields ));
		}
						
		// Focus first field.
		this._form.focusFirstElement();
	},
	
	/**
	 * Build the event listeners.
	 */
	_buildListeners: function()
	{
		this._listeners.change = this.onChange.bindAsEventListener(this);
		this._listeners.submit = this._submit.bindAsEventListener(this);
		this._listeners.focus = this._registerFocus.bindAsEventListener(this);
		
		this._listeners.succeed = this._submitSuccess.bindAsEventListener(this);
		this._listeners.fail = this._submitFailure.bindAsEventListener(this);
		this._listeners.complete = this._submitComplete.bindAsEventListener(this);
	},
	
	/**
	 * On change event (called by the form observer)
	 */
	onChange: function( form )
	{ 
		this._hasFocus.removeClassName('error');
		this._changed = true; 
	},
	
	/**
	 * On focus event
	 */
	_registerFocus: function ( e )
	{
		this._hasFocus = e.element();
	},
	
	/**
	 * Check to see if any requests are in progress
	 * Question posed to this function: "Are there no requests in progress?"
	 *
	 * @return boolean
	 */
	_checkRequests: function()
	{
		// YES - alert the user then send false back to the calling function.
		if ( this._requestInProgress )
		{
			alert('Waiting to resolve a prior request with the server. Please be patient.');
			return false;
		}
		// No - set the request in progress flag true, then return true to the calling function
		else
		{
			this._requestInProgress = true
			return true;
		}
	},
	
	/**
	 * Submit event
	 */
	_submit: function ( e )
	{	
		Event.stop(e);
		
		if ( this._checkRequests() && this._validate() )
		{
			this._form.request({ 
				onSuccess: this._listeners.succeed,
				onFailure: this._listeners.fail,
				onComplete: this._listeners.complete
			});					
		}
		else
		{
			this._requestInProgress = false;
		}
	},
	
	/**
	 * Validate the form.
	 *
	 * @return boolean
	 */
	_validate: function()
	{
		// Reset error count.
		this._errors = false;
		
		// Search Required.
		this._form.getElements().each( function(s) {
			if (this._requiredFields.include(s.name) && s.value == '' )
			{
				s.addClassName('error');
				this._errors = true;
			}
		}.bind(this));
		
		if (this._errors)
		{
			alert("One or more fields, now highlighted in red, have missing or incorrect information. Please correct those fields and try again.");
			this._errors = false;
			return false;
		}
		else
		{
			return true;
		}
	},
	
	/**
	 * Success response
	 */
	_submitSuccess: function (t)
	{
		this._changed = false;
		
		// Now update the grid.
		if (this._grid)
		{
			this._grid._parseRow( t );
		}
		
		// And close the dialog
		if (this._dialog)
		{
			this._dialog._close();
		}
	},
	
	/**
	 * Failure response
	 */
	_submitFailure: function (t)
	{
		alert(t.responseText);
	},
	
	/**
	 * Completion. Actions here are performed regardless of success or failure
	 */
	_submitComplete: function (t)
	{
		this._requestInProgress = false;
	},
	
	destroy: function()
	{
		this._observer.stop();
		Event.stopObserving(this._form, 'submit', this._listeners.submit );
		this._form.getElements().invoke( 'stopObserving', 'focus', this._listeners.focus );
	}
});