/**
 * A class that makes a contentblocks collection slidable
 * (Inspired on implementation in Topsport)
 *
 * @since Thu Apr 14 2011
 * @author Giso Stallenberg
 **/
var WJCarousel = Class.create({
	/**
	 * initialize
	 *
	 * Creates a new WJCarousel
	 *
	 * @since Thu Apr 14 2011
	 * @access public
	 * @param integer id
	 * @param Object options
	 * @return WJCarousel
	 **/
	initialize: function(id, options, slideselectors) {
		this.id = id;
		this.wrapper = $(id + "_brandboxwrapper");
		this.container = $(id + "_brandboxcontainer");
		this.content = $(id + "_brandboxcontent");
		this.slideselectors = slideselectors;
		this.slidewrapper = this.content.down(this.slideselectors["slidewrapper"] );
		
		this._setOptions(options);
		this._getSlides();
		if (this.options.horizontal) {
			this._fixWidth();
		}
		this._addObservers();
		this._initializeControls();
		
		this._initializeCarousel();
	},
	
	/**
	 * _getSlides
	 *
	 * Looks up all slides (in other words contentblocks)
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @return array
	 **/
	_getSlides: function() {
		this.slides = this.slidewrapper.select(this.slideselectors["slides"] );
		this.first = this.slides.first();
		
		if (this.slides.size() > this.options.visibleSlides && this.options.circular) {
			$R(1, this.options.visibleSlides).each(function(index) {
				this.last = this._addSlide(this.slides[index - 1].cloneNode(true) );
				this.last.clonePosition(this.slides[index - 1], {setLeft: false, setTop: false});
				this._cleanIds(this.last);
			}.bind(this) );
		}
		
		this._activateSlide(this.first);
		return this.slides;
	},
	
	/**
	 * _activateSlide
	 *
	 * Activates the given slide
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @param Element slide
	 * @return Element
	 **/
	_activateSlide: function(slide) {
		this.slides.invoke("removeClassName", "carousel-slide-active");
		return slide.addClassName("carousel-slide-active");
	},

	/**
	 * _deactivateSlide
	 *
	 * Deactivate a slide
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @param Element slide
	 * @return Element
	 **/
	_deactivateSlide: function(slide) {
		return slide.removeClassName("carousel-slide-active");
	},
	
	/**
	 * _addSlide
	 *
	 * Adds a slide to the slides (NOTE: does not add a jumper for the slide)
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @param Element slide
	 * @return Element
	 **/
	_addSlide: function(slide) {
		this.slides.first().up().appendChild(slide);
		this.slides.push(slide);
		return slide;
	},
	
	/**
	 * _cleanIds
	 *
	 * Cleans all id's from the given element
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @param Element element
	 * @return Element
	 **/
	_cleanIds: function(element) {
		element.id = null;
		element.select("*[id]").each(function(el) {
			el.id = null;
		} );
		return element;
	},
	
	/**
	 * _fixWidth
	 *
	 * Fixes the width of the wrapper of the slides
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @return void
	 **/
	_fixWidth: function() {
		var width = this.first.getDimensions().width;
		var count = this.slides.size();
		this.slidewrapper.setStyle( {"width": (width * count) + "px"} );
	},
	
	/**
	 * _setOptions
	 *
	 * Sets the options
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @return Object
	 * @see http://code.google.com/p/prototype-carousel/ (for options)
	 **/
	_setOptions: function(options) {
		this.options = Object.extend({
			wheel:         false,
			duration:      1,
			auto:          true,
			frequency:     15,
			circular:      true,
			horizontal:    true,
			visibleSlides: 1
		}, (options || {}) );
		return this.options;
	},
	
	/**
	 * _addOption
	 *
	 * Adds (or overwrites) an option
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @param string name
	 * @param mixed value
	 * @return void
	 **/
	_addOption: function(name, value) {
		this.options[name] = value;
	},

	/**
	 * _addObservers
	 *
	 * Adds the before and after observers
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @return void
	 **/
	_addObservers: function() {
		this._addOption("beforeMove", this._beforeMove.bind(this) );
		this._addOption("afterMove", this._afterMove.bind(this) );
	},

	/**
	 * _initializeControls
	 *
	 * Initializes the controls
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @return array
	 **/
	_initializeControls: function() {
		if (this.slides.size() <= this.options.visibleSlides) {
			this.container.select("div.carousel-controls").invoke("remove");
			return;
		}
		this.controls = this.container.select("a.carousel-control");
		if (this.container.select("a.carousel-jumper").size() > 0) {
			this.jumpers = this.container.select("a.carousel-jumper");
			this.jumpers.first().addClassName("carousel-jumper-active");
			this._addOption("selectedClassName", "carousel-jumper-active");
			this.controls = (this.controls.size() > 0) ? this.controls.concat(this.jumpers) : this.jumpers;
		}
		return this.controls;
	},

	/**
	 * _initializeCarousel
	 *
	 * Creates the carousel
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @return Carousel
	 **/
	_initializeCarousel: function() {
		this.carousel = new Carousel(this.content, this.slides, this.controls, this.options);
		return this.carousel;
	},

	/**
	 * _afterMove
	 *
	 * Performs actions when moving is complete
	 * If the last (additional added) slide is called which is the same as the first slide, select the first jumper
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @return void
	 * @fires brandbox:end
	 **/
	_afterMove: function() {
		if (this.jumpers) {
			this.jumpers.invoke("removeClassName", this.carousel.options.selectedClassName);
			if (this.carousel.current.id) {
				this.container.select("a[rel=" + this.carousel.current.id + "]").invoke("addClassName", this.carousel.options.selectedClassName);
			}
			else if (this.carousel.slides[0].id) {
				this.container.select("a[rel=" + this.carousel.slides[0].id + "]").invoke("addClassName", this.carousel.options.selectedClassName);
			}
		}
		if (this.controls && this.options.circular === false) {
			this.controls.invoke("removeClassName", "carousel-control-disabled");
			var disable = (this.carousel.current === this.slides.first() ) ? "prev" : "next";
			this.controls.each(function(disable, control) {
				if (control.readAttribute("rel") === disable) {
					control.addClassName("carousel-control-disabled");
				}
			}.curry(disable) );
		}
		this._activateSlide(this.carousel.current);
		this._fireEvent("end");
	},

	/**
	 * _beforeMove
	 *
	 * Performs actions when moving is started
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @return void
	 * @fires brandbox:start
	 **/
	_beforeMove: function() {
		this._fireEvent("start");
	},

	/**
	 * _fireEvent
	 *
	 * Fires the given event from this.container
	 *
	 * @since Thu Apr 14 2011
	 * @access protected
	 * @param string name
	 * @return void
	 **/
	_fireEvent: function(name) {
		this.container.fire("brandbox:" + name, {"carousel": this} );
	}
});

