/**
 *	    - тип смены слайдов: карусель, табы (плавный переход, мгновенно)
 *	    - режим: конечный, бесконечный
 *  	    - авто перемотка: вкл, выкл
 *  	    - перемотка кнопочками: вперёд, назад
 *	    - направление: горизонатльный, вертикальный
 *	    - количество слайдов во фрейме
 *	    - шаг, на сколько слайдов прокручивать: фрейм, 1, N
 *	    - скорость слайдов: 0 - X
 *	    - постраничная для фреймов
 *	    - поддержка спецэффектов (swing, scrolling...)
 */

// set Slider as jQuery plugin
(function($) {
    $.fn.slider = function(options, objects) {
        objects = objects || {};
	objects.wrap = this;
	return new Slider(objects, options);
    };
})(jQuery);

/**
*   If U want to cut this variable from global Namespace, you can move this ALL code to prev jQuery function
*   BUT then U can't create Slider by NEW (var carousel = new Slider(...), only by jQuery API, for ex: var tabSlider = $('#slider').slider({"type":"tabs"});
*/

var Slider = function(objects, options) {
    var self = this;

    // merge Default and User options for Slider object
    self.objects = $.extend({}, self.defaults.objects, objects);
    self.options = $.extend({}, self.defaults.options, options);

    // static slider identifer - unique for diferent sliders
    self.sliderIndex.val++;

    // "global" properties of current object
    self.core = {
	"slideIdPrefix" : "slider_index_" + self.sliderIndex.val + '_',
	"current" : 1,
	"isActing": false,
	"timer"	  : null,
	"reverse" : false,
	"previous" : null,
	"autoSlideRun" : false
    }

    // run Slider initialization
    self.init();

    // set "pulic" properties and methods
    return {
	"options" : self.options,
	"objects" : self.objects,
	"current" : function() {return self.core.current},
	"prev"	  : function() {self.prev()},
	"next"	  : function() {self.next()},
	"moveTo"  : function(index) {self.moveTo(index)}
    }
}

Slider.prototype.defaults = {
    "objects" : {
	"wrap"	: "#slider",
	"frame"	: ".frame",
	"roll"  : ".container",
	"slide"	: ".slide"
    },
    "options" : {
	// "carousel", "tabs"
	"type"		: "carousel",
	"loop"		: true,
	// experimental
	"fastClick"	: false,
	"autoSlide"     : false,
	// required when type "carousel"
	// "horizontal", "vertical"
	"sliderOrientation"	: "horizontal",
	// "normal", "revers"
	"sliderDirection"	: "normal",
	// "auto", 1 - N
	// required when type Carousel
	"slidesInFrame" : 1,
	// required when Orientation "horizontal"
	"slideSize"	: null,
	// "frame", 1 - N
	"step"		: 1,
	// if user do animation, autoslide reinit timer
	"autoSlideMode" : "adaptive",
	// 0 - N
	"speed"		: 1000,
	"interval"	: 5000,
	"onEndRoll"	: function(type) {},
	"onBeforeSlide"	: function(currIndex, prevIndex) {},
	"onAfterSlide"	: function(currIndex, prevIndex) {}
    }
}

// static slider identifer - unique for diferent sliders
Slider.prototype.sliderIndex = { "val" : 0 };

// Slider initialization
Slider.prototype.init = function() {
    var self = this;

    //init DOM Objects
    var wrap = self.objects.wrap = $(self.objects.wrap);
    for(var key in self.objects) {
	self.objects[key] = $(self.objects[key], wrap);
    }

    if(self.objects.slide.length <= self.options.slidesInFrame) {
	return;
    }

    self.initStyles();

    self.objects.slide.each(function(){
	var curIndex = self.objects.slide.index(this);
	$(this).attr('id', self.core.slideIdPrefix + (curIndex+1));
    })

    self.autoSlide();
}

