(function($) {
 
	$.fn.tpgSlider = function(settings){
		var config = {
			easing : 'swing',				// click easing type
			intervalEasing: 'linear',		// interval easing type
			incriment : false,				// snap to specific items
			pageSlideDivision : 2,			// view width divide by this to get the amount of each slide incriment
			animateSpeed: 250,				// time in milliseconds to complete animated movement of the scrollbar/content
			animateSpeedInterval: 150		// time in milliseconds to complete animated movement during interval
		};

		var o = $.extend(config, settings); // options
		
		this.each(function() {
			// element-specific code here
			
			var obj = $(this);
			
			var shell = obj.find('.slide-shell');
			var content = obj.find('.slide-content');
			var controls = obj.find('.slide-controls');

			// remove the existing "last" designation
			content.find('.item').removeClass('last');
			content.find('.item:last-child').addClass('last');

			// set container to (width+margin) of children (minus margin of last child for proper end alignment)
			var firstChild = content.find('.item:first-child');
			var childMargin = parseInt(firstChild.css('margin-right'));
			var totalWidth = 0;
			var childCount = 0;
			var itemIncrimentLocation = Array();
			content.find('.item').each(function(index){
				itemIncrimentLocation[childCount] = totalWidth;
				totalWidth += $(this).width()+parseInt($(this).css('margin-right'));
				childCount++;
			});
			content.css({ 'width': (totalWidth)+'px' });
			
			var pageIncriment = Math.floor(shell.width() / o.pageSlideDivision);
			var remainder = content.width() - shell.width();
			var proportion = shell.width() / content.width();
			var startContentPos = 0-parseInt(content.css('left'));

			if (childCount > 0){
				if (proportion < 1){
					controls.show();
					controls.html('');
					controls.html('<div class="scroll"><a class="bar" href="#"></a><div class="track"></div></div><ul><li><a class="prev" href="#">Previous</a></li><li><a class="next" href="#">Next</a></li></ul>');
					var scrollTrack = controls.find('.scroll .track');
					var scrollBar = controls.find('.scroll a.bar');
					var prevBtn = controls.find('a.prev');
					var nextBtn = controls.find('a.next');
					var trackWidth = scrollTrack.width();
					var barWidth = Math.floor(trackWidth * proportion);
					var trackRoom = trackWidth - barWidth;
					scrollBar.width(barWidth);
				} else {
					controls.fadeOut(250);
					content.stop(true,true).animate({ 'left': '0px' }, 250, function(){});
				}
			} else {
				controls.html('');
				controls.hide();
				content.css({ 'left':'0px' });
			}
			
			var defaultAnimateSpeed = o.animateSpeed;
			var animateSpeed = defaultAnimateSpeed;
			var animateSpeedInterval = o.animateSpeedInterval;
			var easingType = o.easing;
			var slideTrackXClick = null;
			
			var incrimentCount = 0;
			var initialPrevInterval;
			var prevButtonInterval;
			var initialNextInterval;
			var nextButtonInterval;
			var initialTrackInterval;
			var trackInterval;
			
			if (proportion < 1 && childCount > 0){
				
				// keep scrollbar in place when content changes (if it's not at 0)
				if (startContentPos != 0){
					if (o.incriment){
						var newContentPos = findClosestIncriment(startContentPos);
						if (newContentPos > remainder){ newContentPos = remainder; }
						var newContentProportion = (newContentPos / remainder);
						var newBarPos = Math.floor(trackRoom * newContentProportion);
						content.stop(true,true).animate({ 'left': 0-newContentPos+'px' }, animateSpeed, o.easing, function(){});
						scrollBar.css({ 'left': newBarPos+'px' });
						for (var i=0; i<itemIncrimentLocation.length; i++){
							if (itemIncrimentLocation[i] == newContentPos){
								incrimentCount = i;
								break;
							}
						}
					} else {
						var startProportion = startContentPos / remainder;
						var newBarStartPos = Math.floor(trackRoom*startProportion);
						if (newBarStartPos > trackRoom){ newBarStartPos = trackRoom; }
						scrollBar.css({ 'left': newBarStartPos+'px' });
					
						if (startContentPos > remainder){
							content.stop(true,true).animate({ 'left': (0-remainder)+'px' }, animateSpeed, o.easing, function(){});
						}
					}
				}
				scrollBar.click(function(){ return false; });
				scrollBar.draggable({ axis: 'x', containment: 'parent', scroll: false });
				scrollBar.bind( "drag", function(event, ui) {
					var barLeft = scrollBar.offset().left-scrollBar.parent().offset().left;
					var scrollPerc = barLeft / trackRoom;
					var contentPos = 0 - Math.floor( remainder * scrollPerc);
					content.css({ 'left': contentPos+'px' });
				});
				scrollBar.bind( "dragstop", function(event, ui) {
					if (o.incriment){
						var currentContentPos = parseInt(content.css('left'))*-1;
						var newContentPos = findClosestIncriment(currentContentPos);
						if (newContentPos > remainder){ newContentPos = remainder; }
						var newContentProportion = (newContentPos / remainder);
						var newBarPos = Math.floor(trackRoom * newContentProportion);
						content.stop(true,true).animate({ 'left': 0-newContentPos+'px' }, animateSpeed, o.easing, function(){});
						scrollBar.stop(true,true).animate({ 'left': newBarPos+'px' }, animateSpeed, o.easing, function(){});
					}
				});

				// scroll track actions
				scrollTrack.mousedown(function(e){
					slideTrackXClick = e.pageX-scrollTrack.parent().offset().left;
					scrollTrackClick();
					initialTrackInterval = setInterval(trackActionDelay, 500);
					return false;
				}).mouseup(function(e){
					clearInterval(initialTrackInterval);
					clearInterval(trackInterval);
					animateSpeed = defaultAnimateSpeed;
					easingType = o.easing;
					return false;
				});
				function trackActionDelay(){
					clearInterval(initialTrackInterval);
					easingType = o.intervalEasing
					animateSpeed = animateSpeedInterval;
					trackInterval = setInterval(scrollTrackClick, animateSpeedInterval);
				}
				function scrollTrackClick(){
					var barXStart = scrollBar.offset().left - scrollTrack.parent().offset().left;
					var barXFinish = barXStart + barWidth;
					if (slideTrackXClick < barXStart){
						// click to the left of the bar
						prevButtonAction();
					} else if (slideTrackXClick > barXFinish){
						// click to the right of the bar
						nextButtonAction();
					} else {
						clearInterval(initialTrackInterval);
						clearInterval(trackInterval);
						easingType = o.easing;
						animateSpeed = defaultAnimateSpeed;
					}
				}
				
				// next/prev button actions
				prevBtn.click(function(){ return false; });
				prevBtn.mousedown(function(){
					prevButtonAction();
					initialPrevInterval = setInterval(prevButtonActionDelay, 500);
					return false;
				}).mouseup(function(){
					clearInterval(initialPrevInterval);
					clearInterval(prevButtonInterval);
					easingType = o.easing;
					animateSpeed = defaultAnimateSpeed;
					return false;
				});
				nextBtn.click(function(){ return false; });
				nextBtn.mousedown(function(){
					nextButtonAction();
					initialNextInterval = setInterval(nextButtonActionDelay, 500);
					return false;
				}).mouseup(function(){
					clearInterval(initialNextInterval);
					clearInterval(nextButtonInterval);
					easingType = o.easing;
					animateSpeed = defaultAnimateSpeed;
					return false;
				});
				function prevButtonActionDelay(){
					clearInterval(initialPrevInterval);
					easingType = o.intervalEasing;
					animateSpeed = animateSpeedInterval;
					prevButtonInterval = setInterval(prevButtonAction, animateSpeedInterval);
				}
				function prevButtonAction(){
					if (o.incriment){ // incrimental movement
						if (incrimentCount > 0){
							incrimentCount--;
							var newContentPos = 0-itemIncrimentLocation[incrimentCount];
							var newContentProportion = ((newContentPos*-1) / remainder);
							var newBarPos = Math.floor(trackRoom * newContentProportion);
							content.stop(true,true).animate({ 'left': newContentPos+'px' }, animateSpeed, easingType, function(){});
							scrollBar.stop(true,true).animate({ 'left': newBarPos+'px' }, animateSpeed, easingType, function(){});
						}
					} else {
						var currentContentPos = parseInt(content.css('left'));
						if ((currentContentPos + pageIncriment) <= 0){
							var newContentPos = currentContentPos + pageIncriment;
							var newContentProportion = ((newContentPos*-1) / remainder);
							var newBarPos = Math.floor(trackRoom * newContentProportion);
							content.stop(true,true).animate({ 'left': newContentPos+'px' }, animateSpeed, easingType, function(){});
							scrollBar.stop(true,true).animate({ 'left': newBarPos+'px' }, animateSpeed, easingType, function(){});
						} else {
							content.stop(true,true).animate({ 'left': '0px' }, animateSpeed, easingType, function(){});
							scrollBar.stop(true,true).animate({ 'left': '0px' }, animateSpeed, easingType, function(){});
						}
					}
				}
				function nextButtonActionDelay(){
					clearInterval(initialNextInterval);
					easingType = o.intervalEasing;
					animateSpeed = animateSpeedInterval;
					nextButtonInterval = setInterval(nextButtonAction, animateSpeedInterval);
				}
				function nextButtonAction(){
					if (o.incriment){ // incrimental movement
						if (itemIncrimentLocation[incrimentCount+1] <= remainder){
							incrimentCount++;
							var newContentPos = 0-itemIncrimentLocation[incrimentCount];
						} else if ((parseInt(content.css('left'))*-1) != remainder) {
							incrimentCount++;
							var newContentPos = 0-remainder;
						} else {
							var newContentPos = parseInt(content.css('left'));
						}
						var newContentProportion = ((newContentPos*-1) / remainder);
						var newBarPos = Math.floor(trackRoom * newContentProportion);
						content.stop(true,true).animate({ 'left': newContentPos+'px' }, animateSpeed, easingType, function(){});
						scrollBar.stop(true,true).animate({ 'left': newBarPos+'px' }, animateSpeed, easingType, function(){});
					} else {
						var currentContentPos = parseInt(content.css('left'));
						if ((currentContentPos - pageIncriment) >= (0-remainder)){
							var newContentPos = currentContentPos - pageIncriment;
							var newContentProportion = ((newContentPos*-1) / remainder);
							var newBarPos = Math.floor(trackRoom * newContentProportion);
							content.stop(true,true).animate({ 'left': newContentPos+'px' }, animateSpeed, easingType, function(){});
							scrollBar.stop(true,true).animate({ 'left': newBarPos+'px' }, animateSpeed, easingType, function(){});
						} else {
							content.stop(true,true).animate({ 'left': (0-remainder)+'px' }, animateSpeed, easingType, function(){});
							scrollBar.stop(true,true).animate({ 'left': trackRoom+'px' }, animateSpeed, easingType, function(){});
						}
					}
				}

				function findClosestIncriment(num){
					var lowestDiff = null;
					var lowestNum = null;
					var incNum = null;
					for (var i=0; i<itemIncrimentLocation.length; i++){
						var test = Math.abs(num-itemIncrimentLocation[i]);
						if (lowestDiff != null){
							if (test < lowestDiff){
								lowestDiff = test;
								lowestNum = itemIncrimentLocation[i];
								incNum = i;
							}
						} else {
							lowestDiff = test;
							lowestNum = itemIncrimentLocation[i];
							incNum = i;
						}
					}
					incrimentCount = incNum;
					return lowestNum;
				}
				
			}
			
			$.fn.tpgSliderSlideToStart = function(){
				var scrollBar = controls.find('.scroll a.bar');
				content.stop(true,true).animate({ 'left': '0px' }, animateSpeed*2, easingType, function(){});
				scrollBar.stop(true,true).animate({ 'left': '0px' }, animateSpeed*2, easingType, function(){});
				incrimentCount = 0;
			};
			
			$.fn.tpgSliderResetSpacing = function(){
				var content = obj.find('.slide-content');
				content.find('.item').removeClass('last');
				content.find('.item:last-child').addClass('last');
			};
			
		});
		
		return this;
	};

})(jQuery);
