/**
 * @author		AnD, JuD
 * @copyright	http://www.unic.com
 */

// check if console.log is available
if (window['console'] === undefined) window.console = { log: function(){} };
var log = (window.ActiveXObject) ? console.debug : console.log;

// allow jQuery to chain .log
if('jQuery' in window) jQuery.fn.log = function(msg) { console.log("%s: %o", msg, this); return this; };

/**
 * MODULES
 * ##################################################|
 * private scope - do it the moo way
 */
(function (jQuery) {
	/**
	 * Carousel1 two-tier module
	 * @param: too many but self-explaining
	 * @note: only for horizontal use
	 * key control
	 * endless mode
	 * items jumping
	 * o
	 * 
	 */
	jQuery.fn.carouselSlideshow = function (options) {
		//var $this = this;
		var options = jQuery.extend({
			horizontal: true,
			container: '.carousel',
			items: '',
			start: 0,
			next: '.carousel-next',
			back: '.carousel-back',
			externalNext: '.carousel-next1',
			externalBack: '.carousel-back1',
			status: true,
			statusItems: '.carousel-status a',
			activeClass: 'active',
			child: true,
			childContainer: '.childCarousel',
			childBorder: 1,
			duration: 500,
			easing: 'swing',
			autoplay: false,
			interval: 5000,
			endless: true			
		}, options);

		// get carousel data
		var carousel = jQuery(this.find(options.container));
		var items = jQuery(carousel.children(options.items));
		var itemsWidth = parseInt(jQuery(items[0]).css('width'));
		var nextBtn = this.find(options.next);
		var prevBtn = this.find(options.back);
		var statusList = this.find(options.statusItems);
		// states
		
		var position = itemsWidth * options.start;
		
		var realIndex = options.start;
		var oldLeftChild = options.start;
		var visibleChildrenNumber = 8;
		
		var isInLRotation = false;
		var isInRRotation = false;
		
		// set ids to identify positions
		for(var i = 0; i < items.length; i++) {
			jQuery(items[i]).attr("id", "slide_" + i)
		}
		
		// set initial position
		carousel.css('left', -position);
		
		// two-tier carousel
		
		var childCarousel = jQuery(this.find(options.childContainer));
		var childItems = jQuery(childCarousel.children(options.items));
		var childItemWidth = parseInt(jQuery(childItems[0]).css('width')) + options.childBorder;
		var childPosition = realIndex * (childItemWidth);
		var nextExtBtn = this.find(options.externalNext);
		var prevExtBtn = this.find(options.externalBack);
		
		// set initial position second carousel
		childCarousel.css('left', -childPosition);
		
		// if status enabled
		if (options.status) {
			statusList.bind('click', showState);
			
			// set initial position
			statusRefresh(realIndex);
		}
		
		// bind next / back events
		nextBtn.bind('click', next);
		prevBtn.bind('click', back);

		nextExtBtn.bind('click', externalNext);
		prevExtBtn.bind('click', externalBack);
		
		// functionality for  state
		function showState(e) {
			
			var current = statusList.index(this);
			itemsPos = items.index(jQuery("#slide_" + current));
			
			moveTo(itemsPos);
			if(options.endless) {
				// set sate position once again
				statusRefresh(current);
			}
		}

		// next functionality
		function next(e) {
			if(e) e.preventDefault();
			
			if (realIndex >= childItems.length - 1) {
				rotateMainRight(1);
				isInRRotation = true;
				realIndex = 0;
			} else {
				realIndex++;
			}

			moveTo(realIndex);
		};

		// back functionality
		function back(e) {
			if(e) e.preventDefault();
			// set bound variation endless false
			if(realIndex <= 0) {
				rotateMainLeft(1);
				isInLRotation = true;
				realIndex = childItems.length - 1;
				
			} else {
				realIndex--;
			}
			moveTo(realIndex);
		};
		function rotateMainRight(count) {
			var lastItem = jQuery(items[items.length - 1]);
			for(var i = 0; i < count; i++) {
				var firstItem = jQuery(items[i]);
				firstItem.insertAfter(lastItem);
				lastItem = firstItem;
			};
			items = jQuery(carousel.children(options.items));
		}
		function rotateMainLeft(count) { 
			var firstItem = jQuery(items[0]);
			for(var i = items.length - 1; i > items.length - count - 1; i--) {
				var lastItem = jQuery(items[i]);
				lastItem.insertBefore(firstItem);
				firstItem = lastItem;
			}
			items = jQuery(carousel.children(options.items));
		}
		// next functionality
		function externalNext(e) {
			if(e) e.preventDefault();
			changePage(visibleChildrenNumber + 1);
		};
		

		// back functionality
		function externalBack(e) {
			if(e) e.preventDefault();
			changePage(-(visibleChildrenNumber + 1));
		};
		
		function changePage(pageSize) {
			var newLeftChild = oldLeftChild + pageSize;
			if (newLeftChild >= childItems.length - visibleChildrenNumber) {
				newLeftChild =  childItems.length - pageSize; 
			} else if (newLeftChild < 0) {
				newLeftChild = 0;
			} 
				
			oldLeftChild = newLeftChild;
			childPosition = (oldLeftChild * childItemWidth);
			statusRefresh(realIndex);
			childCarousel.animate({
				'left': -childPosition, 
				queue: true
			}, options.duration, options.easing);
			
			position = (realIndex * itemsWidth);
		}
		
		
		
		// moveto functionality
		function moveTo(indexPos) {
			var pos = indexPos;
			
			if(isInLRotation) {
				position = itemsWidth;
				carousel.css('left', -position);
				pos = 0;
			}
			if(isInRRotation) {
				position = ((childItems.length - 2) * itemsWidth);
				carousel.css('left', -position);
				pos = childItems.length - 1;
			}
			
			childPosition = (indexPos * (childItemWidth));
			statusRefresh(indexPos);
			var childInView = (oldLeftChild <= indexPos) && (oldLeftChild + visibleChildrenNumber >= indexPos);
			var refresh = false;
			if(!childInView) {
				refresh = true;
				if(oldLeftChild > indexPos) {
					oldLeftChild = indexPos;
				}
				if(oldLeftChild + visibleChildrenNumber < indexPos) {
					oldLeftChild = indexPos - visibleChildrenNumber;
				}
			} 
			if (refresh) {
				childPosition = (oldLeftChild * (childItemWidth));
				
				childCarousel.animate({
					'left': -childPosition, 
					queue: true
				}, options.duration, options.easing);
			}
			
			position = (pos * itemsWidth);
			// unbind click event till animation is finished
			statusList.unbind('click');
			nextBtn.unbind('click');
			prevBtn.unbind('click');
			// animate
			carousel.animate({
				'left': -position, 
				queue: true
			}, options.duration, options.easing, function() {
				// bind click handler
				statusList.bind('click', showState);
				nextBtn.bind('click', next);
				prevBtn.bind('click', back);
				if (isInRRotation) {
					isInRRotation = false;
					rotateMainRight(childItems.length - 1);
					position = (indexPos * itemsWidth );
					carousel.css('left', -position);
					pos = 0;
				}
				if (isInLRotation) {
					isInLRotation = false;
					rotateMainLeft(childItems.length - 1);
					position = (indexPos * itemsWidth );
					carousel.css('left', -position);
				}
			});	
			
			realIndex = indexPos;
		};
		
		// update status functionality
		function statusRefresh(index) {
			statusList.removeClass(options.activeClass);
			jQuery(statusList[index]).addClass(options.activeClass);
			
		};
		
		// keep chaining
		return this;
	};
	
	
	/**
	 * Carousel module
	 * @param: too many but self-explaining
	 * @note: only for horizontal use
	 * key control
	 * endless mode
	 * items jumping
	 * o
	 * 
	 */
	jQuery.fn.carousel = function (options) {
		//var $this = this;
		var options = jQuery.extend({
			horizontal: true,
			container: '.carousel',
			items: '',
			itemsJump: 1,
			itemsVisible: 1,
			start: 0,
			next: '.carousel-next',
			back: '.carousel-back',
			externalNext: [],
			externalBack: [],
			status: true,
			statusItems: '.carousel-status a',
			activeClass: 'active',
			statusNum: '.statusnum',
			child: false,
			childContainer: '.childCarousel',
			childBorder: 1,
			childrenJump: 3,
			duration: 500,
			easing: 'swing',
			autoplay: false,
			interval: 5000,
			endless: true,
			onLoadEvent: null,
			onNextBackEvent: null,
			onBeforeMoveEvent: null
		}, options);

		// get carousel data
		var carousel = jQuery(this.find(options.container));
		var items = jQuery(carousel.children(options.items));
		var itemsWidth = parseInt(jQuery(items[0]).css('width'));
		var nextBtn = this.find(options.next);
		var prevBtn = this.find(options.back);
		var statusList = this.find(options.statusItems);
		var statusnum = this.find(options.statusNum);
		// states
		var bound = items.length - options.itemsVisible;
		var index = options.start;
		var position = (itemsWidth * options.itemsJump) * index;
		// needed for endless loop
		var current = options.start;
		// set ids to identify positions
		for(var i = 0; i < items.length; i++) {
			jQuery(items[i]).attr("id", i)
		}
		
		// set initial position
		carousel.css('left', -position);
		
		// two-tier carousel
		if(options.child) {
			var childCarousel = jQuery(this.find(options.childContainer));
			var childItems = jQuery(childCarousel.children(options.items));
			var childItemWidth = parseInt(jQuery(childItems[0]).css('width')) + options.childBorder;
			var childPosition = index * (childItemWidth * options.childrenJump);
			
			// set initial position second carousel
			childCarousel.css('left', -childPosition);
		}

		// if status enabled
		if (options.status) {
			statusList.bind('click', showState);
			
			// set initial position
			statusRefresh(index);
		}

		// functionality for external triggers: next
		if(options.externalNext.length > 0) {
			options.externalNext.forEach(function (item) {
				jQuery(item).bind('click', next);
			});
		};
		// functionality for external triggers: back
		if(options.externalBack.length > 0) {
			options.externalBack.forEach(function (item) {
				jQuery(item).bind('click', back);
			});
		};
		
		// should autoplay?
		if(options.autoplay) var timer = setInterval(autoplay, options.interval);

		// bind next / back events
		nextBtn.bind('click', next);
		prevBtn.bind('click', back);
		
		if (options.onLoadEvent != null) {
			options.onLoadEvent(items[position]);
		}
		
		// functionality for  state
		function showState(e) {
			current = statusList.index(this);
			itemsPos = items.index(jQuery("#" + current));
			
			if (options.onNextBackEvent != null) {
				options.onNextBackEvent(items[index], items[itemsPos]);
			}
			moveTo(itemsPos);
			if(options.endless) {
				// set sate position once again
				statusRefresh(current);
			}
		}

		// next functionality
		function next(e) {
			if(e) e.preventDefault();

			// endless functionality
			if(options.endless) {
				endlessNext();
				
			} else {

				// set bound
				if (position >= (bound * (itemsWidth * options.itemsJump))) {
					//moveTo(0);
					//stop carousel and do nothing
				} else {
					moveTo(++index);
				}
			}
			
			// clear interval
			if(timer) clearInterval(timer);
		};

		// back functionality
		function back(e) {
			if(e) e.preventDefault();

			// endless functionality
			if(options.endless) {
				endlessBack();
				
			} else {
			
				// set bound variation endless false
				if(position <= 0) {
					//moveTo(bound);
					//stop carousel and do nothing
				} else {
					position = (position - (itemsWidth * options.itemsJump));
					moveTo(--index);
				}
			}
			
			// clear interval
			if(timer) clearInterval(timer);
		};
		
		// autoplay functionality - uses moveTo!
		function autoplay() {
			if(!options.endless) {
				if (index < bound) {
					moveTo(++index);
				} else {
					moveTo(0);
				}
			} else {
				endlessNext();
			}
		};
		
		// moveto functionality
		function moveTo(indexPos) {
			// set new vars
			position = (indexPos * (itemsWidth * options.itemsJump));
			index = indexPos;
			//second carousel
			if(options.child) {
				childPosition = (indexPos * (childItemWidth * options.childrenJump));
			}
			// unbind click event till animation is finished
			statusList.unbind('click');
			nextBtn.unbind('click');
			prevBtn.unbind('click');
			// animate
			carousel.animate({
				'left': -position, 
				queue: true
			}, options.duration, options.easing, function() {
				// bind click handler
				statusList.bind('click', showState);
				nextBtn.bind('click', next);
				prevBtn.bind('click', back);
			});
			// animate second carousel
			if(options.child) {
				childCarousel.animate({
					'left': -childPosition, 
					queue: true
				}, options.duration, options.easing);
			}
			
			
		};
		
		// update status functionality
		function statusRefresh(index) {
			statusList.removeClass(options.activeClass);
			jQuery(statusList[index]).addClass(options.activeClass);
			
			// set current of available
			statusnum.each(function() {
				jQuery(this).text((index + 1) + "/" + items.length);
			});
		};
		
		// endless replacing functionality
		function endlessNext() {
			
			if(index < bound) {
				if (options.onNextBackEvent != null) {
					options.onNextBackEvent(items[index], items[index + 1]);
				}
				moveTo(++index);
				
			} else {
				var firstItem = jQuery(items[0]);
				var lastItem = jQuery(items[items.length - 1]);
				
				if (options.onBeforeMoveEvent != null) {
					options.onBeforeMoveEvent(firstItem);
				}

				firstItem.insertAfter(lastItem);
				index = bound - 1;
				position = (index * (itemsWidth * options.itemsJump));
				carousel.css('left', -position);
				
				// loop second carousel
				if(options.child) {
					var childLastItem = jQuery(childItems[childItems.length - 1]);
					for (var i = options.childrenJump - 1; i >=0; i--) {
						jQuery(childItems[i]).insertAfter(childLastItem);
					}
					childPosition = (index * (childItemWidth * options.childrenJump));
					childCarousel.css('left', -childPosition);
				}

				// update items list
				updateItems();
				
				if (options.onNextBackEvent != null) {
					options.onNextBackEvent(items[index], items[index + 1]);
				}
				
				// animate
				moveTo(++index);
			}
			
			if(current < bound) {
				current++;
			} else {
				current = 0;
			}
			
			// refresh status because the one set with index var is wrong
			if(options.status) statusRefresh(current);
		};
		
		function endlessBack() {
			
			if(index > 0) {
				if (options.onNextBackEvent != null) {
					options.onNextBackEvent(items[index], items[index - 1]);
				}
				moveTo(--index);
				
			} else {
				var firstItem = jQuery(items[0]);
				var lastItem = jQuery(items[items.length - 1]);

				if (options.onBeforeMoveEvent != null) {
					options.onBeforeMoveEvent(lastItem);
				}
				
				lastItem.insertBefore(firstItem);
				index = 1;
				position = (index * (itemsWidth * options.itemsJump));
				carousel.css('left', -position);
				
				// loop second carousel
				if(options.child) {
					var childFirstItem = jQuery(childItems[0]);
					for (var i = options.childrenJump; i > 0; i--) {
						jQuery(childItems[childItems.length - i]).insertBefore(childFirstItem);
					}
					childPosition = (index * (childItemWidth * options.childrenJump));
					childCarousel.css('left', -childPosition);
				}

				// update items list
				updateItems();
				
				if (options.onNextBackEvent != null) {
					options.onNextBackEvent(items[index], items[index - 1]);
				}
				// animate
				moveTo(--index);
			}
			
			if(current > 0) {
				current--;
			} else {
				current = bound;
			}
			
			// refresh status because the one set with index var is wrong
			if(options.status) statusRefresh(current);
		};
		
		//function to update items list
		function updateItems() {
			items = jQuery(carousel.children(options.items));
			// second carousel
			if(options.child) {
				childItems = jQuery(childCarousel.children(options.items));
			}
			bound = items.length - options.itemsVisible;
		}
		
		// keep chaining
		return this;
	};
})(jQuery);
