/**
 * Create a wizard.
 *
 * The `.uiWizard()` method creates a wizard.
 *
 * ### Examples
 * Apply wizard widget to div with class wizard.
 *
 * JavaScript:
 *
 *     ep('div.wizard')
 *         .uiWizard({
 *         });
 *
 *
 * @class jQuery.ui.uiWizard
 * @extends jQuery.widget
 *
 * @uses ep
 * @since 6.11.0
 */

/**
 * See `jQuery.ui.uiWizard` for details.
 *
 * @param {Object} [options] A map of additional options pass to the method.
 *
 * @method uiWizard
 * @member jQuery
 *
 * @since 6.11.0
 */

/*
 * @copyright		© Copyright 2006-2010, epages GmbH, All Rights Reserved.
 *
 * @module			ep.ui.wizard
 */

define("ep/ui/wizard", [
	"jquery",
	"ep",
	"$dict!ep/dict",
	"$tmpl!ep/ui/wizard-stepjump",

	"jquery/uid",
	"jquery/metaparse",
	"jquery/ui/widget",
	"ep/fn/busy",
	"ep/ui/dialog"
], function ($, ep, epDict, tmplWizardStepjump){

/*
 * @dictionary		ep.dict
 *
 * @translation		{Back}
 *					{Next}
 *					{Close}
 *					{Apply}
 */

	var tBack	= epDict.translate('Back'),
		tNext	= epDict.translate('Next'),
		tClose	= epDict.translate('Close'),
		tApply	= epDict.translate('Apply');

	$.widget( 'ui.uiWizard', $.ui.uiDialog, {
		options: {
			width:		1260,
			minWidth:	1004,
			maxWidth:	1260,
			heigh:		760,
			minHeight:	600,
			maxHeight:	760,
		//	stepStart:	{},
			stepItems:	[],
		//	stepEnd:	{},
			close:		$.noop,
			showCloseButton: undefined
		},

		_create: function(){
			var self = this,
				o = $.extend( self.options, {
					modal:			true,
					title:			'',
					resizable:		false,
					dragable:		false,
					form:			{},
					buttons:		{
						back: {
							text: tBack,
							type: 'button',
							click: function( event ){
								self.goToStep( self.step-1 );
							}
						},
						next:		{
							text: tNext,
							type: 'submit'
						}
					}
				});
			// create dialog
			self._superApply(arguments);
			// init elements
			var titlebar = self.uiDialogTitlebar;
			self.elem = self.element
				.attr('id', (self.id = self.element.attr('id') || $.uid('epWizard')) );
			self.uiDialog
				.addClass('ep-uiWizard');
			self.uiClose = titlebar
				.children('.ui-dialog-titlebar-close');
			self.uiTitle = titlebar
				.children('.ui-dialog-title');
			self.uiNumber = $('<span class="ep-uiWizard-number ui-helper-hidden">')
				.insertBefore(self.uiTitle);
			self.uiSubTitle = $('<span class="ep-uiWizard-subTitle">')
				.insertAfter(self.uiTitle);
			self.uiStepJump = ep('<div class="ep-uiWizard-titleButtonbar epDialogTitleButtonbar">')
				.insertAfter(self.uiSubTitle)
				// handle clicks on a-tags in button bar (live event)
				.on( 'click', 'a', function(){
					// go to step from the data attribute
					self.goToStep( $(this).data().index );
				});

			self.uiBack = self.options.buttons.back.addClass('ui-helper-hidden');
			self.uiNext = self.options.buttons.next;
			self.uiButtonpane = self.uiDialog
				.children('.ui-dialog-buttonpane');
			self.uiStepCache = $('<form class="ep-uiWizard-stepCache ui-helper-hidden">')
				.appendTo('body');
			self.uiForm
				.on('submit',$.proxy(self, '_stepSubmit'));
			self.body = $('body');
			self.win = $(window)
				.on('resize',$.proxy(self, '_resize'));
			// setup
			self._setOption('close',o.showCloseButton != undefined ? o.showCloseButton : o.close);

			// seems that next line isn't needed
			// self.step = o.stepStart ? -1 : 0;

			self.step = -1;
		},

		_setOption: function( key, value ){
			switch( key ){
				case 'close':
					this.uiClose[ value===false ? 'addClass' : 'removeClass' ]('ui-helper-hidden');
					this.options.closeOnEscape = !!value;
				break;
			}

			if( $.inArray( key, 'width,minWidth,maxWidth,height,minHeight,maxHeight'.split(',') )>=0 ){
				this._superApply(arguments);
			}
		},

		_stepGet: function( add ){
			var self		= this,
				o			= self.options,
				index		= self.step = add ? Math.max( Math.min( self.step+add, o.stepItems.length + (o.stepEnd ? 0 : -1) ), 0 + (o.stepStart ? -1 : 0) ) : self.step;

			return {
				data:		index<0 ? o.stepStart : index>=o.stepItems.length ? o.stepEnd : o.stepItems[ index ],
				first:		o.stepStart ? -1 : 0,
				index:		index,
				last:		o.stepItems.length-1
			};
		},

		_stepSubmit: function( event, indexOrAlias ){
			var self		= this,
				o			= self.options,
				goToIndex,
				ignore;

			if( indexOrAlias !== undefined ){
				// find goToIndex by alias
				if( typeof indexOrAlias === 'string' ){
					if( o.stepStart && o.stepStart.alias == indexOrAlias ){
						goToIndex = -1;
					}
					else if( o.stepEnd && o.stepEnd.alias == indexOrAlias ){
						goToIndex = o.stepItems.length;
					}
					else{
						$.each( o.stepItems, function( i, stepItem ){
							if( stepItem.alias == indexOrAlias ){
								goToIndex = i;
								return false;
							}
						});
					}
				}
				// goToIndex
				else{
					goToIndex = indexOrAlias;
				}
				// ignore invalid form and saveHandle for backStep
				if( goToIndex !== undefined ){
					ignore = goToIndex < self.step;

					self.uiForm.uiForm('setValid',true);
					self.uiBack.attr('disabled',false);
					self.uiNext.attr('disabled',false);
				}
			}

			if( ignore || this.uiForm.uiForm('isValid') ){
					// back/next step ?
				var	direction = self.stepBack ? -1 : 1,
					// data of current step
					stepData = self._stepGet().data,
					// show busy layer
					elem = self.uiDialog.busy('show'),
					// callback after progress
					updateCallback = function(){
						elem.busy('hide');

						var stepInfo = self._stepGet();

						if(direction == 1 && stepInfo.index == stepInfo.last && stepInfo.data['_saved']){
							self.close();
						}
					};

				// run on change step handle
				if( stepData.changeHandle ){
					stepData.changeHandle( self.uiForm );
				}

				if( ignore || direction==-1 ){
					self._stepUpdate( direction, updateCallback, goToIndex );
				}
				else if( stepData.saveHandle ){
					// run save step handle
					stepData.saveHandle( self.uiForm, function( success ){
						if( success ){
							stepData['_saved'] = true;
							self._stepUpdate( direction, updateCallback, goToIndex );
						}
						else{
							updateCallback();
						}
					});
				}
				else{
					stepData['_saved'] = true;
					self._stepUpdate( direction, updateCallback, goToIndex );
				}
			}
		},

		_stepUpdate: function( direction, callback, goToIndex ){
			if( goToIndex!==undefined ){
				this.step = goToIndex-1;
				direction=1;
			}

			var self = this,
				// set back/next to current step  => get current step
				step = self._stepGet( direction ),
				stepData = step.data,
				// short scope of element
				elem = self.elem,
				// short scope of element
				cache = self.uiStepCache,
				// get/set container of current step
				container = step.data['_container'] || (step.data['_container'] = $('<div class="ep-uiWizard-stepItem" id="'+self.id+'-stepItem-'+step.data.alias+'">').appendTo(cache)),
				// callback after progress
				updateCallback = function( snippet ){
					self.uiStepCache
					elem.children()
						.appendTo(cache);
					if( snippet ){
						container
							.empty()
							.appendTo(elem)
							.append( snippet )
							.find('.ep-js')
								.metaparse();
					}
					else{
						container
							.appendTo(elem);
					}
					self.uiNumber
						.text( step.index+1 )
						.toggleClass('ui-helper-hidden', step.index<0 || step.index>step.last);
					self.uiBack
						.toggleClass('ui-helper-hidden', step.index<=step.first || step.index>step.last);
					self.uiNext
						.text( step.index>=step.last ? step.index==step.last ? tApply : tClose : tNext );
					self.uiTitle
						.text( step.data.title );
					self.uiSubTitle
						.text( step.data.subTitle );
					self.uiStepJump
						.empty()
						.append( tmplWizardStepjump([{steps:self.options.stepItems,index:self.step}] ) )
						[ step.index>step.last ? 'addClass' : 'removeClass' ]('ui-helper-hidden');
					// resize wizard
					self._resize();

					if( callback ){
						callback();
					}
				};

			// set resolved state for step
			stepData['_resolved'] = true;

			if( direction>0 ){
				ep.ajax({
//					url:		'ep/ui/wizardTest_'+stepData.templateName+'.json',
					type:		'post',
					dataType:	'json',
					data:		{
						ViewAction:			'JSONSnippet',
						TemplateName:		stepData.templateName,
						TemplateAction:		stepData.templateAction,
						TemplateLanguageID:	ep.config.languageId,
						ObjectID:			stepData.objectId,
						WizardStepAlias:	stepData.alias,
						WizardStepIndex:	step.index,
						WizardID:			self.id
					}
				})
				.done(function( data ){
					updateCallback( data.snippet );
				})
				.fail(function(data, textStatus, errorThrown){
					updateCallback(data.responseText);
				});
			}
			else{
				updateCallback();
			}
		},

		_resize: function(){
			var self = this,
				o = self.options,
				width = Math.min( Math.max( self.win.width(), o.minWidth), o.maxWidth ) - 20,
				height = Math.min( Math.max( self.win.height(), o.minHeight), o.maxHeight ) - 20;
			// set size of container
			self.uiDialog
				.width( width )
				.height( height );
			// set size of content
			self.element
				.outerWidth( width )
				.outerHeight( height - self.uiDialogTitlebar.outerHeight(true) - self.uiButtonpane.outerHeight(true) );
			// set postion of container
			self._position();
		},

		goToStep: function( index ){
			var self = this;

			self.stepBack = true;
			self._stepSubmit( {}, index );
			self.stepBack = false;
		},

		registerChangeHandle: function( index, handle ){
			var o			= this.options;

			(index<0 ? o.stepStart : index>=o.stepItems.length ? o.stepEnd : o.stepItems[ index ]).changeHandle = handle;
		},

		registerSaveHandle: function( index, handle ){
			var o			= this.options;

			(index<0 ? o.stepStart : index>=o.stepItems.length ? o.stepEnd : o.stepItems[ index ]).saveHandle = handle;
		},

		open: function(){
			var self = this;

			self.body.css('overflow','hidden');
			self._superApply(arguments);
			self._resize();

			// update current step
			self.step--;
			self._stepUpdate(1);
		},

		close: function(event){
			var self = this,
				close = self.options.close;

			self.body.css('overflow','');

			self._superApply(arguments);
			switch( $.type(close) ){
				case 'string':
					location.href = close;
				break;
				case 'function':
					close.call( this, event );
				break;
			}
		}
	});

	return ep;

});