
/**
  * Class LogoSlider
  *
  * Implements a panel, which displays several logos with links to their
  * companies and an information text.
  *
  */

/**
  * Constructor(sliderContainerId, logoClassName);
  *
  * Creates a LogoSlider object and uses the given sliderContainerId to
  * identify the destination layer in which the logos should been inserted.
  *
  * The logoClassName defines the class of each logo which is inserted into
  * the destination layer.
  *
  * informationClassName defines the classname, which should been given to
  * each information box.
  *
  */

function LogoSlider(sliderContainerId, logoClassName, informationClassName)
{
	// Constants
	LogoSlider.MOVEMENT_SPEED = 1;
	LogoSlider.REFRESH_INTERVAL = 40;
	LogoSlider.TOOLTIP_WAIT_TIME = 400;
	
	// Initialize some object attributes
	this.$_sliderContainer = $('#'+ sliderContainerId);
	this.$_movementContainer = null;
	this.$_informationContainer = null;
	this._logoClassName = logoClassName;
	this._informationClassName = informationClassName;
	
	this._containerOffset = 
	{
		top:	0,
		left:	0	
	};
	this._toolboxOffset = 
	{
		top:	0,
		left:	0	
	};
	
	this._containerWidth = 0;
	this._containerHeight = 0;
	this._toolboxWidth = 0;
	this._toolboxHeight = 0;
	this._logoWidth = 0;
	this._logoHeight = 0;
	this._logoHoricontalCount = 0;
	this._logoVerticalCount = 0;
	
	this._currentLogoIndex = 0;
	this._verticalMargin = 0;
	this._movement = true;
	
	this._logoArray = new Array();
	
	this.$_mouseOverElement = null;
	
	// Call necessary methods to build object correctly
	this._discoverVisibleLogoCount();
	this._discoverOffsets();
	this._linkEvents();
}

/**
  * draw( );
  *
  * Draws the panel and starts sliding.
  *
  */

LogoSlider.prototype.draw = function()
{
	// create absolute wrapper container
	this.$_sliderContainer.append('<div id="LSMovement"></div>');
	this.$_sliderContainer.after('<div id="LSInformation"></div>');
	this.$_movementContainer = $('#LSMovement');
	this.$_informationContainer = $('#LSInformation');
	this.$_informationContainer.css('position', 'absolute');
	
	this._toolboxWidth = this.$_informationContainer.get(0).offsetWidth;
	this._toolboxHeight = this.$_informationContainer.get(0).offsetHeight;
	
	this.$_informationContainer.css('display', 'none');
	
	// print initial screen
	this._fillInitialScreen();
	
	// start animation
	this._startAnimation();
}

/**
  * _startAnimation( );
  *
  * Animates the movement.
  *
  */

LogoSlider.prototype._startAnimation = function()
{
	if(Math.abs(this._verticalMargin) >= this._logoHeight)
	{
		// remove 'now invisible' logo row
		this._removeLogoRow();
		
		// append a new logo row
		this._appendLogoRow(this._createLogoRow());
		
		// calculate the new vertical margin
		this._verticalMargin %= LogoSlider.MOVEMENT_SPEED;
	}
	
	this._verticalMargin -= LogoSlider.MOVEMENT_SPEED;
	this.$_movementContainer.css('margin-top', this._verticalMargin +'px');
	
	if(this.isMoving())
	{
		var that = this;
		setTimeout(function(){that._startAnimation()}, LogoSlider.REFRESH_INTERVAL);
	}
}

/**
  * addItem(logoPath, destinationUrl, descriptionText);
  *
  * Adds an item which should been displayed in LogoSlider destination panel.
  *
  * logoPath		- Path to logo
  * destinationUrl	- the url to link with
  * descriptionText	- The text to display, if user holds the mouse over the item
  *
  */

LogoSlider.prototype.addItem = function(logoPath, destinationUrl, descriptionText)
{
	this._logoArray.push(new Array(logoPath, destinationUrl, descriptionText));
}

/**
  * _discoverVisibleLogoCount( );
  *
  * Discovers width and height of logo class and count the amount of visible
  * logos in one screen.
  * In adjacent set object attributes with this settings.
  *
  */

LogoSlider.prototype._discoverVisibleLogoCount = function()
{
	// discovers current element metrics
	this._discoverLogoMetrics();
	this._discoverContainerMetrics();
	
	// calculate amount of visible logos
	this._logoHoricontalCount = Math.floor(this._containerHeight / this._logoHeight);
	this._logoVerticalCount = Math.floor(this._containerWidth / this._logoWidth);
}

