////////////////////////////////////////////////////////////////////////////////////////////////
//
//			PLUGIN:		ARMY KNIFE
//			VERSION:	1.1
//			AUTHOR:		ROMAN D. PACHECO
//			NOTES:
//				2011.10.06	:	1.1	-	NOW ABLE TO SWITCH SECTIONS WITH A TRANSITION OF 'none' (INSTANT)
//									-	ADDED ABILITY TO SET TEXT AND CUSTOM TAB TITLES
//									-	FIXED ANIMATION CLEARING BUG
//			SETTINGS:
//
//				// DEFAULT SETTINGS
//				$("#myElem").armyKnife({
//					speed					:	300,
//					sections				:	"> *",
//					startingSection			:	0,
//					easing					:	"swing",				//	[swing|linear]
//					transition				:	"none",					//	[none|slide|slideIn|slideOut|fade|fadeIn|fadeOut]
//					autoResize				: 	false,
//					resizeSpeed				: 	200,
//					autoRotate				:	false,
//					autoRotateDelay			:	5000,
//					generateNav				:	false,
//					navType					:	"empty",				//	[empty|numeric|text|custom]
//					navItemSource			:	function(section) {		//	REQUIRED WHEN navType = 'text' OR 'custom'; RESPECTIVE SECTION IS PASSED FOR EASY REFERENCE
//						return "&nbsp;";
//					},
//					navItemCode				:	function(source) {		//	REQUIRED WHEN navType = 'custom'; SECTION SOURCE IS PASSED FOR EASY REFERENCE
//						var btn	=	$("<a />",{
//							"href"	: 	"#"
//						});
//						btn.html(source);
//						return btn;
//					},
//					navID					:	false,
//					navClass				:	"armyKnife-Nav",
//					activeNavItemClass		:	"active",
//					showSectionButtons		: 	false,
//					sectionButtonClass		: 	"armyKnife-Btn",
//					sectionButtonCodeNext	: 	$("<a />",{
//						"href"	: 	"#"
//					}),
//					sectionButtonCodePrev	: 	$("<a />",{
//						"href"	: 	"#"
//					})
//				});
//
//				// CHANGE SECTIONS
//				$("#myElem").armyKnife("next");
//				$("#myElem").armyKnife("prev");
//				$("#myElem").armyKnife("goto",5);	//	USE SECTION INDEX, NOT SECTION COUNT
//
//
////////////////////////////////////////////////////////////////////////////////////////////////

