/**
 * This class converts a list of companies to an interactive company viewer.
 * It slides a number of companies at a time through the screen, pausing when
 * the mouse cursor is over a company.
 * @constructor
 */
function CompanyViewer(element, direction, number, movement) {
	this._element = $(element);
	
	this._direction = direction || CompanyViewer.HORIZONTAL;
	this._numCompanies = number || 4;
	this._movement = movement || 150;
	
	if (this._element.children().length > this._numCompanies) {		
		this._hideCompanies();
		this._createNavigation();
		this._startSlider();
		this._element.mouseover(new Delegate(this, this._stopSlider));
		this._element.mouseout(new Delegate(this, this._startSlider));
	}
}

CompanyViewer.prototype = {
	/**
	 * The number of companies to show at a single time.
	 * @private
	 */
	_numCompanies: null,
	
	/**
	 * The direction of movement, can be horizontal or vertical.
	 * @private
	 */
	_direction: null,
	
	/**
	 * The time to pause at each location.
	 * @private
	 */
	_TIME_PER_COMPANY: 3000,
	
	/**
	 * The HTML List element containing the companies
	 * @private
	 */
	_element: null,
	
	/**
	 * A list of each company's HTML List Item element.
	 * @private
	 */
	_companies: null,
	
	/**
	 * Contains a reference to the currently running {setInterval}, if any
	 * @private
	 */
	_interval: null,
	
	/**
	 * The amount of movement. Should be as wide or high as the elements
	 * to ensure fluent movement.
	 * @private
	 */
	_movement: null,
	
	/**
	 * Hides all companies after the first {_numCompanies}
	 * @private
	 */
	_hideCompanies: function () {
		$.each(this._element.children(), new Delegate(this, function(index, company) {
			if (index >= this._numCompanies) {
				$(company).hide();
			}
		}));
	},
	
	/**
	 * Creates next and previous buttons
	 * @private
	 */
	_createNavigation: function () {
		var previousButton = $('<a class="previous-company"></a>').insertBefore(this._element);
		var nextButton = $('<a class="next-company"></a>').insertAfter(this._element);
		
		previousButton.mouseover(new Delegate(this, this._stopSlider));
		previousButton.mouseout(new Delegate(this, this._startSlider));		
		
		nextButton.mouseover(new Delegate(this, this._stopSlider));
		nextButton.mouseout(new Delegate(this, this._startSlider));
		
		if (this._direction == CompanyViewer.HORIZONTAL) {
			previousButton.click(new Delegate(this, this._moveRight));
			nextButton.click(new Delegate(this, this._moveLeft));
		} else {
			previousButton.click(new Delegate(this, this._moveDown));
			nextButton.click(new Delegate(this, this._moveUp));
		}		
	},
	
	/**
	 * Starts an interval that slides the first company out of view, and the
	 * next one in line into view. Prevents starting twice.
	 * @private
	 */
	_startSlider: function () {
		if (this._interval) {
			// We are already running, so don't start again.
			return;
		}
		if (this._direction == CompanyViewer.HORIZONTAL) {
			this._interval = setInterval(new Delegate(this, this._moveLeft), this._TIME_PER_COMPANY);
		} else {
			this._interval = setInterval(new Delegate(this, this._moveUp), this._TIME_PER_COMPANY);
		}
	},
	
	/**
	 * Moves the logo's one to the left. After the animation it appends the first company
	 * to the end of the list, ensuring a cyclic animation.
	 * @private
	 */
	_moveLeft: function () {
		var currentCompany = this._element.children()[0];
		var nextCompany = this._element.children()[this._numCompanies];
		
		$(currentCompany).animate({marginLeft: "-" + this._movement + "px"}, 1000, new Delegate(this, function () {
			$(currentCompany).hide().css("margin-left", "").appendTo(this._element);
		}));
		
		$(nextCompany).css("margin-right", "-" + this._movement + "px").show().animate({marginRight: "0px"}, 1000);
	},
	
	/**
	 * Moves the logo's one to the right. Before the animation it prepends the last company
	 * to the beginning of the list, ensuring a cyclic animation.
	 * @private
	 */
	_moveRight: function () {
		var currentCompany = this._element.children()[this._numCompanies - 1];
		var nextCompany = this._element.children()[this._element.children().length - 1];
					
		$(currentCompany).animate({marginRight: "-" + this._movement + "px"}, 1000, new Delegate(this, function () {
			$(currentCompany).hide().css("margin-right", "");
		}));
		
		$(nextCompany).prependTo(this._element).css("margin-left", "-" + this._movement + "px").show().animate({marginLeft: "0px"}, 1000);
	},
	
	/**
	 * Moves the logo's one up. After the animation it appends the first company
	 * to the end of the list, ensuring a cyclic animation.
	 * @private
	 */
	_moveUp: function () {
		var currentCompany = this._element.children()[0];
		var nextCompany = this._element.children()[this._numCompanies];
					
		$(currentCompany).animate({marginTop: "-" + this._movement + "px"}, 1000, new Delegate(this, function () {
			$(currentCompany).hide().css("margin-top", "").appendTo(this._element);
		}));
		
		$(nextCompany).css("margin-bottom", "-" + this._movement + "px").show().animate({marginBottom: "0px"}, 1000);
	},
	
	/**
	 * Moves the logo's one down. Before the animation it prepends the last company
	 * to the beginning of the list, ensuring a cyclic animation.
	 * @private
	 */
	_moveDown: function () {
		var currentCompany = this._element.children()[this._numCompanies - 1];
		var nextCompany = this._element.children()[this._element.children().length - 1];
					
		$(currentCompany).animate({marginBottom: "-" + this._movement + "px"}, 1000, new Delegate(this, function () {
			$(currentCompany).hide().css("margin-bottom", "");
		}));
		
		$(nextCompany).prependTo(this._element).css("margin-top", "-" + this._movement + "px").show().animate({marginTop: "0px"}, 1000);
	},
	
	/**
	 * If active, stops the interval. Does nothing if the interval is not active.
	 * @private
	 */
	_stopSlider: function () {
		if (this._interval) {
			clearInterval(this._interval);
		}
		
		this._interval = null;
	}
};

CompanyViewer.HORIZONTAL = 1;
CompanyViewer.VERTICAL = 2;

