/* 
 * slide div boxes
 * @plugin textSlider
 * @author {macem | acem@go2.pl} Marcin Sołtysiuk
 * @version {0.6beta}
 * @support {IE6+ , FF , Safari , Opera}
*/

$.fn.textSlider = function (o) {
	
	var $self = $(this);
	
	var options = $.extend ({}, {
		header    : 'div.t-container div > h3',
		elements  : '> div',
		_class    : 't-slider',
		loadClass : 't-loader',
		step      : 1,  // how many slides
		axis      : 'horizontal', // [vertical,horizontal]
		slide     : 0,  // current slide
		nextslide : 0,  // next slide
		mousewheel: true,
		auto      : false, // [left, previous]  autoslide
		autostop  : 'slideshow stopped', 
		onAuto    : function() {},
		onAutoStop: function() {},
		wait      : 3000,
		breadcrumb: true,
		around    : true,
		//breadcrumbText : '%s slide',  TODO
		breadcrumbTitle : 'slide ',
		navigate  : true,
		animate   : 'slide',
		animoption: [1000], 
		autosize  : false, // time for size ms
		method : {
			coords : function (option) {
				if (option.axis == 'horizontal') return {
					left: -option._nextposition
				} 
				else if (option.axis == 'vertical') return {
					top: -option._nextposition
				};				
			}		
		},
		animations: {
			slide : function ($container, slides, option) {
				$container.animate (option.method.coords (option), option.animoption[0], function () {
					option._animation = false;
				});
			},
			show : function ($container, slides, option) {
				$container.css (option.method.coords (option));
				option._animation = false;
			},
			fade : function ($container, slides, option) {
				$container.fadeOut (option.animoption[0], function () {
					$container.css (option.method.coords (option))
					.fadeIn (option.animoption[0], function () {
						option._animation = false;
					});
				});

			},
			resize : function ($container, slides, option) {
				var width = [slides.next.width(), slides.current.width()], right = true;
				slides.current.animate ({width: '0'}, 1500);
				if (option.slide > option.nextslide) right = false; // because of animation-setimeout
				slides.next.css({width:'0'}).animate ({width: width[0]+'px'}, 1500, function() {
					slides.current.removeAttr('style');
					if (right) $container.css (option.method.coords (option));
					option._animation = false;	
				});
				if (!right) $container.css (option.method.coords (option));
			}				
		},
		onCreate : function () {},
		onSlide  : function () {},
		_nextposition : 0,
		previous : {
			text : 'previous slide',
			title : 'show previous slide [B]',
			accesskey : 'B'
		},
		next : {
			text : 'next slide',
			title     : 'show next slide [N]',
			accesskey : 'N'
		}	
	}, o);
	
	// display slide
	function display ($self, $container) {
		var node = $container[0].parentNode;
		var $slides = {
			current : $(node.options.elements + ':eq(' + node.options.slide + ')', $container),
			next    : $(node.options.elements + ':eq(' + node.options.nextslide + ')', $container)
		}
		
		node.options._animation = true;

		node.options._nextposition = 0;
		
		$slides.next.prevAll ('.t-slide').each (function() {
			if (node.options.axis == 'horizontal') {
				var step = this.offsetWidth + parseInt($(this).css('margin-left').replace(/(\d*)\w*/gim, '$1')) + parseInt($(this).css('margin-right').replace(/(\d*)\w*/gim, '$1'));
			} else {
				var step = this.offsetHeight + parseInt($(this).css('margin-top').replace(/(\d*)\w*/gim, '$1')) + parseInt($(this).css('margin-bottom').replace(/(\d*)\w*/gim, '$1'));			}
			node.options._nextposition += step;	
		});
		
		node.options.onSlide (node, $slides);
				
		$self[0].blur();
		
		current (node.options.nextslide, node);
		
		node.options.animations[node.options.animate] ($container, $slides, node.options);

		if (node.options.autosize) autosize (node, $slides.next);

		if (node.options.auto) auto (node);
		
		node.options.slide = node.options.nextslide;
	}
	
	// get slide width  TODO
	function width ($slide, step) {
		var width = $slide[0].offsetWidth;
		for (var i=1; i < step; i++) {
			width += $slide.next ('.t-slide')[0].offsetWidth;	
		}
		return width;		
	}
	// get slide height
	function height ($slide, step) {
		var height = $slide[0].offsetHeight;
		for (var i=1; i < step; i++) {
			height += $slide.next ('.t-slide')[0].offsetHeight;
		}
		return height;		
	}
	
	// autoslide	
	function auto (self) {
		if (!self.options.auto || self.options.mouseover) return;
		
		self.options.onAuto (self);

		// cache for DOM elements
		$('ul.t-breadcrumb a:eq(' + self.options.nextslide + ')', self).fadeTo (self.options.wait, 0, function () {
			this.removeAttribute ('style');
		});
				
		self.options._timeout = window.setTimeout (function (){
			trigger ($(self), (self.options.auto == 'next' ? 't-next' : 't-previous'));
		}, self.options.wait); 
	}
	
	// show custom slide
        function custom () {
		var $this = $(this), $self = $this.parents ('div.t-slider');
		var $container = $('div.t-container', $self);
		
		$self[0].options.nextslide = parseInt ($this.attr ('slide'));
		display ($this, $container);
		
		return false;
	}

	// show next slide 
	function next() {
		var $this = $(this), $self = $this.parents ('div.t-slider'); // TODO _class
		var $container = $('div.t-container', $self);
                var o = $self[0].options;
                
                if (!o._animation) {
			o.nextslide = o.slide + o.step;
			if (o.nextslide > ($(o.elements, $container).length-1)) o.nextslide = 0;
			display ($this, $container);
		}

		return false;
	}
	
	// show previous slide
        function previous() {
		var $this = $(this), $self = $(this).parents ('div.t-slider');
		var $container = $('div.t-container', $self);
                var o = $self[0].options;
		                
                if (!o._animation) {
			o.nextslide = o.slide - o.step;
			if (o.nextslide < 0) o.nextslide = $(o.elements, $container).length - o.step;
			display ($this, $container);
		}

		return false;
	}
	
	// select current breadcrumb
	function current (id, $self) {
		$('ul.t-breadcrumb a.active', $self).removeClass ('active');
		$('ul.t-breadcrumb a[slide=' + id + ']', $self).addClass ('active');
	}
	
	// create breadcrumb		
	function breadcrumb ($this) {
		var $breadcrumb = $('<ul/>').addClass ('t-breadcrumb');
		var $elements = $('div.t-container' + $this[0].options.elements, $this);
		for (var i=0, len=$elements.length; i<len; i=i+$this[0].options.step) {
			var header = $('> h3', $elements[i]);
			$('<li><a href="#slide" title="' + (header.text()||($this[0].options.breadcrumbTitle+(i+1))) + '" slide="' + i + '">' + i + '</a></li>').appendTo ($breadcrumb);	
		}
		return $breadcrumb;	
	}
	
	// create navigation
	function navigate ($this) {
	        $this.append ($('<a/>').addClass ('t-previous').text(options.previous.text).attr ({
			href      : '#previous-slide',
			accesskey : options.previous.accesskey,
			title     : options.previous.title
		}));
		$this.append ($('<a/>').addClass ('t-next').text(options.next.text).attr ({
			href      : '#next-slide',
			accesskey : options.next.accesskey, 
			title     : options.next.title
		}));	
	}

	// trigger nect/previous
	function trigger (self, event) {
		$('<a class="' + event + '"/>').appendTo(self).trigger ('click').remove();	
	}
	
	// event mousewheel TODO 
	function wheel (event) {
		var delta;
		if (window.event && window.event.wheelDelta) { /* IE/Opera. */
			delta = window.event.wheelDelta/120;
		} else if (event.detail) { /** Mozilla case. */
			delta = -event.detail/3;
		}
		
		if ($self[0].options.mouseover) {
			trigger ($self, (delta > 0 ? 't-next' : 't-previous'));
			
			if (window.addEventListener) {
				event.preventDefault();
			} else {
				window.event.returnValue = false;
			}
			
			return false;
		}
	}

	// set size
	function autosize (node, $next) {
		var coords;
		
		if (node.options.axis == 'horizontal') 
			coords = {width: width ($next, node.options.step)};
		
		if (node.options.axis == 'vertical') 
			coords = {width: $next.width(), height: height ($next, node.options.step)};
			
		$(node).animate (coords, node.options.autosize);	
	}
				
	this.each (function () {
		var $this = $(this);

		// events TODO check if added
                $('a.t-previous').die ('click', previous);
		$('a.t-previous').live ('click', previous);
	        $('ul.t-breadcrumb a').die ('click', custom);
	        $('ul.t-breadcrumb a').live ('click', custom);	
		$('a.t-next').die ('click', next);
		$('a.t-next').live ('click', next);
	
               	if (!$this.hasClass (options._class)) { $this.addClass (options._class); };
               	if (!$this.hasClass ('t-' + options.axis)) { $this.addClass ('t-' + options.axis); };
               	
               	// remove
		if (!$('div.t-container', this).length) { $this.html ('<div class="t-container">' + $this.html() + '</div>'); }

                $('.t-container' + options.elements).addClass ('t-slide');
                
                var $slide = $('.t-container' + options.elements + ':eq(' + options.slide + ')', $this);

		if (options.mousewheel) {		
			if (window.addEventListener) window.addEventListener ('DOMMouseScroll', wheel, false);
			else document.onmousewheel = wheel;
		}

		// autoslide
		$this.mouseover (function () {
			this.options.mouseover = true;
			if (this.options.auto) {
				window.clearTimeout (this.options._timeout);
				$('<p class="t-notice">' + this.options.autostop + '</p>').appendTo (this);
				$('ul.t-breadcrumb a:eq(' + this.options.slide + ')', this).stop().removeAttr ('style');
				(this.options.onAutoStop ? this.options.onAutoStop (this) : null);
			}
		});
		$this.mouseout (function () {
			this.options.mouseover = false;
			if (this.options.auto) {
				auto (this);
				$('.t-notice', this).remove();
			}	
		});

                this.options = options;
                
                if (options.navigate) navigate ($this);
                
		if (options.breadcrumb) {
			breadcrumb ($this).appendTo ($this);
			current (options.slide, $this); 
		}

		if (options.slide != 0) {
			this.options.nextslide = options.slide;
			this.options.slide = 0;
			display ($this, $('div.t-container', this)); 
		} 
		else if (options.autosize) autosize (this, $slide);

		if (options.auto) auto (this);
		
		options.onCreate (this);
	});
	
	$.fn.extend ({
		
		textSliderUpdate : function (o) {
			this.each (function () {
				var $this = $(this);
				
				if (o) {
					this.options = $.extend ({}, this.options, o);
				}
								
				if (o.nextslide != undefined && o.nextslide.toString().length) {
					display ($this, $('div.t-container', this));
				} 

				if (o.breadcrumb != undefined && o.breadcrumb.toString().length) {
					var $breadcrumb = $('ul.t-breadcrumb', this);
					if (this.options.breadcrumb && !$breadcrumb.length) breadcrumb ($this).appendTo (this);
					if (!this.options.breadcrumb && $breadcrumb.length) $breadcrumb.remove();
				}
				
				if (o.navigate != undefined && o.navigate.toString().length) {
					var $navigate = $('.t-previous, .t-next', this);
					if (this.options.navigate && !$navigate.length) navigate ($this);
					if (!this.options.navigate && $navigate.length) $navigate.remove();
				}				
			});		
		},
		
		textSliderDestroy : function () {
			this.each (function () {
				$('.t-previous, .t-next, ul.t-breadcrumb', this).remove();
				$('.t-container' + this.options.elements).removeClass ('t-slide');
				$(this).removeAttr ('style')
				.removeClass ('t-' + this.options.axis)
				.removeClass (this.options._class);
				
				$('ul.t-breadcrumb a').die ('click', custom);
				$('a.t-next').die ('click', next);
				$('a.t-previous').die ('click', previous);
				
				delete this.options;
			});
		}			
	});
}
