(function($, undefined) {
	
	$.widget('ui.kjCarousel', {
		widgetEventPrefix: "carousel",
		
		options: {
			//itemWidth:214, 
			//itemHeight:284,
			itemWidth:243, 
			itemHeight:330,
			viewportWidth:964,
			viewportHeight:400,
			correctionPadding:8,
			scaleFactor: 0.6,
			topOffsetMax: 100,
			viewableItems: 7,
			initialSelection: 0
		},
		_create: function() {
			this.correction = 0; // TODO: is this needed? check clipping either side
			this.currentSelection = this.options.initialSelection;

			this.median = Math.floor(this.options.viewableItems/2);

			this.carousel = this.element;
			this.carouselContent = $('<div id="carousel-content"/>').appendTo(this.carousel);

			this.attachedItems = [];
			this.allItems = [];
			for (var i = 0 ; i < this.options.dataProvider.length ; i++) {
				var itm = this.options.dataProvider[i];
				this.allItems.push(this._renderItem(itm));
			}

			this.carousel.css({position:'relative', overflow:'hidden', width:this.options.viewportWidth+2*this.correction+'px', height:this.options.viewportHeight+'px'});
			this.carouselContent.css('position', 'relative');
			
			this._animateToPosition(0,0);
		},
		_renderItem: function(o) {
			var self = this;
			var el = $('\
					<div class="carousel-item">\
						<div class="carousel-item-frame"></div>\
						<div class="carousel-item-frame carousel-item-frame-highlight"></div>\
						<img class="carousel-item-image" src="' + this.options.imgBaseUrl + o.imgUrl+'">\
					</div>');
			el.css('position', 'absolute');
			el.click(function(){self._animateToElement(this);});
			el.find('img').mouseenter(function(){self._highlightItem(el, true);})
							.mouseleave(function(){self._highlightItem(el, false);});
			el.data('item', o);
			return el.get(0);
		},
		_animateToPosition: function(idx, duration, easingType, passedData) {
			var currentTime = new Date();
			easingType = easingType ? easingType : 'easeInOutQuint';
			duration = duration ? duration : 600;

			if (!passedData) {
				passedData = {
					timerStart: currentTime,
					start: this.currentSelection,
					totalTime: duration
				};
			}

			var timer = currentTime - passedData.timerStart;

			if (timer < duration) {
				var easingFn = $.easing[easingType] || $.easing[$.easing.def];
				var newidx = easingFn(null, timer, passedData.start, idx - passedData.start, passedData.totalTime);

				if (typeof $.easing.def == 'string') {
					var easingFn = $.easing[easingType] || $.easing[$.easing.def];
					var newidx = easingFn(null, timer, passedData.start, idx - passedData.start, passedData.totalTime);
				} else {
					var newidx = $.easing[easingType]((timer / passedData.totalTime), timer, passedData.start, idx - passedData.start, passedData.totalTime);
				}
				var self = this;
				this._setPosition(newidx, function() { self._animateToPosition(idx, duration, easingType, passedData);});
				
			} else {
				var newidx = ((idx % this.allItems.length) + this.allItems.length) % this.allItems.length;
				this.currentSelection = newidx;
				this._setPosition(newidx);
			}
		},
		_animateToElement: function(el) {
			var idx = this.allItems.indexOf(el);
			if (idx == this.currentSelection) return;
			
			this._highlightItem(el, false);
			this.animating = true;
			this._trigger('animationstart');
			
			var dist = Math.abs(idx - this.currentSelection);
			if (dist > this.median) {
				if (idx > this.currentSelection) {
					idx -= this.allItems.length;
				} else {
					idx += this.allItems.length;
				}
			}
			this.targetPosition = idx;
			this._animateToPosition(idx, 600+(idx-this.currentSelection-1)*150);
		},
		_setPosition: function(idx, fn) {
			var l = Math.round(idx) - (this.options.viewableItems-1)/2 - 1;
			var h = Math.round(idx) + (this.options.viewableItems-1)/2 + 1;
			
			var arr = [];
			for (var i = l ; i <= h ; i++) {
				var ni = ((i % this.allItems.length) + this.allItems.length) % this.allItems.length;
				var itm = this.allItems[ni];
				arr.push(itm);
				this._tweenElement(i-idx, itm);
			}
			
			this.currentPosition = idx;

			this._mergeDetachVisibleItems(arr);
			
			
			if (fn) {
				setTimeout(fn, 0);
			} else {
				var self = this;
				this.animating = false;
				this._trigger('animationend');
			}
		},
		_tweenElement: function(i, el) {
			el = $(el);
			var s = 1 - Math.abs(i)*(1-this.options.scaleFactor)/this.median;
			var z = this.median+1-Math.round(Math.abs(i));
			var w = Math.round(this.options.itemWidth*s);
			el.css('width', w+'px');
			el.css('height', Math.round(this.options.itemHeight*s)+'px');
			var left = Math.round(this.options.viewportWidth/2 + i*(this.options.viewportWidth)/this.options.viewableItems - w/2);
			left = Math.max(left, 0);
			left = Math.min(left, this.options.viewportWidth-w);
			el.css({'left':left + 'px', top:(this.options.topOffsetMax*(1-s)).toFixed(1)+'px', zIndex:z});
		},
		_mergeDetachVisibleItems: function(arr) { 
			for (var i = 0 ; i < arr.length ; i++) {
				var idx = this.attachedItems.indexOf(arr[i]);
				if (idx == -1) {
					this.carouselContent.append(arr[i]);
				} else {
					this.attachedItems.splice(idx, 1);
				}
			}
			for (var i = 0 ; i < this.attachedItems.length ; i++) {
				$(this.attachedItems[i]).detach();
			}
			attachedItems = arr;
		},
		_highlightItem: function(el, hl) {
			return; // no transition effect
			if (this.animating) return;
			var el = $(el);
			if (hl) {
				//el.find('.carousel-item-frame').animate({opacity:0}, {duration:500, queue:false});
				el.find('.carousel-item-frame-highlight').animate({opacity:1}, {duration:100, queue:false});
			} else {
				//el.find('.carousel-item-frame').animate({opacity:1}, {duration:500, queue:false});
				el.find('.carousel-item-frame-highlight').animate({opacity:0}, {duration:100, queue:false});
			}
		},
		selection: function(v) {
			if (v === undefined) {
				return this.currentSelection;
			}
			// TODO: animate to position
		},
		getItem: function() {
			return this.options.dataProvider[this.currentSelection];
		}
	});
	
})( jQuery );