Slider.prototype.autoSlide = function(delay) {
    var self = this;

    var beforeAnimate = function () {
	switch(self.options.autoSlideMode) {
	    case 'adaptive':
		// WTF??? It's not work!
//		if(self.userAnimate) {
//		    self.autoSlide();
//		    return false;
//		}
		// EXPERIMENT
		//alert($(':animated').length);
		if($(':animated').length>0) {
		    self.autoSlide(1000);
		    return false;
		}
		break;
	}
	self.core.autoSlideRun = true;
	return true;
    }

    if(self.options.autoSlide) {
	if(self.core.reverse) {
	    self.core.timer = setTimeout(function(){
		if(beforeAnimate()) {
		    self.prev()
		}
	    }, (delay || self.options.interval) );
	}
	else {
	    self.core.timer = setTimeout(function(){
		if(beforeAnimate()) {
		    self.next()
		}
	    }, (delay || self.options.interval) );
	}
    }
}

Slider.prototype.initStyles = function() {
    var self = this;
    switch(self.options.type) {
	case "carousel":
	    // set width of slides roll
	    if(self.options.sliderOrientation=="horizontal") {
		var rollSize = self.objects.slide.length * self.options.slideSize + self.options.slideSize;
		self.objects.roll.width(rollSize);
		self.objects.slide.css({"float" : "left"});
	    }
	    self.objects.roll.css({"position":"relative"});
	    break;
	case "tabs":
	    self.objects.slide.css({
		"position" : "absolute",
		"z-index"  : 1,
		"opacity"  : 1,
		"display"  : "none"
	    });
	    self.objects.slide.eq(0).css({"z-index" : "2"}).show();
	    break;
    }
}

Slider.prototype.next = function() {
    var self = this;
    var index = self.core.current + self.options.step;
    if(index > self.objects.slide.length) {
	index = index-self.objects.slide.length;
	if(!self.options.loop) {
	    index = self.objects.slide.length;
	}
    }
    self.core.reverse = false;
    self.moveTo(index, 1, self.options.step);
}

Slider.prototype.prev = function() {
    var self = this;
    var index = self.core.current - self.options.step;
    if(index <= 0) {
	index = self.objects.slide.length + index;
	if(!self.options.loop) {
	    index = 1;
	}
    }
    self.core.reverse = true;
    self.moveTo(index, -1, self.options.step);
}

Slider.prototype.moveTo = function(index, direction, distance) {
    var self = this;
    if(self.objects.slide.length <= self.options.slidesInFrame) {
	return;
    }
    if(self.core.isActing && !self.options.fastClick) {
	return;
    }

    switch(index) {
	case self.core.current:
	    return;
	    break;
	case 1:
	    // run event
	    self.options.onEndRoll('first');
	    break;
	case self.objects.slide.length:
	    // run event
	    self.options.onEndRoll('last');
	    break;
    }

    // run event
    self.options.onBeforeSlide(index, self.core.current);

    // mmm
    if(!self.core.autoSlideRun) {
	self.userAnimate = true;
    }

    clearTimeout(self.core.timer);

    var callback = function() {
	self.autoSlide();

	// mmm
	if(!self.core.autoSlideRun) {
	    self.userAnimate = false;
	}
	self.core.autoSlideRun = false;

	// run event
	self.options.onAfterSlide(index, self.core.current);
	self.core.isActing = false;
	self.core.current = index;
    }

    var acting = self.core.isActing;
    self.core.isActing = true;
    self.objects.slide = $(self.objects.slide.selector);

    switch(self.options.type) {
	case "carousel":
	    self.showSlide(index, callback, acting, direction, distance);
	    break;
	case "tabs":
	    self.showTab(index, callback, acting);
	    break;
    }
}

