/*
*   5/22/2011
*	@projectDescription Scott Smith's Professional Resume
*   @author Scott Smith (scott dot smith at pop dot com)
*	@version 1.1
*	@namespace SCOTT
*	@dependencies jquery 1.5.1, hoverIntent r6, jquery.address
*/

SCOTT = {};

/**
*	@classDescription controller static unenforced singleton creates/ controlls different section views
*	@return {object} Publicly accessible methods
**/
SCOTT.sectionController = (function() {
	
	var self = {},
		sections = [],
		sectionsLen = 0,
		currentSection = 0,
		isInitialLoad = true,
		isAnimating = false,
		mainNav = {},
		subnav = {};

/**
*	Private initializor find all 'sections', make new instances of SCOTT.section, set event handlers, make a sub nav for the 'Experience' section.
*	TODO: Make sub nav creation dynamic based on occurence of neste list in main nav.
*	@see SCOTT.sectionController.init()
*	@return {void}
**/	

	function __init() {
		var s = $('section');
		self = SCOTT.sectionController;
		s.each(function(i, obj) {
			sections[i] = new SCOTT.section(obj);
		});
		sectionsLen = s.length;
		subnav = new SCOTT.subnav('li.sub-nav');
		__initHandlers();
	}

/**
*	Initialize event handlers for deep linking - jquery.address
*	@return {void}
*	@see setSection()
**/
	function __initHandlers() {
		var arr = [];
		mainNav = $('#main-nav ul');
		$.address.init(function(e) {
            $('a', mainNav).address(function() {
                return $(this).attr('href').replace(location.pathname, '/');
            });
        }).change(function(e) {
			//is there no url data?  go to default start section 'mission'
            if(e.value === '' || e.value === '/') {			
				arr[0] = 'mission';			
			}else {
				arr = __cleanPaths(e.value);
			}
			self.setSection(arr);    	
        });
	}

/**
*	Makes and returns a 'cleaned' array from a '/' separated string
*	@param {string} str ex: '/technical/technical-child/'
*	@return {array}
*	@see setSection()
**/
	function __cleanPaths(str) {
		var arr = str.split('/');
		$(arr).each(function(i, val) {
			if(val === '') {
				arr.splice(i, 1);
			}
		});
		return arr;
	}
	
/**
*	Loops through main and sub nav menus and sets css 'on states'
*	@param {string} str current section name ex: 'mission'
*	@param {string} pString name of current section's parent section ex: 'experience'
*	@return {void}
**/
	function __setNavButtons(str, pString) {
		var a = mainNav.find('[href="'+str+'"]'),
			p,
			btns = {},
			pBtns = {};
		pBtns = mainNav.find('li.nav-on');
		if(pString) {			
			p = subnav.el.find('> [href="'+pString+'"]');
			btns = subnav.el.find('li.nav-on');
			if(btns.length) {
				btns.removeClass('nav-on');
			}
			if(pBtns) {
				pBtns.removeClass('nav-on');
			}
			p.parent('li').addClass('nav-on');
		}else {
			if(pBtns) {
				pBtns.removeClass('nav-on');
			}
		}
		a.parent('li').addClass('nav-on');
	}
	
/**
*	Publicy acccessible methods object
**/
	return {

/**
*	Gain access to the protected init method
*	@return {void}
**/
		init: function() {
			__init();
		},

/**
*	Controls the subnav menu and section behaviors based on array of section names if nothing is currently animating and the sections name(s) are valid
*	TODO: abstract this out to accept any number of levels and nested sections
*	@param {array} arr
*	@return {void}
**/
		setSection: function(arr) {
			var len = arr.length,
				sectionString = '',
				sectionIndex = 0,
				i = 0;
				
			if(arr[0] === 'experience') {
				//Show the experience subnav
				subnav.intro(false);
				//if no sub page remove on-state
				if(!arr[1]) { 
					__setNavButtons(arr[0]);
				}
			}else {
				//Hide subnav if not in the experience section
				subnav.outro(false);
			}
			if(isAnimating === false) {
				if(len === 1 || len === 2) {
					//loop through sections array looking for section match, doesnt do anything if no match
					for(i = 0; i < sectionsLen; i++) {
						if(String(sections[i].name) === arr[len - 1]) {
							if(len === 1) {
								__setNavButtons(arr[0]);
							}else {
								__setNavButtons(arr[0]+'/'+arr[1], arr[0]);
							}
							//initial visit to site no need to animate anything out
							if(isInitialLoad) {
								isInitialLoad = false;
								sections[i].intro();
							}else {
								//animate previous section out pass calback to animate current section in
								sections[currentSection].outro(
									sections[i].intro, 
									sections[i]
								);
							}
							currentSection = i;
							break;
						}
					}
				}		
			}
		},

/**
*	Set our isAnimating flag
*	@param {boolean} bool
*	@retun {void}
**/
		setAnimating: function(bool) {
			isAnimating = bool;
		}
	};
	
}());