(function($){
	var pluginName	=	"armyKnife",
		_v			=	{
			cssProps	:	{
				active	:	{
					marginLeft	:	"0%"
				},
				above	:	{
					zIndex		: 	100
				},
				below	:	{
					zIndex		: 	10
				},
				hiddenR	:	{
					marginLeft	:	"100%"
				},
				hiddenL	:	{
					marginLeft	:	"-100%"
				},
				fadeOut	:	{
					opacity	:	0
				},
				fadeIn	:	{
					opacity	:	1
				}
			},
			regex		: 	{
				transition	: 	{
					fadeIn		:	new RegExp("fade(,|$|In)","i"),
					fadeOut		:	new RegExp("fade(,|$|Out)","i"),
					slideIn		:	new RegExp("slide(,|$|In)","i"),
					slideOut	:	new RegExp("slide(,|$|Out)","i"),
					none		:	new RegExp("none(,|$)","i")
				}
			}
		},
		_e			=	{
			button	: 	$("<a />",{
				"href"	: 	"#"
			})
		},
		_s			=	{
			speed					:	300,
			sections				:	"> *",
			startingSection			:	0,
			easing					:	"swing",				//	[swing|linear]
			transition				:	"none",					//	[none|slide|slideIn|slideOut|fade|fadeIn|fadeOut]
			autoResize				: 	false,
			resizeSpeed				: 	200,
			autoRotate				:	false,
			autoRotateDelay			:	5000,
			generateNav				:	false,
			navType					:	"empty",				//	[empty|numeric|text|custom]
			navItemSource			:	function(section) {		//	REQUIRED WHEN navType = 'text' OR 'custom'; RESPECTIVE SECTION IS PASSED FOR EASY REFERENCE
				return "&nbsp;";
			},
			navItemCode				:	function(source) {		//	REQUIRED WHEN navType = 'custom'; SECTION SOURCE IS PASSED FOR EASY REFERENCE
				var btn	=	_e.button.clone();
				btn.html(source);
				return btn;
			},
			navID					:	false,
			navClass				:	pluginName + "-Nav",
			activeNavItemClass		:	"active",
			showSectionButtons		: 	false,
			sectionButtonClass		: 	pluginName + "-Btn",
			sectionButtonCodeNext	: 	_e.button.clone(),
			sectionButtonCodePrev	: 	_e.button.clone()
		},
		_m			=	{
			init	:	function(o,callback) {
				return this.each(function() {
					var $this	=	$(this),
						data	=	$this.data(pluginName);
					if(!data) {
						var s =	$.extend(true,{},_s);
						s = o ? $.extend(true,s,o) : s;
						$.extend(true,s,{
							sectionList	:	[],
							navItems	:	[],
							currentSection	:	s.startingSection,
							targetSection	:	false
						});
						if(s.generateNav) {
							s.nav = $("<ul />",{
								"class"	:	s.navClass
							});
						};
						var allSections	=	$this.find(s.sections);
						$.each(allSections,function(i,e) {
							if(s.generateNav) {
								var thisLI	=	$("<li />"),
									thisA	=	_e.button.clone();
								
								switch(s.navType) {
									case "numeric":
										thisA.html(parseFloat(i + 1));
										break;
									case "text":
										var source	=	s.navItemSource($(e)) || s.navItemSource;
										thisA.html(source);
										break;
									case "custom":
										var source	=	s.navItemSource($(e)) || s.navItemSource,
											code	=	s.navItemCode(source) || s.navItemCode;
										thisA = code;
										break;
									default:
										thisA.html("&nbsp;");
								}
								s.nav.append(thisLI);
								thisLI.append(thisA);
								thisA.bind("click",function() {
									_m["goto"].call($this,i);
									return false;
								});
								if(i == s.startingSection) {
									thisLI.addClass(s.activeNavItemClass);
								};
								s.navItems.push(thisLI);
							};
							if(i == s.startingSection) {
								$(e).css(_v.cssProps.active);
							} else {
								$(e).css(_v.cssProps.hiddenR);
							};
							if(s.showSectionButtons) {
								if(i > 0) {
									var prevBtn	=	s.sectionButtonCodePrev.clone();
									prevBtn.html() == "" && prevBtn.html("Prev");
									prevBtn
										.addClass(s.sectionButtonClass)
										.bind("click",function() {
											_m.prev.call($this);
											return false;
										})
										.appendTo($(e));
								};
								if(i < allSections.length - 1) {
									var nextBtn	=	s.sectionButtonCodeNext.clone();
									nextBtn.html() == "" && nextBtn.html("Next");
									nextBtn
										.addClass(s.sectionButtonClass)
										.bind("click",function() {
											_m.next.call($this);
											return false;
										})
										.appendTo($(e));
								};
							};
							s.sectionList.push($(e));
						});
						if(s.generateNav) {
							if(s.navID) {
								if($("#" + s.navID).length) {
									$("#" + s.navID).replaceWith(s.nav);
								} else {
									$this.after(s.nav);
								};
								s.nav.attr("id",s.navID);
							} else {
								$this.after(s.nav);
							};
						};
						$this.data(pluginName,s);
						data = $this.data(pluginName);
					};
					if(data.autoRotate) {
						_m.setAutoRotate.call($this);
					};
					if(data.autoResize) {
						data.targetSection = data.currentSection;
						_m.resizeView.call($this,callback);
					} else {
						if(typeof callback == "function") {
							callback();
						}
					};
				});
			},
			setAutoRotate	:	function() {
				return this.each(function() {
					var $this	=	$(this),
						data	=	$this.data(pluginName);
					if(data) {
						clearTimeout(data.autoRotateInterval);
						data.autoRotateInterval = setTimeout(function() {
							if(typeof data.isAnimating == "undefined" || data.isAnimating.isResolved()) {
								_m.next.call($this);
							} else {
								if(!data.isAnimating.isResolved()) {
									$.when(data.isAnimating).then(function() {
										_m.next.call($this);
									});
								};
							};
						},data.autoRotateDelay);
					};
				});
			},
			resizeView	:	function(callback) {
				return this.each(function() {
					var $this	=	$(this),
						data	=	$this.data(pluginName);
					if(data) {
						var viewHeight			=	$this.height(),
							targetSectionHeight	=	data.sectionList[data.targetSection].outerHeight();
						if(viewHeight != targetSectionHeight) {
							$this.animate({
								"height"	: 	targetSectionHeight
							},data.resizeSpeed,function() {
								if(typeof callback == "function") {
									callback();
								};
							});
						} else {
							if(typeof callback == "function") {
								callback();
							};
						};
					};
				});
			},
			"goto"	:	function(target) {
				return this.each(function() {
					var $this	=	$(this),
						data	=	$this.data(pluginName);
					if(data && target != data.currentSection && (typeof data.isAnimating == "undefined" || data.isAnimating.isResolved())) {
						data.isAnimating	=	new $.Deferred();
						if(data.autoRotate) {
							_m.setAutoRotate.call($this);
						};
						data.targetSection = target;
						var direction = target < data.currentSection ? "right" : "left";
						if(data.autoResize) {
							_m.resizeView.call($this,function() {
								_m.animate.call($this,direction);
							});
						} else {
							_m.animate.call($this,direction);
						};
					};
				});
			},
			next	:	function() {
				return this.each(function() {
					var $this	=	$(this),
						data	=	$this.data(pluginName);
					if(data && data.sectionList[data.currentSection] && (typeof data.isAnimating == "undefined" || data.isAnimating.isResolved())) {
						data.isAnimating	=	new $.Deferred();
						if(data.autoRotate) {
							_m.setAutoRotate.call($this);
						};
						data.targetSection = data.sectionList[data.currentSection + 1] ? data.currentSection + 1 : 0;
						if(data.autoResize) {
							_m.resizeView.call($this,function() {
								_m.animate.call($this);
							});
						} else {
							_m.animate.call($this);
						};
					};
				});
			},
			prev	:	function() {
				return this.each(function() {
					var $this	=	$(this),
						data	=	$this.data(pluginName);
					if(data && data.sectionList[data.currentSection] && (typeof data.isAnimating == "undefined" || data.isAnimating.isResolved())) {
						data.isAnimating	=	new $.Deferred();
						if(data.autoRotate) {
							_m.setAutoRotate.call($this);
						};
						data.targetSection = data.sectionList[data.currentSection - 1] ? data.currentSection - 1 : data.sectionList.length - 1;
						if(data.autoResize) {
							_m.resizeView.call($this,function() {
								_m.animate.call($this,"right");
							});
						} else {
							_m.animate.call($this,"right");
						};
					};
				});
			},
			animate	:	function(dir,callback) {
				callback = !!callback ? callback : function() {};
				return this.each(function() {
					var $this	=	$(this),
						data	=	$this.data(pluginName);
					dir = !!dir ? dir : "left";
					if(data && data.sectionList[data.currentSection] && data.sectionList[data.targetSection]) {
						
						data.sectionList[data.currentSection].css(_v.cssProps.below);
						var currentCSSProps	=	_v.cssProps.active;
						if(data.transition.match(_v.regex.transition.slideOut) || data.transition.match(_v.regex.transition.none)) {
							currentCSSProps	=	dir == "left" ? _v.cssProps.hiddenL : _v.cssProps.hiddenR;
						};
						var animObjCurrent	=	$.extend(true,{},currentCSSProps);
						!!data.transition.match(_v.regex.transition.fadeOut) && $.extend(true,animObjCurrent,_v.cssProps.fadeOut);
						
						//	ANIMATE CURRENT SECTION OUT
						if(data.transition.match(_v.regex.transition.none)) {
							data.sectionList[data.currentSection].css(animObjCurrent);
							callback();
						} else {
							data.sectionList[data.currentSection].animate(animObjCurrent,data.speed,data.easing,callback);
						};
						
						if(data.transition.match(_v.regex.transition.fadeIn)) {
							data.sectionList[data.targetSection].css(_v.cssProps.fadeOut);
						} else {
							data.sectionList[data.targetSection].css(_v.cssProps.fadeIn);
						};
						
						data.sectionList[data.targetSection].css(_v.cssProps.above);
						var resetCSSProps	=	_v.cssProps.active;
						if(data.transition.match(_v.regex.transition.slideIn) || data.transition.match(_v.regex.transition.none)) {
							resetCSSProps = dir == "left" ? _v.cssProps.hiddenR : _v.cssProps.hiddenL;
						};
						data.sectionList[data.targetSection].css(resetCSSProps);
						var animObjTarget	=	$.extend(true,{},_v.cssProps.active);
						!!data.transition.match(_v.regex.transition.fadeIn) && $.extend(true,animObjTarget,_v.cssProps.fadeIn);
						
						//	ANIMATE TARGET SECTION IN
						if(data.transition.match(_v.regex.transition.none)) {
							data.sectionList[data.targetSection].css(animObjTarget);
							data.isAnimating.resolve();
							callback();
						} else {
							data.sectionList[data.targetSection].animate(animObjTarget,data.speed,data.easing,function() {
								data.isAnimating.resolve();
								callback();
							});
						};
						if(data.nav) {
							data.nav
								.find("." + data.activeNavItemClass)
								.removeClass(data.activeClass);
							data.navItems[data.targetSection].addClass(data.activeNavItemClass);
						};
						data.currentSection = data.targetSection;
					};
				});
			}
		};
	$.fn[pluginName] = function(m) {
		
		// IF THE METHOD PASSED EXISTS...
		if(_m[m]) {
			
			// RETURN THE METHOD AND ANY ATTACHED ARGUMENTS
			return _m[m].apply(this,Array.prototype.slice.call(arguments,1));
		
		// IF NOTHING IS PASSED OR NO METHOD IS PASSED BUT AN OBJECT IS PASSED...
		} else if (!m || typeof m == "object") {
			
			// RUN THE init METHOD BY DEFAULT AND PASS ANY ATTACHED ARGUMENTS
			return _m.init.apply(this,arguments);
			
		// IF WHAT IS PASSED DOESNT APPLY...
		} else {
			
			// SHOW AN ERROR
			$.error(_v.pluginName + ": Invalid method passed");			
		};
	};
})(jQuery);
