/******************************************************************
** Carousel
**	A simple javascript carousel for scrolling items up and down.
**
**	Parameters
**		container (optional)
**			- the id of element (or element itself) that you want
**				to establish as the carousel
**			- defaults to 'carousel'
**    layout (optional) ['vertical'|'horizontal']
**      - specify vertical or horizontal layout
**      - defaults to 'vertical'
**		start_item (optional)
**			- the number of the item you wish the carousel to start on
**				specified
**			- defaults to 1
******************************************************************/

function Carousel(container, layout, start_item) {
	this.container = $(container)||$('carousel');
  this.layout = layout||'vertical';
	this.cur_location = start_item||1;
	this.strip = this.container.select(".carousel_strip")[0];
	this.items = this.strip.select(".carousel_item");
	this.transition_time = 200; // milliseconds
	this.fps = 7; // frames per second
	this.sleep_time = this.transition_time / this.fps;
	this.in_progress = false;
	this.last_user_interaction = 0;
	this.after_user_interaction_block_auto_scroll_for = 10000; // milliseconds
	this.auto_scroll_time = 5000; // milliseconds
  
  if(this.layout == 'vertical') {
    this.originalOffset = parseInt(this.strip.getStyle('top'));
    this.height = this.items.length > 0 ? parseInt(this.items[0].getStyle('height')) : 0;
    this.item_space = this.items.length > 0 ? parseInt(this.items[0].getStyle('margin-top')) + parseInt(this.items[0].getStyle('margin-bottom')) : 0;
    this.visible_items = Math.floor(parseInt(this.container.getStyle('height')) / (this.height + this.item_space));
  } else {
    this.originalOffset = parseInt(this.strip.getStyle('left'));
    this.width = this.items.length > 0 ? parseInt(this.items[0].getStyle('width')) : 0;
    this.item_space = this.items.length > 0 ? parseInt(this.items[0].getStyle('margin-left')) + parseInt(this.items[0].getStyle('margin-right')) : 0;
    this.visible_items = Math.floor((parseInt(this.container.getStyle('width')) - 30) / (this.width + this.item_space));
  }

	this.offset = this.originalOffset;
	this.eligible_top_spots = this.items.length - this.visible_items + 1;

	with(this) {
		Event.observe(window, 'load', function() {
      if(layout == 'vertical')
        strip.setStyle({height: (height * items.count)+'px'});
      else
        strip.setStyle({width: (width * items.count)+'px'});

      if(items.length > visible_items)
        container.select('.carousel_scroll_button').invoke('show')
		});
	}

	this.start = function(pause_time) {
		if (pause_time != undefined)
			this.auto_scroll_time = pause_time;

    if(this.items.length > this.visible_items) {
      with(this) {
        setTimeout(function() {
          auto_scroll();
        }, auto_scroll_time);
      }
    }
	}

	this.auto_scroll = function(pause_time) {
		if (pause_time == undefined)
			pause_time = this.auto_scroll_time;

		if (this.last_user_interaction + this.after_user_interaction_block_auto_scroll_for < new Date().getTime()) {
			pause_time = this.auto_scroll_time; // always use default time when in autoscroll
			new_item = (this.cur_location % (this.items.length - this.visible_items + 1)) + 1;
			this.scrollToItem(new_item);
			with(this) {
				setTimeout(function() {
					auto_scroll();
				}, pause_time);
			}
		}
		else {
			with(this) {
				setTimeout(function() {
					auto_scroll(1000);
				}, pause_time);
			}
		}
	}

	this.scrollUp = function() {
		this.last_user_interaction = new Date().getTime();
		new_item = (this.cur_location + (this.eligible_top_spots * 2) - 2) % (this.eligible_top_spots) + 1;
		this.scrollToItem(new_item);
	}

	this.scrollDown = function() {
		this.last_user_interaction = new Date().getTime();
		new_item = (this.cur_location % (this.items.length - this.visible_items + 1)) + 1;
		this.scrollToItem(new_item);
	}

  this.scrollLeft = function() {
    this.last_user_interaction = new Date().getTime();
		new_item = (this.cur_location + (this.eligible_top_spots * 2) - 2) % (this.eligible_top_spots) + 1;
		this.scrollToItem(new_item);
  }

	this.scrollRight = function() {
		this.last_user_interaction = new Date().getTime();
		new_item = (this.cur_location % (this.items.length - this.visible_items + 1)) + 1;
		this.scrollToItem(new_item);
	}

	this.scrollToItem = function(itemNum) {
		if (!this.in_progress) {
			this.in_progress = true;
      if(this.layout == 'vertical')
        new_item_offset = -((itemNum - 1) * (this.height + this.item_space)) + this.item_space + (this.originalOffset / 2);
      else
        new_item_offset = -((itemNum - 1) * (this.width + this.item_space)) + this.item_space + (this.originalOffset / 2);
			this.scrollToPos(this.offset,new_item_offset);
			this.cur_location = itemNum;
		}
	}

	this.scrollToPos = function(start,end) {
		this.scroll(start,end,start);
	}

	this.scroll = function(start_pos,end_pos,cur_pos) {
		if (cur_pos != undefined && ((start_pos < end_pos && cur_pos < end_pos) || (start_pos > end_pos && cur_pos > end_pos))) {
			pct = ((cur_pos - start_pos) / (end_pos - start_pos));
			// have to give it a slight nudge for the formula to work
			if(pct == 0)
				pct = 0.0001
			new_pct = this.easeOut(pct);
			new_pos = (new_pct * (end_pos - start_pos)) + start_pos;
			this.updatePos(new_pos);
      this.start_pos = start_pos;
      this.end_pos = end_pos;
      this.new_pos = new_pos;
      with(this) {
        setTimeout(function() {
          scroll(start_pos,end_pos,new_pos);
        }, sleep_time);
      }
		}
		else {
			this.in_progress = false;
		}
	}

	this.updatePos = function(pos) {
    if(this.layout == 'vertical')
      this.strip.setStyle({'top' : pos+"px"});
    else
      this.strip.setStyle({'left' : pos+"px"});
		this.offset = pos;
	}

	this.easeOut = function(pos) {
		return -(Math.pow((pos-1), 4) -1)
	}
}
