/*
  The jquery.pistoleto plugin - nice looking vertical bar menu with big images 

  Package contents:
    jquery.pistoleto.js
    jquery.pistoleto.css
  
  Used CSS classes:
    pistoleto, active
  
  Example usage:
  	$('#something').pistoleto();
  	
  HTML:
	<dl style="height: 400px; width: 600px;" id="promo" class="pistoleto">
		<dt class="active"><div></div><a href="#">Punkt 1</a></dt>
		<dd class="active"><img src="images/01.jpg" alt="Image 01" /></dd>

		<dt><div></div><a href="#">Punkt 2</a></dt>
		<dd><img src="images/02.jpg" alt="Image 02" /></dd>

		<dt><div></div><a href="#">Punkt 3</a></dt>
		<dd><img src="images/03.jpg" alt="Image 03" /></dd>
		
		<dt><div></div><a href="#">Punkt 4</a></dt>
		<dd><img src="images/04.jpg" alt="Image 04" /></dd>
	</dl>
	  
  Author: Andrey Gusev <gauss-gs@izhpt.com>
  
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.  
 */


(function($){

	$.fn.pistoleto = function(input) {
		
		function clamp(value, min, max) {
			if(value <= min) return min;
			else if(value >= max) return max;
			else return value;
		}
		function wrap(value, via) {
			if(value > 0) return value % via;
			else return Math.abs(via + value) % via;
		}
		
		var self = this;		
		var data = $(this).data('pistoleto');
		
		var methods = {
			'transition': function(auto){
			
				self.find('dd .text').css({'opacity': 0});
			
				/* transition already running */
				if(data.transitionId && !auto) return;
				
				/* first step */
				if(!data.transitionId && !auto) {
					
					self.trigger('motion-start');
					self.find('dt.active div').fadeOut('fast', function(){
						self.find('dt').removeClass('active');
						methods['transition'](true);						
					});					
					return;
				}

				/* other */
				var els = self.find('dt');
				var step = 360.0 / els.length;
				 
				/* position */
				var newPos = step * data.newSelected;
				var fpath = Math.abs(newPos - data.pos - data.speed) % 360.0;
				var bpath = (Math.abs(360.0 - Math.max(newPos, data.pos)) + Math.min(newPos, data.pos) - data.speed) % 360.0;
				var path = 0.0; var accel = 1.0;
				
				/* direction */
				if(newPos < data.pos) accel = -accel;
				if (bpath < fpath) {
					path = bpath; accel = -accel;
				} else {
					path = fpath;
				}
				
				/* accel factor */
				accel *= path * data.accelFactor;

				/* calculate speed */				
				data.speed = clamp(data.speed + accel, -data.maxSpeed, data.maxSpeed);
				data.pos = wrap(data.pos + data.speed, 360.0);					

				/* calculate friction */
				if(Math.abs(data.speed) > 1.0) data.speed *= 0.4;

				var finished = false;
				if (path < 1.0 && Math.abs(data.speed) <= 1.0) {
					data.pos = newPos;
					data.speed = 0;
					finished = true;
				}
				
				els.each(function(k, v) {
					var phi = (data.pos - step * k) / 180.0 * Math.PI;
					var o = $(v).css({
						/*
						'padding-top': Math.round(25.0 + 15.0 * Math.cos( phi )) + 'px',
						'padding-bottom': Math.round(25.0 + 15.0 * Math.cos( phi )) + 'px',
						*/
						'z-index': Math.round( 10 + els.length + els.length * Math.cos( phi ) ),
						'opacity': 0.5 + 0.5 * Math.cos( phi )
					});
					var h = self.height() / 2.0 - $(v).outerHeight() / 2.0;
					o.css({
						'top': Math.round(h + h * Math.sin( phi )) + 'px',
						'width': Math.round(data.activeWidth + data.activeWidth * Math.cos( phi )) + 'px',
					});
				});

				/* execute finish script */
				if (finished) {
					var selected = data.newSelected; 
					self.find('dt:eq(' + selected + ')').addClass('active').find('div').fadeIn('fast');
					self.queue(function(){
						self.find('dd.active').css('z-index', 1).animate({
							'opacity': 0
						}, data.effectTime, function() {
							self.dequeue();
						});
					}).queue(function(){
						
						self.find('dd.active').css('opacity', 0).removeClass('active');
						self.find('dd:eq(' + selected + ')').css({
							'opacity': 0,
							'z-index': 2,
							'display': 'block'
						}).animate({
							'opacity': 1
						}, data.effectTime, function() {
							self.dequeue(); 
														
							var currentDate = new Date();

							self.find('dd.active .text').animate({opacity: 1},2000);
							
							self.find('dd.active .slider').easySlider({
								auto: true, 
								continuous: true,
								numeric: true,
								numericId: 'controls'+currentDate.getTime(),
								speed: 1000,
								pause: 5000,
							});
							
							self.find('dd.active .slider').removeClass('slider').addClass('unslider');
							
							
							
						});						
						
						
					}).queue(function(){
						self.find('dd:eq(' + selected + ')').css({
							'opacity': 1,
							'display': 'block'
						}).addClass('active');
						data.selected = selected;
						self.trigger('motion-stop');					
						self.dequeue();						
					});
				}
				
				/* execute next timeout */
				if (!finished) data.transitionId = setTimeout(function() { methods['transition'](true); }, data.stepInterval);
				else data.transitionId = null;
			},
			'current': function() { return data.selected; },
			'select': function(page){
				var len = $(self).find('dd').length;
				if (page >= 0) data.newSelected = page % len;
				else data.newSelected = len - ( Math.abs(page) % len );
				
				methods['transition']();			
			},
			'next': function() { methods['select'](data.selected + 1); },
			'prev': function() { methods['select'](data.selected - 1); }
		};
		
		/* standart method invocation procedure */
		if(methods[input]) {
			methods[input].apply(self, Array.prototype.slice.call(arguments, 1));
		} else if(typeof input == 'object' || !input) {
			data = $.extend({}, $.fn.pistoleto.defaults, input);

			self.find('dt').each(function(k, v) {
				$(v).css('display', 'block');
				$(v).bind('click.pistoleto', function(){ methods['select'](k); });
				
			});
		
			methods['select'](0);
			
		} else {
			$.error('Method ' + input + ' does not exist in pistoleto!');
		}
		
		$(self).data('pistoleto', data);
		
		return self;
	};
	$.fn.pistoleto.defaults = {
		'stepInterval': 30,
		
		'accelFactor': 0.4,
		'maxSpeed': 10.0,
		
		'effectTime': 500,
		
		'activeWidth': 100,
		
		/* internal attrs */
		'selected': 0,
		'oldSelected': 0,
		'newSelected': 0,

		'pos': 0,
		'speed': 0.0
	};
	
}(jQuery));

