

var inputHelper = Class.create({
	viewFirstBubble:			true,						// After the Walkthru, should the first Bubble be visible after fadeout of the others
	
	delayTime: 						2,							// Delay between appearance of the Bubbles on Pageload
	visibleTime: 					4,							// Time, between appearance of the last Bubble and hiding all Bubbles
	highlightTime:				1,							// Fade-In and Fade-Out Time for the Highlighter
	
	bubbleOffsetLeft: 		5,							// Offset to the left in Pixels
	highlightPadding:			10,							// Padding of the Highlight-Element around the target
	
	outerBubbleClass: 		'bubble',				// Class of the outer Bubble
	innerBubbleClass: 		'innerBubble',	// Class of the inner Bubble with the Content-Paragraph
	helpButtonClass: 			'bubbleHelp',		// Class of the Help-Button-Element
	bubbleDecoClass: 			'bubbleDeco',		// Class of the Deco-Bubble
	highlightClass:				'highlighter',	// Class of the Highlight-Element
	goOnLinkClass:				'goOnLink',			// Class of the GoOn-Link
	
	bubbleIdSuffix: 			'_bubble',			// Bubble ID-Suffix
	bubbleDecoIdSuffix: 	'_deco',				// Deco ID-Suffix
	highlighterIdSuffix:	'_highlight',		// Highlighter ID-Suffix
	
	helpButtonTag: 				'legend',				// Tag name in which the Help Button should be added
	bubbleTarget: 				document.body,	// Target-Element for the Bubbles
	
	goOnText:							'Weiter...',		// Textlink, shown at the end of an Bubbletext,			

	//---------
	
	conf: null,
	fields: null,
	aoBubbles: new Array(),
	aoHighlight: new Array(),
	iBubbleStep: 0,
	iStepsLength: 0,
	bInitialisation: true,
	oRequestedBubble: null,
	bHelperBubbleOn: false,
	
	/**
	 * Init-Function
	 * @param Array asConf
	 * @param Array asSubversiveFields
	 */
	initialize: function(asBubbleConf)
	{
		this.conf = asBubbleConf;
		
		this.conf.each(function(oItem, iIndex){
			this.generateBubble(iIndex);
			$(this.bubbleTarget).insert({top: this.aoBubbles[iIndex]});
			this.measureTarget(iIndex);
			this.insertHelpButton(iIndex);
		}, this);

		this.bubbleWalk();
	},
	
	/**
	 * Inserts a Help-Button that shows the corresponding Helper-Bubble
	 * @param Integer iIndex
	 */
	insertHelpButton: function(iIndex)
	{

		var oItem = $(this.conf[iIndex].id).down(this.helpButtonTag);
		if ( oItem )
		{
			oItem.addClassName(this.helpButtonClass);
			oItem.observe('click', this.showHelperBubble.bind(this));
		}

	},
	
	/**
	 * Walks thru all the Bubbles and shows them
	 */
	bubbleWalk: function()
	{
		this.iStepsLength = this.conf.length - 1;
		this.stepping();
		this.bw = new PeriodicalExecuter(this.stepping.bind(this), this.delayTime);
	},
	
	/**
	 * Shows one Bubble on the Walkthru
	 */
	stepping: function()
	{
		this.showBubble(this.iBubbleStep);
		this.highlightThings(this.iBubbleStep);
		
		if ( this.iBubbleStep == this.iStepsLength )
		{
			this.bw.stop();
			this.hideObserver();
		}
		else
		{
			this.iBubbleStep++;
		}
	},
	
	/**
	 * Calls the Hide-all-walkthru-Bubbles-Function after a given time
	 */
	hideObserver: function()
	{
		this.ho = new PeriodicalExecuter(this.hideAllBubbles.bind(this), this.visibleTime);
	},
	
	/**
	 * Hides all Walkthrou-Bubbles
	 */
	hideAllBubbles: function()
	{
		this.conf.each(function(oItem, iIndex){
			if ( this.viewFirstBubble === false )
			{
				$(this.conf[iIndex].id + this.bubbleIdSuffix).fade({from: 0.9, to: 0, duration: 0.5});
			}
			else
			{
				this.iCurrentBubble = 0;
				if ( iIndex != 0 )
					$(this.conf[iIndex].id + this.bubbleIdSuffix).fade({from: 0.9, to: 0, duration: 0.5});
			}
				
		}, this);
		this.ho.stop();
		this.bInitialisation = false;
	},
	
	/**
	 * Shows a Bubble
	 * @param Event e
	 */
	showHelperBubble: function(e)
	{
		this.oRequestedBubble = $(e.element().up().id + this.bubbleIdSuffix);
		
		if ( this.bInitialisation === false && this.oRequestedBubble )
		{
			this.oRequestedBubble.appear({from: 0, to: 0.9, duration: 1})
		}
	},
	
	/**
	 * Sets some Parameters and shows a Bubble
	 * @param Integer iBubbleUid
	 */
	showBubble: function(iBubbleUid)
	{
		$(this.conf[iBubbleUid].id + this.bubbleIdSuffix).setStyle({
			top: this.conf[iBubbleUid].top,
			left: this.conf[iBubbleUid].left,
			zIndex: '100'
		});
		
		$(this.conf[iBubbleUid].id + this.bubbleDecoIdSuffix).setStyle({
			height: this.conf[iBubbleUid].decoHeight
		});
		
		$(this.conf[iBubbleUid].id + this.bubbleIdSuffix).appear({from: 0, to: 0.9, duration: 1});
	},
	
	showNextBubble: function()
	{
		if ( this.conf[this.iCurrentBubble] )
			$(this.conf[this.iCurrentBubble].id + this.bubbleIdSuffix).fade({from: 0.9, to: 0, duration: 1});
		
		this.iCurrentBubble = this.iCurrentBubble+1;

		if ( this.conf[this.iCurrentBubble] )
		{
			$(this.conf[this.iCurrentBubble].id + this.bubbleIdSuffix).appear({from: 0, to: 0.9, duration: 1});
		}
		else
		{
			$$('.' + this.goOnLinkClass).invoke('toggle');
		}
	},
	
	/**
	 * Hides a Bubble
	 */
	hideBubble: function()
	{
		var oItem = $(this);
		this.bHelperBubbleOn = false;
		oItem.fade({from: 0.9, to: 0, duration: 0.5});
	},
	
	/**
	 * Generates the HTML for a Bubble
	 * @param Integer iIndex
	 */
	generateBubble: function(iIndex)
	{
		var sBubbleId = this.conf[iIndex].id + this.bubbleIdSuffix;
		
		var oStep = new Element('span').update((iIndex + 1));
		
		var oGoOnLink = new Element('p', {'class': this.goOnLinkClass}).update(this.goOnText);
		oGoOnLink.observe('click', this.showNextBubble.bind(this));
		var oText = new Element('p').update(this.conf[iIndex].text);
		oText.insert({top: oStep, bottom: oGoOnLink});
		
		var oInnerBubble = new Element('div', {'class': this.innerBubbleClass});
		oInnerBubble.insert({top: oText});
		
		var oBubbleDeco = new Element('div', {'class': this.bubbleDecoClass, id: this.conf[iIndex].id + this.bubbleDecoIdSuffix}).update('&nbsp;');

 		this.aoBubbles[iIndex] = new Element('div', {'class': this.outerBubbleClass, style: 'display: none;', id: sBubbleId});
		this.aoBubbles[iIndex].observe('click', this.hideBubble);
		this.aoBubbles[iIndex].insert({top: oInnerBubble, bottom: oBubbleDeco});
	},
	
	/**
	 * Measures some things for dimensioning and positioning of the Bubbles
	 * @param Integer iIndex
	 */
	measureTarget: function(iIndex)
	{
		var jFDim = $(this.conf[iIndex].id).getDimensions();
		var jFPos = $(this.conf[iIndex].id).cumulativeOffset();
		var jBDim = $(this.conf[iIndex].id + this.bubbleIdSuffix).getDimensions();

		this.conf[iIndex].left = jFPos.left - jBDim.width - this.bubbleOffsetLeft + 'px';
		this.conf[iIndex].top = jFPos.top + (Math.floor(jFDim.height / 2)) - (Math.ceil(jBDim.height / 2)) + 'px';
		this.conf[iIndex].decoHeight = jBDim.height + 'px';
	},
	
	/**
	 * Highlights the things that correspond to a Bubble
	 * @param Integer iIndex
	 */
	highlightThings: function(iIndex)
	{
		if( typeof(this.conf[iIndex].highlight) == 'object' )
		{
			this.conf[iIndex].highlight.each(function(sItem){
				jODim = $(sItem).getDimensions();
				jOPos = $(sItem).cumulativeOffset();
				
				var sTop = jOPos.top - this.highlightPadding + 'px';
				var sLeft = jOPos.left - this.highlightPadding + 'px';
				
				var sHeight = ( jODim.height < 10 ) ? 15 + (2 * this.highlightPadding) + 'px' : jODim.height + (2 * this.highlightPadding) + 'px';
				var sWidth = jODim.width + (2 * this.highlightPadding) + 'px';
				
				var oHighlighter = new Element('div', {id: sItem + this.highlighterIdSuffix, 'class': this.highlightClass});
				oHighlighter.setStyle({
					display: 'none',
					zIndex: '100',
					top: sTop,
					left: sLeft,
					width: sWidth,
					height: sHeight
				});
				
				$(this.bubbleTarget).insert({bottom: oHighlighter});
				
				this.aoHighlight.push($(sItem + this.highlighterIdSuffix));
				
				$(sItem + this.highlighterIdSuffix).appear({
					from: 0, 
					to: 0.6, 
					duration: this.highlightTime, 
					afterFinish: this.destroyHighlighter.bind(this)
				});
			}, this);
		}
	},
	
	/**
	 * Destroys a Highlight-Field
	 */
	destroyHighlighter: function()
	{
		var oItem = this.aoHighlight.shift();
	  oItem.fade({
			from: 0.6, 
			to: 0, 
			duration: this.highlightTime
		})
	}
});