/**
  * _discoverOffsets( );
  *
  * Discovers offsets of slider container.
  *
  */

LogoSlider.prototype._discoverOffsets = function()
{
	this._containerOffset.top = 0;
	this._containerOffset.left = 0;
	
	$handle = this.$_sliderContainer.parent();
	
	do
	{
		var position;
		try
		{
			position = $handle.css('position');
		} catch(NS_ERROR_XPC_BAD_CONVERT_JS) {
			break;
		}
		if(position != 'static')
		{
			this._containerOffset.top += $handle.position().top;
			this._containerOffset.left += $handle.position().left;
		}
	} while(($handle = $handle.parent()).length > 0);
	
	this._containerOffset.left -= 20;
}

/**
  * _discoverLogoMetrics( );
  *
  * Discovers logo metrics.
  *
  */

LogoSlider.prototype._discoverLogoMetrics = function()
{
	// create dummy logo object and get metrics
	this.$_sliderContainer.append('<div class="'+ this._logoClassName +' dummyLogo" style="visibility: hidden">&nbsp;</div>');
	var $dummyLogo = this.$_sliderContainer.children('div.dummyLogo:last');
	this._logoWidth = $dummyLogo.get(0).offsetWidth;
	this._logoHeight = $dummyLogo.get(0).offsetHeight;
	
	// create dummy toolbox and get metrics
	this.$_sliderContainer.after('<div class="'+ this._logoClassName +' dummyLogo" style="visibility: hidden">&nbsp;</div>');
	var $dummyLogo = this.$_sliderContainer.children('div.dummyLogo:last');
	this._logoWidth = $dummyLogo.get(0).offsetWidth;
	this._logoHeight = $dummyLogo.get(0).offsetHeight;
	
	// remove dummy logo object
	$dummyLogo.remove();
}

/**
  * _discoverContainerMetrics( );
  *
  * Discovers LogoSlider container metrics.
  *
  */

LogoSlider.prototype._discoverContainerMetrics = function()
{
	this._containerWidth = this.$_sliderContainer.get(0).offsetWidth;
	this._containerHeight = this.$_sliderContainer.get(0).offsetHeight;
}

/**
  * _createLogoRow( );
  *
  * Returns an array, which contains the _next_ to show logos.
  *
  */

LogoSlider.prototype._createLogoRow = function()
{
	var logoArrayLength = this._logoArray.length;
	var rowArray = new Array();
	
	for(var i = 0; i < this._logoVerticalCount; ++i)
	{
		if(this._currentLogoIndex + i >= logoArrayLength)
		{
			// the next time this method is called, the first logo should been
			// used
			break;
		}
		
		// specify logo index
		rowArray.push(this._logoArray[i + this._currentLogoIndex]);
	}
	
	if(this._currentLogoIndex + this._logoVerticalCount >= logoArrayLength)
	{
		this._currentLogoIndex = 0;
	}
	else
	{
		this._currentLogoIndex += this._logoVerticalCount;
	}
	
	if(!rowArray.length)
	{
		return null;
	}
	
	return rowArray;
}

/**
  * _appendLogoRow(logoRow);
  *
  * Appends a new logorow to the destination container on bottom.
  *
  * logoRow		- defines the contents of logos
  *
  */

LogoSlider.prototype._appendLogoRow = function(logoRow)
{
	var logoRowLength = logoRow.length;
	
	for(var i = 0; i < this._logoVerticalCount; ++i)
	{
		if(i >= logoRowLength)
		{
			// print empty logo
			this.$_movementContainer.append(	'<div class="'+ this._logoClassName +'">'
											+	'&nbsp;</div>');
		}
		else
		{
			var logo = logoRow[i];
			this.$_movementContainer.append(	'<div class="'+ this._logoClassName +'"'
											+	'style="font-size:'+ this._logoHeight +'px">'
											+	'<a href="'+ logo[1] +'">'
											+	'<img src="'+ logo[0] +'" />'
											+	'</a>'
											+	'<div class="'+ this._informationClassName +'" '
											+	'style="display:none">'
											+	logo[2]
											+	'</div>'
											+	'</div>');
		}
	}
}

/**
  * _removeLogoRow( );
  *
  * Removes the first row from the destination container.
  *
  */

LogoSlider.prototype._removeLogoRow = function()
{
	this.$_movementContainer.children('div.'+ this._logoClassName +':lt('+ this._logoVerticalCount +')').remove();
}

