/**
 * Class : mooSlide
 * ----------------
 * Author : Chris Sewell
 * Created on : 12/5/11
 * Description : Scrolls a list of elements inside a container
 */
var mooSlide = new Class({

	Implements: [Events,Options],
	
	options: {
		next_button: false,							// element to use as next button
		back_button:  false,						// element to use as back button
		starting_slide: 0,							// initial slide to view
		opacity: 0.4,										// opacity level of unselected slides
		slides_to_load: 1,							// how many slides to preload
		show_name: false,								// name of the array served up by the ajax array  ##!important
		duration: 750,									// animation duration
		transition: 'back:in:out',			// transition type
		ajax_enabled: false,						// flag to determine whether we use ajax or not
		wrapper_id: 'scroll_wrapper',		// id of wrapper element
		orientation: 'horizontal',			// which way should we scroll
		highlighting: true
	},
	
	hook_function: function(){}.bind(this),	// hook function to be run evertime a user clicks the back and next buttons
	
	more_to_load: true,
	slides: [],
	current_slide: 0,
	running: false,
	
	/**
	 * Initialises the class
	 *   creates the: -
	 *     request object
	 *     wrapper div
	 *     wrapper FX object
	 *   loads the initial slides
	 *   enables the back and next buttons
	 */
  initialize: function(container, options) {
  
  	// Create error console for IE output
  	this.error_console = new Element('div', {id:'error_console'});
  	this.error_console.inject($(document.body), 'bottom');
  	
		this.setOptions(options);
  	this.container = container;
		
		// Set css property to change based on orientation
		this.css_property = this.options.orientation=='horizontal' ? 'left' : 'top' ;
		
  	// Create request object
  	this.req = new Request({
  		url: '/ajax/get_slide',
  		link: 'chain',
  		async: false
  	});

		// Create a new <div> to wrap the elements inside the container
  	this.wrapper = new Element('div',{
  		id: this.options.wrapper_id,
  		styles: {
  			position: 'relative',
  			left: 0,
  			top: 0
  		}
  	});
  	// Add all slide elems to the new wrapper if we're not loading them later
  	if(!this.options.ajax_enabled){ this.wrapper.adopt(this.container.getChildren()); }
  	this.wrapper.inject(this.container, 'top');
  	
  	// Create the FX tween object to slide the wrapper about
  	this.wrapper_fx = new Fx.Tween(this.wrapper, {
			duration: this.options.duration,
			transition: this.options.transition,
			property: this.css_property,
			onStart: function(){
				this.running = true;
				this.disable_buttons();
				this.highlight_selected();
			}.bind(this),
			onComplete: function(){
				this.running = false;
				this.enable_buttons();
			}.bind(this)
		});
		
		// Add mousewheel event to container
		this.container.addEvent('mousewheel', function(e){
			e.stop();
			if(e.wheel>0){ this.back(); }
			else{ this.next(); }
		}.bind(this));
		
		// Load initial slides via ajax
		if(this.options.ajax_enabled){
			var slide_nums = '';
	  	for(var i=0; i<this.options.slides_to_load; i++){ slide_nums = slide_nums+i+','; }
	  	slide_nums = slide_nums.substring(0, slide_nums.length-1);
	  	this.load_slides(slide_nums);
	  //  Or grab the existing html if we're not using ajax
  	} else {
  		this.slides = this.wrapper.getChildren();
  	}
  	this.highlight_selected();
  	
  	// Add click events to the next and back buttons
  	this.enable_buttons();
  	
  	this.show_slide(this.options.starting_slide);

	},
	
	/**
	 * Tag an error to the bottom of the error console
	 */
	add_error: function(err){
		var p = new Element('p', {'html': err});
		p.inject(this.error_console, 'bottom');
	},
	
	/**
	 * Move the wrapper to show a specific slide
	 */
	show_slide: function(slide_num){
		// Load additional slides if we need to
		if((slide_num >= this.slides.length) && this.options.ajax_enabled){
			var slide_nums = '';
			for(var i=this.slides.length; i<=slide_num; i++){
				slide_nums = slide_nums+i+',';
			}
			slide_nums = slide_nums.substring(0, slide_nums.length-1);
			this.disable_buttons();
			this.load_slides(slide_nums);
			this.enable_buttons();
		}
		// Move the wrapper to show the desired slide when we're ready
		this.ready_check = this.go_to_slide.periodical(500, this, slide_num);
	},
	
	/**
	 * got_to_slide
	 * ------------
	 * Calculates the distance required to move and moves the content accordingly
	 *
	 * @param int slide-num the array key of the slide we want to go to
	 */
	go_to_slide: function(slide_num){
		if(this.load_completed || !this.options.ajax_enabled){
			clearInterval(this.ready_check);		
			//get scroll distance
			var distance = 0;
			if(slide_num < this.current_slide){
				for(var i=slide_num; i<this.current_slide; i++){
					distance += this.calculate_distance(i);
				}
				var new_pos = this.wrapper.getStyle(this.css_property).toInt() + distance;
			}
			if(slide_num > this.current_slide){
				for(var i=slide_num; i>this.current_slide; i--){
					distance += this.calculate_distance(i);
				}
				var new_pos = this.wrapper.getStyle(this.css_property).toInt() - distance;
			}
			if(slide_num!=this.current_slide){
				this.wrapper_fx.start(new_pos);
			}
			this.current_slide = slide_num;
			this.highlight_selected();
			this.hook_function();
		}
	},
	
	/**
	 * Highlights the selected slide
	 */
	highlight_selected: function(){
		if(this.options.highlighting){
			this.slides.setStyle('opacity', this.options.opacity);
			this.slides[this.current_slide].setStyle('opacity', 1);
		}
	},
	
	/**
	 * Add the click events to the next and back buttons
	 */
	enable_buttons: function(){
  	this.options.next_button.addEvent('click', function(){this.next()}.bind(this));
  	this.options.back_button.addEvent('click', function(){this.back()}.bind(this));
	},
	
	/**
	 * Removes click events from the next and back buttons
	 */
	disable_buttons: function(){
  	this.options.next_button.removeEvents('click');
  	this.options.back_button.removeEvents('click');
	},
	
	/**
	 * Calculate distance
	 */
	calculate_distance: function(index){
		var temp = this.slides[index].getSize();
		var size = this.options.orientation=='horizontal' ? temp.x : temp.y ;
		var margin1 = this.options.orientation=='horizontal' ? 'margin-left' : 'margin-top' ;
		var margin2 = this.options.orientation=='horizontal' ? 'margin-right' : 'margin-bottom' ;
		var distance = 	size + 
										this.slides[index].getStyle(margin1).toInt() + 
										this.slides[index].getStyle(margin2).toInt();
		return distance;
	},
	
	/**
	 * Slide the wrapper to show the next slide
	 */
	next: function(){
		if(!this.running){
			// load another slide if there is one
			if(this.more_to_load && this.options.ajax_enabled) this.load_slides(this.slides.length);
	  	
			// calculate the current position and move to the next slide if there is one
			if(this.current_slide < this.slides.length-1){
				var distance = this.calculate_distance(this.current_slide);
	  		var pos = this.wrapper.getStyle(this.css_property)=='auto' ? 0 : this.wrapper.getStyle(this.css_property).toInt();
				var new_pos =  pos - distance;
				this.current_slide++;
				this.wrapper_fx.start(new_pos);
			}
			this.hook_function();
		}
	},
	
	/**
	 * Slide the wrapper to show the previous slide
	 */
	back: function(){
		if(!this.running){
			// calculate the current position and move to the next slide if there is one
			if(this.current_slide > 0){
				var distance = this.calculate_distance(this.current_slide);
	  		var pos = this.wrapper.getStyle(this.css_property)=='auto' ? 0 : this.wrapper.getStyle(this.css_property).toInt();
				var new_pos = pos + distance;
				this.current_slide--;
				this.wrapper_fx.start(new_pos);
			}
			this.hook_function();
		}
	},
	
	/**
	 * Adds the passed in slide to the bottom of the wrapper 
	 * element, then resets the this.slides var
	 */
	add_slide: function(new_slide){
		// convert html string to DOM element
		var slide = Elements.from(new_slide)[0];
		slide.inject(this.wrapper);
		// reset main slides array
		this.slides = this.wrapper.getChildren();
		return;
	},
	
	/**
	 * Loads slides via ajax
	 * @param INT num Ajax array index number of the slide to load
	 */
	load_slides: function(nums){
		if(!this.options.show_name) return false;
		this.load_completed = false;
		var num = num!=undefined ? num : 0 ;
		var slide_html = JSON.decode(this.req.send('show_name='+this.options.show_name+"&num="+nums).response.text);
		// catch a 'no data' error
		if(slide_html==0) return false;
		// stop further ajax requests if all slides are loaded
		if(slide_html == 'finished') {
			this.more_to_load = false;
			this.load_completed = true;
			return;
		}
		// create all returned slides and add them to the wrapper
		Array.each(slide_html, function(html_str){
			this.add_slide(html_str);
		}, this);
		this.load_completed = true;
		return;
	}
});
