/*
 * Slider based on Glider found at http://www.missingmethod.com/projects/glider.html
 * Chris Peery
 * version 1 2008-10-16
 */

var Slider = Class.create();
Object.extend(Object.extend(Slider.prototype, Abstract.prototype), {
	initialize : function(viewport, slider, groupControls, slideControls, options) {
		this.viewport = $(viewport);
		this.slider = $(slider);
		this.groupControls = $(groupControls);
		this.groupControlsArray = [];
		this.slideControls = $(slideControls);
		this.slideControlsArray = [];
		this.groupHighlight = null;
		this.autoPlayTimer = null;

		this.groups = [];
		this.slides = [];
		this.playing = false;
		this.activeGroup = null;
		this.activeGroupControl = null;
		this.activeSlide = null;
		this.activeSlideIndex = null;
		this.activeSlideControl = null;

		this.options = Object.extend({
		  autoPlay: true,
		  autoPlayTimer: 10,
			beforeSlide: Prototype.emptyFunction,
			afterSlide: Prototype.emptyFunction,
			slideWidth: 308,
			duration: 0.5,
			defaultSlide:null,
			groupHighlightId: null,
			groupControlsEvent: 'click',
			slideControlsEvent: 'click',
			nextControlsEvent: 'click',
			previousControlsEvent: 'click',
			nextControlsClassName: 'next-slide',
			previousControlsClassName: 'previous-slide',
			sliderSlideClassName: 'slide',
			sliderGroupClassName: 'group'
			},options || {});

		if ( null == this.viewport || null == this.slider ) {
			alert('Viewport/Slider div layers was not loaded properly')
			return false;
		}

		// if group highlight layer is defined load it
		if ( null != this.options.groupHighlightId ) {
			this.groupHighlight = $(this.options.groupHighlightId);
		}

		// load all groups and slides inside of the slider object
		this.groups = this.slider.getElementsByClassName(this.options.sliderGroupClassName);
		this.slides = this.slider.getElementsByClassName(this.options.sliderSlideClassName);

		// based on number of slides resize the width of the slider
		this.slider.width = this.options.slideWidth * this.slides.length;
		this.slider.style.width = this.slider.width + 'px';

		// define events for slider
		this.events = { 
			groupClick: this.groupClick.bind(this),
			slideClick: this.slideClick.bind(this),
			nextClick: this.nextClick.bind(this),
			previousClick: this.previousClick.bind(this),
			autoPlay: this.playOrPause.bind(this)
		};

		// add group observers for slider
		if ( null != groupControls ) {
			this.groupControlsArray = this.groupControls.getElementsBySelector('a');
			this.groupControlsArray.invoke('observe', this.options.groupControlsEvent, this.events.groupClick);
		}

		// add individual slide observers for slider
		if ( null != slideControls ) {
  		this.slideControlsArray = this.slideControls.getElementsBySelector('a');
  		this.slideControlsArray.invoke('observe', this.options.slideControlsEvent, this.events.slideClick);
		}

		// add next slide observers
		var nextControls = $$("." + this.options.nextControlsClassName);
		nextControls.invoke('observe', this.options.nextControlsEvent, this.events.nextClick);

		// add next slide observers
		var previousControls = $$("." + this.options.previousControlsClassName);
		previousControls.invoke('observe', this.options.previousControlsEvent, this.events.previousClick);

		// check for default slide to load
		var pageLoadedSlide = window.location.href.split("#")[1];
		var defaultSlideId = ( pageLoadedSlide ) ? pageLoadedSlide : ( ( null != this.options.defaultSlide ) ? this.options.defaultSlide : this.slides[0].id );
		if ( null != defaultSlideId ) this.loadDefaultSlide(defaultSlideId);
		
		if ( this.options.autoPlay ) {
			this.autoPlayTimer = new PeriodicalExecuter(this.events.autoPlay, this.options.autoPlayTimer);
		}
	},
	playOrPause: function() {
		if (this.scrolling) this.scrolling.cancel();
		if (this.moving) this.moving.cancel();

		var nextSlide = this.calculateNextSlide();
		if ( nextSlide )
		{
			if ( null != this.groupHighlight ) {
				var groupId = nextSlide.up().id;
				this.setActiveGroupControlByGroupId(groupId);
				this.highlightActiveGroup();
			}

			this.scrollToSlide(nextSlide);
		}
	},
	autoPlayControl: function(event) {
    Event.stop(event);
    var element = Event.element(event);
		
    if ( this.playing )
    {
      this.autoPlayTimer = new PeriodicalExecuter(this.events.autoPlay, this.options.autoPlayTimer);
    }
    else
    {
      this.autoPlayTimer.stop();
    }
	},
	loadDefaultSlide: function(defaultSlideId) {
		if (this.scrolling) this.scrolling.cancel();
		if (this.moving) this.moving.cancel();

		var targetSlide = this.slider.down('#'+defaultSlideId);

		if ( targetSlide )
		{
			if ( !targetSlide.hasClassName('slide') )
				targetSlide = targetSlide.down(0); // group provided so we go down one level to first slide

			if ( null != this.groupHighlight ) {
				var groupId = targetSlide.up().id;
				this.setActiveGroupControlByGroupId(groupId);
				this.highlightActiveGroup();
			}

			this.scrollToSlide(targetSlide);
		}
	},
	nextClick: function(event){
		Event.stop(event);
		if (this.scrolling) this.scrolling.cancel();
		if (this.moving) this.moving.cancel();

		var nextSlide = this.calculateNextSlide();
		if ( nextSlide )
		{
			if ( null != this.groupHighlight ) {
				var groupId = nextSlide.up().id;
				this.setActiveGroupControlByGroupId(groupId);
				this.highlightActiveGroup();
			}

			this.scrollToSlide(nextSlide);
		}
	},
	previousClick: function(event){
		Event.stop(event);
		if (this.scrolling) this.scrolling.cancel();
		if (this.moving) this.moving.cancel();

		var previousSlide = this.calculatePreviousSlide();
		if ( previousSlide )
		{
			if ( null != this.groupHighlight ) {
				var groupId = previousSlide.up().id;
				this.setActiveGroupControlByGroupId(groupId);
				this.highlightActiveGroup();
			}

			this.scrollToSlide(previousSlide);
		}
	},
	groupClick: function(event) {
		Event.stop(event);
		if (this.scrolling) this.scrolling.cancel();
		if (this.moving) this.moving.cancel();

		var element = Event.element(event);

		// if our event was triggered by the href find it
		if ( !element.readAttribute('href') ) element = element.up('a', 0);

		element.blur(); // remove focus from link

		var targetGroup = this.slider.down('#'+element.href.split("#")[1]);
		if ( targetGroup )
		{
			if ( null != this.groupHighlight ) {
				this.activeGroupControl = element.up();
				this.highlightActiveGroup();
			}

			var targetSlide = targetGroup.down('.' + this.options.sliderSlideClassName);
			this.scrollToSlide(targetSlide);
		}

		// add active class name to element
		this.groupControlsArray.each(function(control){
			if (control == element) {
				control.addClassName("active")
			}else{
				control.removeClassName("active")
			}
		});
	},
	slideClick: function(event) {
		Event.stop(event);
		if (this.scrolling) this.scrolling.cancel();
		if (this.moving) this.moving.cancel();

		var element = Event.element(event);
		element.blur(); // remove focus from link

		var targetSlide = this.slider.down('#'+element.href.split("#")[1]);
		if ( targetSlide )
		{
			if ( null != this.groupHighlight ) {
				var groupId = targetSlide.up().id;
				this.setActiveGroupControlByGroupId(groupId);
				this.highlightActiveGroup();
			}

			this.scrollToSlide(targetSlide);
		}
	},
	highlightActiveGroup: function() {
		Position.prepare();
		var containerOffset = Position.cumulativeOffset(this.groupHighlight);
		var elementOffset = Position.cumulativeOffset(this.activeGroupControl);
		
		var calculatedGrowthPercentage = 0;
		if ( this.activeGroupControl.getWidth() > this.groupHighlight.getWidth() ) { // grow the highlight element
			calculatedGrowthPercentage = 100 + ( ( this.activeGroupControl.getWidth() - this.groupHighlight.getWidth() ) / this.groupHighlight.getWidth() ) * 100;
		} else { // shrink the highlight element
			calculatedGrowthPercentage =  100 - ( ( ( this.groupHighlight.getWidth() - this.activeGroupControl.getWidth() ) / this.groupHighlight.getWidth() ) * 100 );
		}

		new Effect.Parallel (
			[
				this.moving = new Effect.MoveBy(this.groupHighlight, 0, (elementOffset[0]-containerOffset[0]), {sync:true, duration:this.options.duration}),
				this.growing = new Effect.Scale(this.groupHighlight, calculatedGrowthPercentage, {sync:true, duration:this.options.duration, scaleY:false, scaleContent:false, scaleFromCenter:false})
			],
			{}
		);
	},
	scrollToSlide: function(slide){
		this.activeSlide = slide;

		Position.prepare();
		var containerOffset = Position.cumulativeOffset(this.viewport);
		var elementOffset = Position.cumulativeOffset(slide);

		this.scrolling = new Effect.SmoothScroll(this.viewport, {duration:this.options.duration, x:(elementOffset[0]-containerOffset[0]), y:(elementOffset[1]-containerOffset[1])});
	},
	setActiveGroupControlByGroupId: function(groupId) {
		this.groupControlsArray.each(function(control) {
			var controlTargetGroupId = control.href.split("#")[1];
			if ( groupId == controlTargetGroupId ) {
				this.activeGroupControl = control.up();
			}
		}.bind(this));
	},
	calculateNextSlide: function() {
		if ( null == this.activeSlide ) return this.slides[1];

		Position.prepare();
		var containerOffset = Position.cumulativeOffset(this.viewport);
		var elementOffset = Position.cumulativeOffset(this.activeSlide);
		var index = ((elementOffset[0]-containerOffset[0]) / this.options.slideWidth) + 1;

		// check to see if we have reached the last slide
		if ( index == this.slides.length ) return this.slides[0];

		return this.slides[index];
	},
	calculatePreviousSlide: function() {
		if ( null == this.activeSlide ) return this.slides[this.slides.length - 1];

		Position.prepare();
		var containerOffset = Position.cumulativeOffset(this.viewport);
		var elementOffset = Position.cumulativeOffset(this.activeSlide);
		var index = ((elementOffset[0]-containerOffset[0]) / this.options.slideWidth) - 1;

		// check to see if we have reached the last slide
		if ( index < 0 ) return this.slides[this.slides.length - 1];

		return this.slides[index];
	}
});

Effect.SmoothScroll = Class.create();
Object.extend(Object.extend(Effect.SmoothScroll.prototype, Effect.Base.prototype), {
	initialize: function(element) {
		this.element = $(element);
		
		var options = Object.extend({
			x: 0,
			y: 0,
			mode: 'absolute'
			} , arguments[1] || {}  );

		this.start(options);
	},
	setup: function() {
		if (this.options.continuous && !this.element._ext ) {
			this.element.cleanWhitespace();
			this.element._ext=true;
			this.element.appendChild(this.element.firstChild);
		}

		this.originalLeft=this.element.scrollLeft;
		this.originalTop=this.element.scrollTop;

		if(this.options.mode == 'absolute') {
			this.options.x -= this.originalLeft;
			this.options.y -= this.originalTop;
		} 
	},
	update: function(position) {
		this.element.scrollLeft = this.options.x * position + this.originalLeft;
		this.element.scrollTop  = this.options.y * position + this.originalTop;
	}
});

Event.observe(window,'load',function(){ new Slider('viewport', 'slider', 'groupControl', 'slideControl', {groupHighlightId:'groupHighlight'}); });