/**
  * _fillInitialScreen( );
  *
  * Fills the initial screen.
  *
  */

LogoSlider.prototype._fillInitialScreen = function()
{
	var visualRowCount = this._logoHoricontalCount + 2; 
	
	for(var i = 0; i < visualRowCount; ++i)
	{
		var logoRow = this._createLogoRow();
		if(!logoRow)
		{
			break;
		}
		
		this._appendLogoRow(logoRow);
	}
}

/**
  * _linkEvents( );
  *
  * Links all necessary events with elements.
  *
  */

LogoSlider.prototype._linkEvents = function()
{
	var that = this;
	
	this.$_sliderContainer.mouseover(function(e)
	{
		if(that.isMoving())
		{
			that.setMoving(false);
		}
		
		if(e.target.tagName == 'IMG')
		{
			that.$_mouseOverElement = $(e.target);
			setTimeout(function(){that._showTooltip($(e.target));}, LogoSlider.TOOLTIP_WAIT_TIME);
		}
	});
	
	this.$_sliderContainer.mouseout(function(e)
	{
		that.$_mouseOverElement = null;
		that.$_informationContainer.css('display', 'none');
	});
	
	this.$_sliderContainer.mousemove(function(e)
	{
		if(e.target.tagName == 'IMG')
		{
			var topSet = false;
			var body = $('body').get(0);
			
			var _toolboxWidth = that.$_informationContainer.get(0).offsetWidth;
			var _toolboxHeight = that.$_informationContainer.get(0).offsetHeight;
			if(_toolboxWidth == 0 && _toolboxHeight == 0)
			{
				_toolboxWidth = that._toolboxWidth;
				_toolboxHeight = that._toolboxHeight;
			}
			
			// calculate toolbox offset
			var offsetLeft 	= 	body.offsetWidth - e.pageX - _toolboxWidth - 20;
			var offsetTop 	= 	body.offsetHeight - e.pageY - _toolboxHeight - 20;
			
			if(offsetLeft > 0 && offsetTop > 0)
			{
				offsetLeft = 0;
				offsetTop = 0;
			}
			else if(offsetLeft > 0 && offsetTop <= 0)
			{
				offsetTop = -20 - _toolboxHeight;
				offsetLeft = 0;
			}
			else if(offsetLeft <= 0 && offsetTop > 0)
			{
				offsetLeft = -40 - _toolboxWidth;
				offsetTop = 0;
			}
			else
			{
				offsetLeft = -20 - _toolboxWidth;
				offsetTop = -20 - _toolboxHeight;
			}
			
			// set position of toolbox
			that.$_informationContainer.css('left', e.pageX - that._containerOffset.left + offsetLeft);
			that.$_informationContainer.css('top', e.pageY - that._containerOffset.top + offsetTop);
		}
	});
	
	this.$_sliderContainer.bind('mouseleave', function()
	{
		that.setMoving(true);
	});
}

/**
  * _showTooltip($target)
  *
  * Creates a logobased tooltip with the defined content.
  *
  * $target			- defines the target, which tooltip should been
  *					  showed
  *
  */

LogoSlider.prototype._showTooltip = function($target)
{
	if(		!this.$_mouseOverElement
		||	this.$_mouseOverElement.attr('src') != $target.attr('src'))
	{
		// user leaved mouse from element; so ignore the event
		return;
	}
	
	var $tip = this._getTooltipFromLogo($target);
	//$tip.css('display', 'block');
	this.$_informationContainer.html($tip.html());
	this.$_informationContainer.css('display', 'block');
	
	this._toolboxWidth = this.$_informationContainer.get(0).offsetWidth;
	this._toolboxHeight = this.$_informationContainer.get(0).offsetHeight;
}

/**
  * _getTooltipFromLogo($logo)
  *
  * Returns the tooltiplayer from the image of a logo.
  *
  * $logo			- defines the layer for the logo
  *
  */

LogoSlider.prototype._getTooltipFromLogo = function($logo)
{
	return $logo.parent().siblings('div.'+ this._informationClassName);
}

/**
  * setMoving(whether);
  *
  * Enables / disables movement.
  *
  */

LogoSlider.prototype.setMoving = function(whether)
{
	this._movement = whether;
	if(this._movement)
	{
		this._startAnimation();
	}
}

/**
  * isMoving( );
  *
  * Returns current moving status.
  *
  */

LogoSlider.prototype.isMoving = function()
{
	return this._movement;
}