/**
*	@classDescription content section object with animation in and out methods.  Based on html section markup
*	@param {object} target html 'section' element 
*	@param {object} options config object 
**/
SCOTT.section = function(target, options) {
	var self = this;
	self.el = $(target);
	self.name = self.el.attr('id');
	
	//TODO: Enable ability to pass in any number of child animation objects
	self.options = $.extend({
		inTime: 300,
		outTime: 300
	}, options || {});
	
	//TODO: Make these different object types, SCOTT.animationObj
	//animation objects
	self.upper = $(self.el.find('.upper-right'));
	self.lower = $(self.el.find('.lower-left'));
	self.content = $(self.el.find('.content'));

	//original choordinates for our animation object
	self.upperX = self.upper.css('right');
	self.upperY = self.upper.css('top');
	self.lowerX = self.lower.css('left');
	self.lowerY = self.lower.css('bottom');
	self.contentX = self.content.css('left');
	
	//the List of thumbs in certain sections
	self.thumbs = $('ul.slide-list', self.el);
	self.thumbLen = self.thumbs.find('li').length;
	self.slideList = null;
	if(self.thumbLen > 0) {
		self.slideList = new SCOTT.slideList(self.thumbs);
	}
};

/**
*	@return {object} Publicly accessible methods on the prototype
**/
SCOTT.section.prototype = {

/**
*	Animate all of the section animation objects in
*	@param {function} callback optional
*	@param {object} ctx optional scope context for callback
*	@return {void}
**/	
	intro: function(callback, ctx) {
		var self = this,
			_ctx = ctx || this;
		self.el.removeClass('hidden');
		
		self.lower.animate({
			'bottom': '0px',
			'left': '0px',
			'opacity': '1'
		}, self.options.inTime);
		self.upper.animate({
			'top': '0px',
			'right': '0px',
			'opacity': '1'
		}, self.options.inTime, function() {
			self.content.animate({
				'left': '100px',
				'opacity': '1'
			}, self.options.inTime, function() {
				if(typeof callback === 'function') {
					callback.call(_ctx);
				}else {
					if(self.slideList) {
						self.slideList.intro();
					}
					SCOTT.sectionController.setAnimating(false);
				}
			});
		});
	},
	
/**
*	Animate all of the section animation objects out
*	@param {function} callback optional
*	@param {object} ctx optional scope context for callback
*	@return {void}
**/
	outro: function(callback, ctx) {
		var self = this,
			_ctx = ctx || this,
			time = 0,
			tout = {},
			tout2 = {};
		if(self.slideList) {
			self.slideList.outro();
			time = 1000;
		}
		
		//a timepout is set if we have a thumb list so that it can have a chance to animate out
		tout = setTimeout(function(){
			self.content.animate({
				'opacity': '0',
				'left': self.contentX

			}, self.options.outTime, function() {
				self.upper.animate({
					'opacity': '0',
					'top': self.upperY,
					'right': self.upperX

				});
				self.lower.animate({
					'opacity': '0',
					'bottom': self.lowerY,
					'left': self.lowerX

				}, self.options.outTime, function() {
					self.el.addClass('hidden');	
					
					//Let's wait a just a moment before we animate other stuff in				
					tout2 = setTimeout(function() {
						if(typeof callback === 'function') {
							callback.call(_ctx);
						}else {
							SCOTT.sectionController.setAnimating(false);
						}
						clearTimeout(tout2);
					}, 400);				
					clearTimeout(tout);
				});
			});
		}, time);	
	}
};

/**
*	@classDescription sub nav object with animation in and out methods.  Based on html sub nav markup
*	@param {object} target html 'section' element 
*	@param {object} options config object 
**/
SCOTT.subnav = function(target, options) {
	var self = this;
	self.el = $(target);
	self.isAnimating = false;
	self.options = $.extend({
		topIn: '27px',
		topOut: '13px',
		inTime: 200,
		outTime: 200
	}, options || {});
	self.init();
};

