if(!GY) {
	GY = {};
}
GY.slideshow = function(target, options) {

	// defaults
	this.options = $.extend({
		animationDuration: 200, // time, in milliseconds, it takes for animation to complete
		captions: true, // has captions?
		captionsClass: 'caption', // CSS classname of the caption element
		giveHeight: 80, // amount of pixels that the photo must be larger than in order to warrant expand / collapse
		groupsOf: 1, // how many items should slide at once
		hasCounter: true, // add '4 of 5', etc text
		initialHeight: 555, // max height (without expanding)
		initialIndex: 0, // where to start
		loop: false, // should the slideshow loop (i.e. start over from the beginning)?
		navClass: 'nav', // nav class - wrapper for next / previous buttons, and states
		nextBtnClass: 'next', // class of next button
		offsetLeft: 0, // additional x space (to make up for padding and stuff)
		prevBtnClass: 'prev', // class of previous button
		slideCounterClass: 'counter',
		states: false // show state dots?
	}, options || {});
	
	var self = this;
	this.target = $(target);

	// shortcuts and instance variables
	this.groupsOf = this.options.groupsOf;
	this.states = this.options.states;
	this.animating = false;
	this.init = true; // initialize flag
	this.exandHeight = false;
	
	// find the ul
	this.slideWindow = this.target.find('ul');
	this.slideWindow.css({'position': 'relative'});
	// find children
	this.slides = this.slideWindow.find('li');

	// use the first child as measure for width (and height)
	var slideWidth = $(this.slides[0]).width();
	var slideHeight = this.slideHeight = $(this.slides[0]).height();
	var slidesWidth = (slideWidth + this.options.offsetLeft) * this.slides.length + 'px';

	// set the scrollwindowWidth
	this.slideWindow.css({'width': this.slidesWidth});
	this.currentIndex = (this.inBounds(this.options.initialIndex, this.slides.length)) ? this.options.initialIndex : 0;
	this.groupIndex = (this.currentIndex % this.groupsOf === 0) ? this.currentIndex : (Math.floor(this.currentIndex / this.groupsOf) * this.groupsOf);
	
	// how many groups are there altogether?
	this.totalGroups = Math.ceil(this.slides.length / this.groupsOf);
	
	// create the nav
	this.createNav();

	
	/**
	 * keyboard navigation
	 */
	$(document).keydown(function(e) {
		switch(e.keyCode) {
			case 37: // left arrow
				self.previous();
				break;
			case 39: // right arrow
			 	self.next();
				break;
			default: 
				break;
		}
	});

};
GY.slideshow.prototype = {
	
	createNav: function() {
		var self = this,
			nav = $('<nav class="slideshow-nav clearfix"/>');
		
		
		if(this.totalGroups > 1) {
			this.prevBtn = $('<a href="#" class="' + this.options.prevBtnClass +'" />');
			this.nextBtn = $('<a href="#" class="' + this.options.nextBtnClass +'" />');

			nav.append(this.prevBtn);
			if(this.states) {
				var ul = $('<ul class="states"/>');
				nav.append(ul);

				for(var i = 0, l = this.totalGroups; i < l; i++) {
					ul.append('<li><a href="#"></a></li>');
				}
			}
			nav.append(this.nextBtn);

			this.prevBtn.bind('click', function(e) {
				e.preventDefault();
				self.previous();
			});

			this.nextBtn.bind('click', function(e) {
				e.preventDefault();
				self.next();
			});
			
			if(this.options.hasCounter) {
				var count = $('<div class="' + this.options.slideCounterClass + '"/>'), 
					totalCount = $('<span class="total-count" />').text('/' + this.totalGroups);
				this.currentCount = $('<span class="current-count" />').text(this.groupIndex);
				count.append(this.currentCount).append(totalCount);
				nav.append(count);
			}
		}

    // if(this.slideHeight > (this.options.initialHeight + this.options.giveHeight)) {
    //  this.expandHeight = true;
    //  this.maxHeight = this.slideHeight;
    // 
    //  this.target.height(this.options.initialHeight);
    //  this.expandContract = $('<a href="#" class="ex-co">+ Expand</a>');
    //  nav.append(this.expandContract);
    //  
    //  this.expandContract.bind('click', function(e) {
    //    e.preventDefault();
    //    $(this).toggleClass('expand');
    //    if($(this).hasClass('expand')) {
    //      self.expand($(this));
    //    } else {
    //      self.contract($(this));
    //    }
    //  });
    // } else if (this.slideHeight < this.options.initialHeight) {
    //  this.slideWindow.find('li').addClass('padding');
    // } else {}
    this.target.after(nav);
		
		this.updateNav();
		
	},
	
	inBounds: function(n, l) {
		// check if index is a) numeric and b) within the bounds of the slideshow
		return (!isNaN(parseFloat(n)) && isFinite(n) && n >= 0 && n <= (l - 1));
	},
	
	/**
	 * Contract height back to initial maxHeight
	 * @param el {jQuery object}
	 */
	contract: function(el) {
		this.target.stop().animate({
			height: this.options.initialHeight
		}, 250, function() {
			el.text('+ Expand');
		});
	},
	
	/**
	 * Expand height
	 * @param el {jQuery object}
	 */
	expand: function(el) {
		this.target.stop().animate({
			height: this.maxHeight
		}, 250, function() {
			el.text('- Shrink');
		});
	},
	
	/**
	 * Advance to the next slide / section
	 */
	next: function() {
		var next = this.groupIndex + this.groupsOf;
		if(next >= this.slides.length) {
			if(this.options.loop) {
				next = 0;
			} else {
				next = this.groupIndex;
			}
		}
		this.slideTo(next);
	},
	
	/**
	 * Retreat to the previous slide / section
	 * @param index {number}
	 */
	previous: function() {
		// go to previous slide
		var prev = this.groupIndex - this.groupsOf;
		
		if(prev < 0) {
			if(this.options.loop) {
				prev = (this.totalGroups - 1) * this.groupsOf;
			} else {
				prev = 0;
			}
		}
		this.slideTo(prev);
	},
	
	/**
	 * Slide
	 * @param index {number}
	 */
	slideTo: function(index, jump) {
		
		var self = this;
		
		// are we within bounds?
		if(!this.inBounds(index)) {
			this.currentIndex = index;
		}
		this.groupIndex = index = parseInt(index, 10); // make sure index is a number
		// find element
		var el = this.slides.eq(index);
		if(el.length === 0) {
			el = this.sections.eq(0);
		}
		// find offset
		var left = '-' + el[0].offsetLeft + 'px';
		this.slideWindow.stop().animate({left: left}, this.options.animationDuration, function(e) {
		// self.doneAnimating(el);
		});
		
		this.updateNav();
		// 		if(!jump) {
		// 			// animate
		// 			if(this.has3D) {
		// 				this.translate(left, this.options.animTimeSlide, function() {
		// 					self.doneAnimating(el);
		// 				});
		// 			} else {
		// 				this.wrapper.stop().animate({left: left}, this.options.animTimeSlide, function(e) {
		// 					self.doneAnimating(el);
		// 				});
		// 			}
		// 		} else {
		// 			// jump
		// 			if(this.has3D) {
		// 				this.translate(left, 0);
		// 			} else {
		// 				this.wrapper.stop().css({left: left});
		// 			}
		// 			el.addClass('current');
		// 		}
	},
	
	updateNav: function() {
		if(this.currentCount) {
			this.currentCount.text(this.groupIndex + 1);
		}
		
	}
};

/**
 * Plugify-ing
 */
(function ($) {
	$.fn.slideshow = function(options) {
		var slideshow, 
			self = this;
		this.each(function() {
		    slideshow = new GY.slideshow(self.selector, options);
		});
		return slideshow;
	};
})(jQuery);
