(function($) {	
	$.fn.kviewer = function(options){
		return this.each(function(i){
															
			// $(______).kviewer() == <ul id="______">
			var e = this;
			e.kvthis = $(this).css({position:'relative'});
			e.opts = $.extend({}, kviewer, options);
			
			var total = e.kvthis.children().length;
			
			var initHeight = 280;
			
			e.container = $('<div id="kv'+i+'" class="kvContainer">').css({position:'relative',width:e.opts.width});
			e.thumbContainer = $('<div class="kvThumbs">').css({width: e.opts.width});
			e.imgContainer = $('<div class="kvImgs">').css({height: initHeight, width:(e.opts.width * total)});
			e.loader = $('<div class="kvLoader">').css({height: initHeight, width: e.opts.width});

			// 1) wrap in container, 2) wrap in thumbContainer
			e.kvthis.wrap(e.container);
			e.kvthis.wrap(e.thumbContainer);
			
			// Insert imgContainer
			e.kvthis.parent().parent().prepend(e.imgContainer);
			e.imgContainer.append(e.imgUl);
			
			// Set up loading graphic since it's important
			var hasLoadImg = (e.opts.loadimg);
			if(hasLoadImg) {
				
				var icHeight = parseFloat(e.imgContainer.css('height'));
				
				e.loader.css({width: e.opts.width+'px', height: icHeight+'px', opacity: 0.6});
				
				e.ldrimg = $('<img src="'+e.opts.loadimg+'">').css({opacity: 0}); // prevent 'flashing'
				
				e.ldrimg.bind('load', function(){
					e.ldrimg.css({position: 'relative', left: (e.opts.width/2)-(this.width/2)+'px', top: (icHeight/2-12)+'px', opacity: 1});
				});
				
				e.ldrimg.appendTo(e.loader);
				e.kvthis.parent().parent().prepend(e.loader);
			}
			
			// ----------------------------------
			// Lets center the thumbnail ul and, if necessary, add scrollers
				
			var maxThumbsCanFit = Math.floor(e.opts.width/(e.opts.thumbWidth+(e.opts.thumbPadding*2)));
			var thumbUlWidth = total*(e.opts.thumbWidth+(e.opts.thumbPadding*2));
			
			var thumbOffset = (total <= maxThumbsCanFit) ? (e.opts.width/2)-total*(e.opts.thumbWidth+(e.opts.thumbPadding*2))/2 : (e.opts.width/2)-maxThumbsCanFit*(e.opts.thumbWidth+(e.opts.thumbPadding*2))/2;
		
			e.kvthis.css({left: thumbOffset+'px', width: thumbUlWidth});
			
			
						
			/********************************/
			var curSel = 0;
			var numPanes = Math.ceil(total/maxThumbsCanFit)-1;
			var perPane = maxThumbsCanFit;
			
			
			// [0] = is first pane, [1] = first in current, [2] = last in current, [3] = is last pane
			function paneInfo(){
				var rangeStart = Math.abs((parseFloat(e.kvthis.css('left'))-thumbOffset))/(e.opts.thumbWidth+(e.opts.thumbPadding*2));
				var rangeEnd = (rangeStart + maxThumbsCanFit-1 < total-1) ? rangeStart + maxThumbsCanFit-1 : total-1;
				return [(rangeStart==0), rangeStart, rangeEnd, (rangeEnd==total-1)];
			}
			/********************************/
			
			
			function Tabs(action){
				if (total > maxThumbsCanFit) {
					if(action == 'disable') {
						if($('.kvTabLeft, .kvTabRight').length == 2){
							$('.kvTabLeft').unbind('click');
							$('.kvTabRight').unbind('click');
						}
					} else if(action == 'enable') {
						if($('.kvTabLeft, .kvTabRight').length == 2){
							$('.kvTabLeft').bind('click', function(){tabLeft()});
							$('.kvTabRight').bind('click', function(){tabRight()});
						}
					}
				}
			}
			
			if ( total > maxThumbsCanFit ) {
				var tableft = $('<img src="/js/plugins/kviewer_images/tableft.png" class="kvTabLeft">');
				var tabright = $('<img src="/js/plugins/kviewer_images/tabright.png" class="kvTabRight">');
				// 23 px = width of tabright.png
				tabright.css({left: e.opts.width-23+'px'});
				e.kvthis.parent().prepend(tableft).prepend(tabright);
				
				var thumbCur = 0;
				var thumbEnd = Math.ceil(total/maxThumbsCanFit)-1;
				
				
				// ----------------------------------
				// TAB clicking
				function tabRight(){
						var toClick;
						if(!paneInfo()[3]) {
							toClick = paneInfo()[2]+1;
						} else {
							toClick = 0;
						}
						e.kvthis.children().eq(toClick).find('a').click();
				}
				
				function tabLeft(){
					var toClick;
					if(!paneInfo()[0]){
						toClick = (paneInfo()[1]-1);
					}else{
						toClick = (total-1);
					}
					e.kvthis.children().eq(toClick).find('a').click();
				}
				
				$('.kvTabRight').bind('click', function(){tabRight()});
				$('.kvTabLeft').bind('click', function(){tabLeft()});
			}

			
			// ----------------------------------
			// For each <li> of the thumbnail <ul>
			e.kvthis.children().each(function(i){
				
				var thumb_a = $(this).find('a');
				var thumb_img = $(this).find('img').css({padding: e.opts.thumbPadding, opacity: 0.6});
				
				var img = $('<img>').attr({src: '/js/plugins/kviewer_images/blank.gif'}).addClass('kv_notloaded');
				e.imgContainer.append(img);
											
				
				// ----------------------------------
				// Enables CLICK / SHIFT+CLICK on big images
				img
				.bind('mousedown', function(e){
					var next = (e.shiftKey) ? (i-1) : (i+1);
					var numToClick = (next == total) ? 0 : ((next < 0 ) ? (total-1) : next);
					
					var _next = thumb_a.parent().parent().children().eq(numToClick);
					_next.find('a').click();

				});
				
				function slideThumbs(cur){
					//alert(numPanes);
					if(numPanes >= 1){
						/*if(cur == 0) {
							e.kvthis.animate({left: thumbOffset+'px'});
						} else if (cur % (perPane-1) == 0 && cur != (total-1)){
							//alert( -(cur*(e.opts.thumbWidth+e.opts.thumbPadding*2)) );
							e.kvthis.animate({left: (-(cur*(e.opts.thumbWidth+e.opts.thumbPadding*2))+thumbOffset)+'px'});
						} else if (cur == total-1) {
							
						}*/
						if(cur == 0) {
							e.kvthis.animate({left: thumbOffset+'px'}, 200);
						} else if (cur % perPane == 0 && cur != (total-1)){
							e.kvthis.animate({left: (-(cur*(e.opts.thumbWidth+e.opts.thumbPadding*2))+thumbOffset)+'px'}, 200);
						} else if (cur % perPane == (perPane-1)) {
							e.kvthis.animate({left: (-((cur-(perPane-1))*(e.opts.thumbWidth+e.opts.thumbPadding*2))+thumbOffset)+'px'}, 200);
						} else if (cur == (total-1)) {
							var erg = Math.floor(total/maxThumbsCanFit)*(maxThumbsCanFit) * (50 + ((numPanes-1) * 2));
							e.kvthis.animate({left: -erg+'px'}, 200);
						}						
					}
				}
				
				function test_Animate(elt) {
					e.loader.fadeOut(80);
					var imgheight = elt.attr('height');
					e.imgContainer.animate({left: -(e.opts.width*i)+'px', height: imgheight},'swing', function(){Tabs('enable')});
				};
				
				
				thumb_a.bind('click', function(){
																			 
					Tabs('disable');
				 
					var curSel = i;
					slideThumbs(i);
					
					var imgToReplace = e.imgContainer.children().eq(i);
					
					if (!thumb_img.hasClass('kvSelected')) {
						e.kvthis.find('.kvSelected').removeClass('kvSelected').css('opacity',0.6);
						thumb_img.fadeTo(50,1.0).addClass('kvSelected');

						var image = new Image();
						image.onload = function(){
							var marg = (e.opts.width - $(this).attr('width'))/2;
							//imgToReplace.parent().prepend('<span>');
							imgToReplace.attr('src', $(this).attr('src')).css('margin','0 '+marg+'px');
							test_Animate(imgToReplace);
						};
						
						if (imgToReplace.hasClass('kv_notloaded')) {
							e.loader.show().css('height',e.imgContainer.css('height'));
							image.src = thumb_a.attr('href');
							imgToReplace.removeClass('kv_notloaded');
						} else {
							test_Animate(imgToReplace);
						};
					}
					
					return false;
				}); // end: thumb_a.bind('click')
				
				// IMPORTANT: after thumb_a is bound to click, click the first one
				if(i == 0){thumb_a.click();}
				
			}); // end: e.kvthis.children().each
			
			//$(e.kvthis.children().get(0)).find('a').click();
		});
	};
	kviewer = {
		width: 372,
		loadimg: '/js/plugins/kviewer_images/loader.gif',
		thumbWidth: 50,
		thumbPadding: 2
	};
})(jQuery);