if (Object.isUndefined(s3core))throw 's3core.wizard is part of the s3core libraray. s3core.js must be loaded first.';
s3core.wizard=Class.create
(
	{
		valid:			true,
		errorMsgCount:	0,
		config:
		{
			form:		false,
			pages:		[],
			start:		false
		},
		page:
		{
			first:		0,
			last:		0,
			current:	0
		},
		btnText:
		{
			cancel:		'Cancel',
			back:		'Back',
			next:		'Next',
			submit:		'Submit'
		},
		hasBtn:
		{
			cancel:		false,
			back:		false,
			next:		false,
			submit:		false
		},
		initialize: function(config)
		{
			//Set config.
			this.config=Object.extend(this.config,config);
			//Grab the form.
			this.config.form=$(this.config.form);
			if (this.config.pages.length===1)
			{
				this.config.pages=this.config.pages.collect
				(
					function(element)
					{
						return $(element);
					}
				);
			}
			else
			{
				/* Grab all the pages.
				 * Hide them all.
				 * Show the starting page.
				 */
				(this.config.pages=this.config.pages.collect
				(
					function(element)
					{
						return $(element);
					}
				).invoke('hide')).find
				(
					function(element)
					{
						if (element.identify()==this.config.start)
						{
							return true;
						}
						return false;
					}.bind(this)
				).show();
				//Setup the page object.
				this.page.last=this.config.pages.length-1;
				for (var i=0; i<this.config.pages.length; i++)
				{
					if (this.config.pages[i].identify()==this.config.start)
					{
						this.page.current=i;
						break;
					}
				}
			}
			//Check button-text values are consistent with this.btnText (default) values.
			if ($('wizard_cancel'))
			{
				this.hasBtn.cancel=true;
				if ($F('wizard_cancel') && this.btnText.cancel != $F('wizard_cancel')) this.btnText.cancel = $F('wizard_cancel');
				else if (!$F('wizard_cancel')) $('wizard_cancel').value=this.btnText.cancel;
			}
			if ($('wizard_back'))
			{
				this.hasBtn.back=true;
				if ($F('wizard_back') && this.btnText.back != $F('wizard_back')) this.btnText.back = $F('wizard_back');
				else if (!$F('wizard_back')) $('wizard_back').value=this.btnText.back;
			}
			if ($('wizard_next'))
			{
				this.hasBtn.next=true;
				if ($F('wizard_next') && this.btnText.next != $F('wizard_next')) this.btnText.next = $F('wizard_next');
				else if (!$F('wizard_next')) $('wizard_next').value=this.btnText.next;
			}
			if ($('wizard_submit'))
			{
				this.hasBtn.submit=true;
				if ($F('wizard_submit') && this.btnText.submit != $F('wizard_submit')) this.btnText.submit = $F('wizard_submit');
				else if (!$F('wizard_submit')) $('wizard_submit').value=this.btnText.submit;
			}
			//Setup Buttons.
			this.setButtonStates();
			//Bind events to buttons.
			if (this.hasBtn.submit) $('wizard_submit').observe('click',this.button_submit.bindAsEventListener(this));
			if (this.hasBtn.next) $('wizard_next').observe('click',this.button_next.bindAsEventListener(this));
			if (this.hasBtn.back) $('wizard_back').observe('click',this.button_back.bindAsEventListener(this));
			if (this.hasBtn.cancel) $('wizard_cancel').observe('click',this.button_cancel);
			//Bind the submit event to form so that we can check whether at the last page of the form.
			this.config.form.observe('submit',this.form_submit.bindAsEventListener(this));
			this.errorMsgCount=0;
			return;
		},
		setError: function(theElement,theMessage)
		{
			this.valid=false;
			theElement=$(theElement);
			if (Object.isUndefined(theElement.errMsgObj))
			{
				var id=s3core.random();
				theElement.insert({before:new Element('div',{id:id,'class':'error message'}).update(theMessage)});
				$(theElement).addClassName('error');
				this.watchErrorMsg(theElement,id);
			}
			return this;
		},
		watchErrorMsg: function(theElement, theError)
		{
			theElement=$(theElement);
			if (theError)theElement.errMsgObj=$(theError);
			Event.observe(theElement,'change',this.removeErrorMsg);
			this.errorMsgCount++;
		},
		removeErrorMsg: function(event)
		{
			var theElement = $(Event.element(event));
			Event.stopObserving(theElement, 'change', this.removeErrorMsg);
			if(!Object.isUndefined(theElement.errMsgObj)) 
			{
				$(theElement.errMsgObj).remove();
			}
			if(!Object.isUndefined(theElement.errMsgObj)) 
			{
				delete theElement.errMsgObj;
			}
			theElement.removeClassName('error');
			this.errorMsgCount--;
			if (this.errorMsgCount == 0 && !this.valid) {
				this.valid=true;
				if (this.isLastPage()) this.setButtonStates();
			}
		},
		isFirstPage: function(thePage)
		{
			return (this.page.current==this.page.first)?true:false;
		},
		isLastPage: function(thePage)
		{
			return (this.page.current==this.page.last)?true:false;
		},
		changePage: function()
		{
			//Handle pages.
			for (var i=0; i<this.config.pages.length; i++)
			{
				if (i != this.page.current && this.config.pages[i].visible())
				{
					this.config.pages[i].blindUp
					(
						{
							afterFinish: function()
							{
								this.config.pages[this.page.current].show();
								return;
							}.bind(this)
						}
					);
					break;
				}
			}
			this.setButtonStates();
			return;
		},
		setButtonStates: function()
		{
			if (this.isLastPage())
			{
				if (this.hasBtn.submit)
				{
					if (this.hasBtn.next) $('wizard_next').disable();
					if (this.valid) $('wizard_submit').enable();
				}
				else if (this.hasBtn.next)
				{
					$('wizard_next').value=this.btnText.submit;
					if (this.valid) $('wizard_next').enable();
					else $('wizard_next').disable();
				}
				if (this.config.pages.length == 1)
				{
					if (this.hasBtn.back) $('wizard_back').disable();
				}
				else if (this.hasBtn.back) $('wizard_back').enable();
			}
			else if (this.isFirstPage())
			{
				if (this.hasBtn.back) $('wizard_back').disable();
				if (this.hasBtn.next) $('wizard_next').value=this.btnText.next;
				if (this.hasBtn.submit && this.hasBtn.next) $('wizard_next').enable();
				if (this.hasBtn.submit) $('wizard_submit').disable();
			}
			else
			{
				if (this.hasBtn.back) $('wizard_back').enable();
				if (this.hasBtn.next) $('wizard_next').value=this.btnText.next;
				if (this.hasBtn.submit && this.hasBtn.next) $('wizard_next').enable();
				if (this.hasBtn.submit) $('wizard_submit').disable();
			}
			if (!this.hasBtn.submit && this.hasBtn.next) $('wizard_next').enable();
			if (this.hasBtn.cancel) $('wizard_cancel').enable();
			return;
		},
		disableButtons: function()
		{
			if (this.hasBtn.next) $('wizard_next').disable();
			if (this.hasBtn.back) $('wizard_back').disable();
			if (this.hasBtn.cancel) $('wizard_cancel').disable();
			if (this.hasBtn.submit) $('wizard_submit').disable();
			return;
		},
		button_next: function()
		{
			this.disableButtons();
			if (this.isLastPage())
			{
				if (!this.hasBtn.submit) this.config.form.submit();
			}
			else
			{
				this.page.current++;
				this.changePage();
			}
			return false;
		},
		button_back: function()
		{
			this.disableButtons();
			this.page.current--;
			this.changePage();
			return;
		},
		button_cancel: function()
		{
			if (confirm('Are you sure you want to cancel? You will loose everything you have inputted up to this point.'))
			{
				history.back();
				return true;
			}
			return false;
		},
		button_submit: function()
		{
			if (this.isLastPage())
			{
				this.config.form.submit();
				return true;
			}
			return false;
		},
		form_submit: function()
		{
			if (!this.isLastPage())
			{
				return false;
			}
			return true;
		}
	}
);