

(function($) {
	
	var defaultControl = {
		
		width:	0,
		height:	0,
		children:	null,
	    root:	undefined,
	    displayTime:	9000,
		transitionType:	'fade',
		
		transitionSpeed:	2000,
		
	
		containerClass:	undefined,
		
	
		caption:	undefined,
		
		
		captionChild:	undefined,
		
		
		captionFn: function (el, i) {
			return $(el).find('img').attr('title');
		},
		
		
		captionClass: undefined,
		
		
		next:	'',
		previous:	'',
		play:	'',
		pause:	'',
		
		
		transitionBefore: undefined,
		transitionAfter: undefined,
		
		
		playFn: '',
		pauseFn: '',
		
		overlayTop:	0,
		overlayBottom:	0,
		overlayLeft:	0,
		overlayRight:	0,
		overlayCenter:	0
	};
	
	var Control = function (container, options) {
		options = this.options = $.extend({}, defaultControl, options);
		
		
		var thisControl = this;
		
	
		$container = this.$container = $(container);
		
		
		if (options.root) {
			this.$root = $(options.root);
		}
		
	
		var $element_set = this.$container.children(options.children);
		this.length = $element_set.length;
		if (this.length == 0) {
			return;
		}
		
	
		var controls = ['next','previous','play','pause'];
		for (var i=0; i<controls.length; i++) {
			(function () {
				var control = controls[i];
				if (options[control]) {
					thisControl.find(options[control]).click( function (e) {
						e.preventDefault();
						thisControl[control]();
					});
				}
			})();
		}
		
		
	
		this.transition = {};
		
	
		if (options.caption) {
			this.$caption = this.find(options.caption);
			var captionChild = options.captionChild;
			if (!captionChild) {
				
				var conType = this.$caption.get(0).tagName;
				captionChild = (conType == 'UL' || conType == 'OL') ? 'li' : 'div';
				captionEl = '<'+captionChild+'></'+captionChild+'>';
				
				
				var captionFn = options.captionFn;
				for (var i=0; i<this.length; i++) {
					this.$caption.append(
						$(captionEl).append(
							captionFn($element_set.get(i), i)
						)
					);
				};
			}
		
			this.transition.caption = new Transition({
				$container:	this.$caption,
				$element_set:	this.$caption.children(captionChild),
				type:		options.transitionType,
				speed:		options.transitionSpeed
			});
		}
		
	
		this.transition.main = new Transition({
			$container:	$container,
			$element_set:	$element_set,
			type:		options.transitionType,
			speed:		options.transitionSpeed,
			containerClass:	options.captionClass,
            width:      options.width,
            height:     options.height
		}, function () {
			thisControl.startCountdown();
		});
		
		
		this.currentId = 0;
		this.changing = false;
		this.playing = false;
	};
	
	$.extend(Control.prototype, {
        add: function ($el) {
            this.$container.append($el);
            this.transition.main.add($el);
            this.length++;
            return this;
        },
        end: function () {
            
            return this.$container;
        },
		find: function (selector) {
			if (!this.$root) {
				return $(selector);
			}
			return this.$root.find(selector);
		},
        
        isEnabled: function () {
          
            if (this.length > 1)  {
                return true;
            }
            return false;
        },
		
		
		previous: function () {
           
            if (!this.isEnabled()) {
                return;
            }
            
		
			if (this.changing) {
				return;
			}
			
			
			this.stopCountdown();
			
		
			var nextId = this.currentId - 1;
			if (nextId < 0) {
				nextId = this.length + nextId;
			}
			this.show(nextId);
		},
		next: function () {
           
            if (!this.isEnabled()) {
                return;
            }
            
			
			if (this.changing) {
				return;
			}
			
			
			this.stopCountdown();
			
			
			var nextId = (this.currentId + 1) % (this.length);
			this.show(nextId);
		},
		pause: function () {
			this.playing = false;
			this.stopCountdown()
			
			
			if (this.options.pauseFn) {
				this.options.pauseFn(this, this.currentId);
			}
		},
		play: function () {
			this.playing = true;
			this.startCountdown()
			
			
			if (this.options.playFn) {
				this.options.playFn(this, this.currentId);
			}
		},
		startCountdown: function () {
			
			this.stopCountdown();
			
			if (!this.playing) {
				return;
			}
			
			
			var thisControl = this;
			this.timeout = setTimeout(function () {
                if (thisControl.isEnabled()) {
                    thisControl.next();
                } else {
                    thisControl.startCountdown();
                }
			}, this.options.displayTime);
		},
		stopCountdown: function () {
			if (this.timeout) {
				clearTimeout(this.timeout);
			}
		},
		
		show: function (nextId) {
			
			if (this.options.transitionBefore) {
				this.options.transitionBefore(this, this.currentId, nextId);
			}
			
			
			var thisControl = this;
			this.changing = true;
			if (this.transition.caption) {
				this.transition.caption.show(nextId);
			}
			this.transition.main.show(nextId, function() {
				
				if (thisControl.options.transitionAfter) {
					thisControl.options.transitionAfter(thisControl, thisControl.currentId, nextId);
				}
				
			
				thisControl.currentId = nextId;
				thisControl.changing = false;
				thisControl.startCountdown();
			});
		}
	});
	
	
	
	var defaultTransition = {
		$container:	undefined,
		$element_set:	undefined,
		type:	defaultControl.transitionType,
		speed:	defaultControl.transitionSpeed,
		width:	0,
		height:	0,
		containerClass:	undefined
	};
	
	var Transition = function (options, callbackFn) {
		options = $.extend({}, defaultTransition, options);
		this.$container = options.$container;
		this.type = options.type;
		this.speed = options.speed;
        
		var $element_set = options.$element_set;
		
		
		$container.css('position', 'relative');
		if (options.height) {
			$container.css('height', options.height);
		}
		if (options.width) {
			$container.css('width', options.width);
		}
		if (options.containerClass) {
			$container.addClass(options.containerClass);
		}
		
	
		this.zIndexNext = 1;
		var thisTransition = this;
		this.$elements = [];
		$element_set.each( function () {
			var $el = $(this);
            thisTransition.add($el)
		});
		
		
		this.currentId = 0;
		this.$elements[this.currentId].show();
		if (callbackFn) {
			callbackFn();
		}
	}
	
	
	$.extend(Transition.prototype, {
        add: function ($el) {
			this.$elements.push($el);
			$el
				.css('z-index', this.zIndexNext++)
				.css('position', 'absolute')
				.hide()
			;
            return this;
        },
		jump: function (nextId, callbackFn) {
			this._show(nextId, callbackFn, 0);
		},
		show: function (nextId, callbackFn) {
			this._show(nextId, callbackFn, this.speed);
		},
		_show: function (nextId, callbackFn, speed) {
			
			this.abort();
			
			
			var from =	this.from =	this.$elements[this.currentId];
			var to =	this.to =	this.$elements[nextId];
			var type = this.type;
			
			
			var thisTransition = this;
			var completeFn = function () {
				
				if (!thisTransition.active) {
					return;
				}
				thisTransition.active = false;
                
            
                from.hide();
                to.show();
				
				
				thisTransition.currentId = nextId;
				
				
				if (callbackFn) {
					callbackFn();
				}
			};
			
		
			this.active = true;
			
			
			if (type == 'fade') {
				from.fadeOut(speed);
				to.fadeIn(speed, completeFn);
			} else if (type == 'slide') {
				from.slideUp(speed);
				to.slideDown(speed, completeFn);
			} else {
				from.hide();
				to.show();
				completeFn();
			}
		},
		abort: function (toEnd) {
			
			if (!this.active) {
				return;
			}
			
		
			this.active = false;
			
			
			this.to.stop(true, true);
			this.from.stop(true, true);
			
			
			this.to.hide();
			this.from.show();
		}
	});
	
	
	function elementFactory(el, options) {
		
		if (el.$Slideygal) {
			return el.$Slideygal;
		}
		
		
		return el.$Slideygal = new Control(el, options);
	}
	function jQueryFactory($el, options) {
		var built = [];
		$el.each( function () {
			built.push( elementFactory(this, options) );
		});
		return built;
	}
	
	
	
	$.fn.slideygal = function (options) {
		
		var built = jQueryFactory(this, options);
		$.each(built, function () {
			this.play();
		});
        
      
        return built[0];
	};
	$.slideygal = function (el, options) {
		
		if (el instanceof $) {
			return jQueryFactory(el, options);
		}
		return elementFactory(el, options);
	};
})(jQuery);