// TODO: Добавить разные эффекты,
// TODO: Добавить несколько слайдов во фрейме (точно надо?)
Slider.prototype.showTab = function(index, callback, acting) {

    var self = this;
    var terminateSwitch = function() {
	$('#' + self.core.slideIdPrefix + self.core.previous).stop().css({"opacity":1,"z-index":1}).hide();
	//$('body').append(self.core.previous + ' ' + self.core.current + ' ' + index + '<br />');
	$('#' + self.core.slideIdPrefix + self.core.current).css({"z-index":2});
        animateSwitch();
    }

    var animateSwitch = function() {
	var current = self.core.current;
	var next    = index;
	// for next animation
	self.core.previous = self.core.current;
	self.core.current = index;

	//$('body').append('show ind '+next+'; animate curr'+current);

	$('#' + self.core.slideIdPrefix + next).show();
	var animateCallback = function(){
	    $(this).css({"z-index":1, "opacity":1}).hide();
	    $('#' + self.core.slideIdPrefix + next).css({"z-index":2});
	    callback();
	}
	$('#'+ self.core.slideIdPrefix + current).animate({"opacity":0}, self.options.speed, 'linear', animateCallback);
    }

    var staticSwitch = function() {
	//self.objects.slide.hide();
	$('#' + self.core.slideIdPrefix + self.core.current).hide();
	$('#' + self.core.slideIdPrefix + index).show();
	callback();
    }

    if(self.options.speed>0 && acting) {
        return terminateSwitch();
    }
    if(self.options.speed>0) {
	return animateSwitch();
    }
    return staticSwitch();
}

Slider.prototype.showSlide = function(index, callback, acting, direction, distance) {
    var self = this;
//    if(self.options.loop) {
//	alert('Option "loop" is not available in "carousel" yet');
//    }
    // Перемещаем слайд на 1 позицию вправо или влево
    if(acting) {
	return false;
    }
    // Пока что доступно движение только с шагом в 1 слайд
    if(!self.options.loop && Math.abs(index-self.core.current)!=1) {
	//alert('incorrect index');
	return false;
    }

    var orientation = (self.options.sliderOrientation=="horizontal") ? 'left' : 'top';
    var properties = {};

    var nextDirection = function(step) {

	// Типа двигаем влево || вверх
	var animateCallback = function() {
	    // Сдвигаем контейнер
	    self.objects.roll.css(orientation, 0);
	    // Удаляем клонов
	    self.objects.slide.filter('.temp').remove();
	    callback();
	}

	for(i=0;i<=(step-1);i++) {
	    // Клонируем в конец контейнера
	    self.objects.slide.eq(i).clone().appendTo(self.objects.roll);
	    // Помечаем клона
	    self.objects.slide.eq(i).attr('id', '').addClass('temp');
	}

	properties[orientation] = -self.options.slideSize * step;
	self.objects.roll.animate(properties, self.options.speed * step, 'linear', animateCallback);
    }

    var prevDirection = function(step) {
	// Типа двигаем вправо || вниз
	var from = self.objects.slide.length;
	var to = self.objects.slide.length-step;

	for(i=from; i>=to; i--) {
	    // Клонируем в начало контейнера
	    self.objects.slide.eq(i).clone().prependTo(self.objects.roll);
	    // Помечаем клона
	    self.objects.slide.eq(i).attr('id', '').addClass('temp');
	}

	self.objects.roll.css(orientation, -self.options.slideSize * step);
	var animateCallback = function() {
	    // Удаляем клонов
	    self.objects.slide.filter('.temp').remove();
	    callback();
	}
	properties[orientation] = 0;
	self.objects.roll.animate(properties, self.options.speed * step, 'linear', animateCallback);
    }

/*    if(!direction) {
	// Пытаемся вычислить направление
	if(Math.abs(index-self.core.current) < ((self.objects.slide.length-self.core.current) + index)) {
	    direction = -1;
	    step = Math.abs(index-self.core.current);
	}
	else {
	    direction = 1;
	    step = ((self.objects.slide.length-self.core.current) + index);
	}
    }
    //$('body').append(self.core.current + '&rarr;' + index +  '; L' + (index-self.core.current) + ' || R' + ((self.objects.slide.length-self.core.current) + index) + '<br />');
*/
    if(!distance) {
        distance = self.options.step;
    }

    if(direction>0) {
	nextDirection(distance);
    }
    else {
	prevDirection(distance);
    }
}

Slider.prototype.userAnimate = false;