/**
*	@return {object} Publicly accessible methods on the prototype
**/
SCOTT.subnav.prototype = {
	
/**
*	@return {void}
**/
	init: function() {
		var self = this;
		self.initHandlers();
		self.ul = self.el.find('ul');
	},
	
/**
*	Initialize event listeners.  Uses hoverIntent in place of hover
*	@return {void}
**/
	initHandlers: function() {
		var self = this,
			navOn = false;
		self.el.hoverIntent(function(e){
			navOn = self.el.hasClass('nav-on');
			self.intro(navOn);
		}, function(e) {
			navOn = self.el.hasClass('nav-on');
			self.outro(navOn);
		});
	},
	
/**
*	@param {boolean} bool if not active link then do stuff
**/
	intro: function(bool) {
		var self = this;
		if(self.isAnimating === false && !bool) {
			self.ul.removeClass('hidden');
			self.isAnimating = true;
			self.ul.animate({
				'top': self.options.topIn,
				'opacity': '1'
			}, self.options.inTime, function() {
				self.isAnimating = false;
			});
		}
	},
	
/**
*	@param {boolean} bool if not active link then do stuff
**/
	outro: function(bool) {
		var self = this;
		if(self.isAnimating === false && !bool) {
			self.isAnimating = true;
			self.ul.animate({
				'top': self.options.topOut,
				'opacity': '0'
			}, self.options.outTime, function() {
				self.ul.addClass('hidden');
				self.isAnimating = false;
			});
		}
	}
};

/**
*	@classDescription thumbnail list object with animation in and out methods.  Based on html list markup
*	@param {object} target html 'section' element 
*	@param {object} options config object , offsetY {int}, inTime {int}, outTime {int}, waitTime {int} - time in m/s to wait until next thumb comes in
**/
SCOTT.slideList = function(target, options) {
	var self = this;
	self.el = $(target);
	self.options = $.extend({
		waitTime: 200,
		inTime: 300,
		outTime: 300,
		offsetY: 75
	}, options || {});
	self.len = self.el.length;
	self.h = self.el.find('li').height();
};

SCOTT.slideList.prototype = {
/**
*	initialize stubb
**/
	init: function() {
		
	},
	
/**
*	Animate thumbs in 1 at a time
**/
	intro: function() {
		var self = this,
			touts = [];
		$(self.el.find('li')).each(function(i, obj) {
			(function(i) {
				//set timeout for delay between thumbs
				touts[i] = setTimeout(function() {
					$(obj).animate({
						'opacity': '1',
						'top': (i * self.h) + 'px' 
					}, self.options.inTime, function() {
						clearTimeout(touts[i]);
					});
				}, self.options.waitTime * (i + 1));
			}(i));
		});
	},
	
/**
*	Animate thumbs out 1 at a time
**/
	outro: function() {
		var self = this,
			touts = [];
		$(self.el.find('li')).each(function(i, obj) {
			(function(i) {
				//set timeout for delay between thumbs
				touts[i] = setTimeout(function() {
					$(obj).animate({
						'opacity': '0',
						'top': (i * self.options.offsetY + self.h) + 'px' 
					}, self.options.outTime, function() {
						clearTimeout(touts[i]);
					});
				}, self.options.waitTime * (i + 1));
			}(i));
		});
	}
};

/**
*	@classDescription give the site that sweet papyrus look
*	@param {object}
**/
SCOTT.awesomify = function(target, options) {
	var self = this;
	self.options = $.extend({
		initText: 'awesome-ify',
		afterText: 'un-awesome-ify'
	}, options || {});
	self.el = $(target);
	self.init();
};

SCOTT.awesomify.prototype = {

/**
*	@return {void}
**/
	init: function() {
		var self = this;
		self.el.click(function(e) {
			e.preventDefault();
			self.onClickHandler();
		});
	},
	
/**
*	Toggles the body class and text for the target
*	@return {void}
**/
	onClickHandler: function(obj) {
		var self = this;
			html = self.el.html();
		if(html === 'awesome-ify') {
			$('body').addClass('awesome-ify');
			self.el.html(self.options.afterText);
		}else {
			$('body').removeClass('awesome-ify <');
			self.el.html(self.options.initText);
		}
	}
};

/**
*	On DOM ready 
**/
$(function() {
	var awesome = new SCOTT.awesomify('li.awesome a');
	SCOTT.sectionController.init();
});






















