///////////////////////////////////////////////////////////////////////////////
//	Core
///////////////////////////////////////////////////////////////////////////////
/**
 * The SD Global object.
 * @module SD
 * @title  SD Global
 */
if (typeof SD == "undefined" || !SD) {
	/**
	 * The SD global namespace object.  If SD is already defined, the
	 * existing SD object will not be overwritten so that defined
	 * namespaces are preserved.
	 * @class SD
	 * @static
	 */
	var SD = {};
}

/**
 * The bootstrap method is meant to load and initialize page components.
 *
 * The bootstrap method can only be executed once.
 * 
 * @method bootstrap
 * @static
 */
SD.bootstrap = (function () {
	$(document).ready(function () {
		// console.profile('Bootstrap');
		SD.page.Common.initialize();
		// console.profileEnd();
	});
	return function () {
		throw new Error('Bootstrap has already executed.');
	}
})();

///////////////////////////////////////////////////////////////////////////////
//	Language
///////////////////////////////////////////////////////////////////////////////
/**
 * The Language Components
 * @module lang
 * @title Language Components
 */
SD.lang = {};

/**
 * A helper method to ensure an object implements certain methods/properties.
 * @namespace SD.lang
 * @method ensureImplements
*/

SD.lang.ensureImplements = function () {
	// TODO: Actually make me!
}

/**
 * An abstract class helper
 * @namespace SD.lang
 * @class Class
*/
SD.lang.Class = function (args) {
	var Class = {};
	Class.name = args.name;

	// Return our beautiful new Class
	return Class;
};

///////////////////////////////////////////////////////////////////////////////
//	User Interface Components
///////////////////////////////////////////////////////////////////////////////
/**
 * The User Interface Components 
 * @module ui
 * @title User Interface Components
 */
SD.ui = {};

/**
 * The AbstractComponent component is a convenience class that autoinitializes
 * itself only if its container property (a DOM element) exists.
 * @namespace SD.ui
 * @class AbstractComponent
 * @extends SD.lang.Class
 * @constructor
 * @param args {Object} An arguments object.
*/
SD.ui.AbstractComponent = function (args) {
	var that = SD.lang.Class(args);
	that.container = args.container;
	if (typeof that.container !== 'undefined') {
		$(document).ready(function () {
			that.initialize();
		});
	}
	
	return that;
};

/**
 * The ContentScroller component utilizes jScrollPane to create a region of
 * scrollable content using a custom-styled scrollbar.
 * @namespace SD.ui
 * @class ContentScroller
 * @extends SD.ui.AbstractComponent
 * @static
*/
SD.ui.ContentScroller = (function () {
	var that = SD.ui.AbstractComponent({
		/**
		 * Name of the class (default: 'ContentScroller').
		 * @property name
		 * @type String
		 */
		name: 'ContentScroller',
		/**
		 * The main container of the content scroller.
		 * @property container
		 * @type HTMLElement
		 */
		container: $('#bd-content-scroller').get(0)
	});
	/**
	 * Initializes the content scroller by also initializing the jScrollPane.
	 * @method initialize
	 */
	that.initialize = function () {
		// Build jScrollPane container
		that.container.scrollTop = '0';
		$(that.container).jScrollPane({
			showArrows: true,
			// animateTo: true,
			scrollbarWidth: 13
		});
		
		// Strip out inline styles (for printing reasons)
		$(that.container).css({
			position: '',
			width: ''
		});
		$(that.container).parent().css({
			height: '',
			width: ''
		});
	};
	
	return that;
})();

/**
 * TODO: Add description
 * @namespace SD.ui
 * @class CutFinder
 * @extends SD.ui.AbstractComponent
 * @static
*/
SD.ui.CutFinder = (function () {
	var that = SD.ui.AbstractComponent({
		/**
		 * Name of the class (default: 'CutFinder').
		 * @property name
		 * @type String
		 */
		name: 'CutFinder',
		/**
		 * The main container of the content scroller.
		 * @property container
		 * @type HTMLElement
		 */
		container: $('#cut_finder').get(0)
	});
	/**
	 * Initializes the content scroller by also initializing the ColorBox modal.
	 * @method initialize
	 */
	that.initialize = function () {
		// Define elements
		that.popup = $('#cut_finder-popup').get(0);
		that.buttons = {
			open: $('#cut_finder-link').get(0),
			close: $('#cut_finder-popup-close').get(0)
		};
		
		// Create modal window
		that.createModalWindow();
		
		// Setup button handlers
		$(that.buttons.open).click(that.handleButtons);
		$(that.buttons.close).click(that.handleButtons);
	};
	that.createModalWindow = function () {
		// Initialize jqModal
		$(that.popup).jqm({
			overlay: 1
		});
		
		// Setup link handler
		$('ul', that.popup).click(that.handleLinks);
	};
	that.openWindow = function () {
		$(that.popup).jqmShow();
	};
	that.closeWindow = function () {
		$(that.popup).jqmHide();
	};
	that.handleButtons = function (e) {
		e.preventDefault();
		
		if (this === that.buttons.open) {
			that.openWindow();
		} else if (this === that.buttons.close) {
			that.closeWindow();
		}
	};
	that.handleLinks = function (e) {
		if (e.target.tagName === 'A' && String(window.location).match(e.target.pathname)) {
			e.preventDefault();
			$(SD.ui.ContentScroller.container)[0].scrollTo(e.target.hash);
			$(that.popup).jqmHide();
		}
	};
	
	return that;
})();

/**
 * TODO: Add description
 * @namespace SD.ui
 * @class CutFinder
 * @extends SD.ui.AbstractComponent
 * @static
*/
SD.ui.StoreLinks = (function () {
	var that = SD.ui.AbstractComponent({
		/**
		 * Name of the class (default: 'StoreLinks').
		 * @property name
		 * @type String
		 */
		name: 'StoreLinks',
		/**
		 * The main container of the store links.
		 * @property container
		 * @type HTMLElement
		 */
		container: $('ul#stores').get(0)
	});
	
	that.initialize = function () {
		$('a[rel="external"]').attr('target', '_blank');
	};
	
	return that;
})();

///////////////////////////////////////////////////////////////////////////////
//	Pages
///////////////////////////////////////////////////////////////////////////////
/**
 * The Page components 
 * @module page
 * @title Page components
 */
SD.page = {};

/**
 * The Common page.
 * @namespace SD.page
 * @class Common
 * @static
*/
SD.page.Common = {
	initialize: function () {
		// Allows for targeting CSS selectors for users with JavaScript enabled
		$('body').addClass('has_script');
		
		// Initialize analytics based on environment
		var url = window.location.toString();
		if (url.match('local.') || url.match('qa.')) {
			// dev/qa tracking
			var account = 'UA-8394476-2'
		} else {
			// live tracking
			var account = 'UA-8394476-1'
		}
		SD.util.Analytics.initialize({
			account: account
		});
		
		// Build print links
		$('#print').click(function (e) {
			window.print();
			e.preventDefault();
		});
	}
};
///////////////////////////////////////////////////////////////////////////////
//	Utilities
///////////////////////////////////////////////////////////////////////////////
/**
 * A collection of useful utilities.
 * @module util
 * @title Utilities
 */
SD.util = {};

/**
 * The Analytics utility.
 * @namespace SD.util
 * @class Analytics
 * @static
*/
SD.util.Analytics = {
	options: {},
	trackers: [],
	/**
	 * Initializes the Analytics helper.
	 * @
	 */
	initialize: function (options) {
		// Set options
		if (options.account === undefined) {
			throw new Error('Account number must be defined for Analytics helper.');
		} else {
			this.options.account = options.account;
		}
		if (options.autoTrackPageView === false && options.autoTrackPageView !== undefined) {
			this.options.autoTrackPageView = options.autoTrackPageView;
		} else {
			this.options.autoTrackPageView = true;
		}
		if (options.propSalt === undefined) {
			this.options.propSalt = 'svu';
		} else {
			this.options.propSalt = options.propSalt;
		}
		if (options.props !== undefined) {
			this.props = options.props;
		};
		
		// Download analytics JavaScript core
		this.downloadScript();
		
		// Execute routines when analytics JavaScript has been downloaded
		$(this).bind('scriptReady', SD.util.Event.createDelegate(this, function (e) {
			this.buildTracker();
			if (this.options.autoTrackPageView) this.trackPageView();
		}));
	},
	downloadScript: function () {
		var that = this;
		var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
		$.getScript(gaJsHost + 'google-analytics.com/ga.js', function () {
			$(that).trigger('scriptReady');
		});
	},
	buildTracker: function () {
		// Try to create tracker
		try {
			if (typeof this.options.account === 'string') {
				this.trackers.push(_gat._getTracker(this.options.account));
			} else {
				for (var i=0; i < this.options.account.length; i++) {
					this.trackers.push(_gat._getTracker(this.options.account[i]));
				};
			}
		} catch(err) {}
	},
	buildURL: function (href) {
		// Define placeholder variables
		var path, tags = '';
		if (href) {
			path = href;
		} else {
			path = window.location.pathname + window.location.search;
		}
		
		// Add page properties to path
		if (this.props) {
			// Build prop query string
			for (prop in this.props) {
				tags += '&' + this.options.propSalt + '_' + prop + '=' + this.props[prop];
			}
			// Determine if a query string already exists in the path
			var regexp = new RegExp(/^.*?\?/);
			if (!path.match(regexp)) {
				tags = '?' + tags.substr(1, tags.length);
			}
		}
		
		return String(path + tags);
	},
	trackEvent: function (category, action, label, value) {
		// Check for trackers
		if (this.trackers.length === 0) {
			throw new Error('No trackers have been defined in the Analytics helper.');
		}
		// Check for arguments
		if (category === undefined || action === undefined) {
			throw new Error('A category and action must be provided in order to track an event with the Analytics helper.');
		} else {
			for (var i=0; i < this.trackers.length; i++) {
				this.trackers[i]._trackEvent(category, action, label, value);
				// console.info('ANALYTICS | Track Event | ' + category + '::' + action + '::' + label + '::' + value);
			};
		}
	},
	trackPageView: function (href) {
		// Check for trackers
		if (this.trackers.length === 0) {
			throw new Error('No trackers have been defined in the Analytics helper.');
		}
		if (href) {
			for (var i=0; i < this.trackers.length; i++) {
				this.trackers[i]._trackPageview(this.buildURL(href));
				// console.info('ANALYTICS | Track Pageview | ' + this.buildURL(href));
			};
		} else {
			for (var i=0; i < this.trackers.length; i++) {
				this.trackers[i]._trackPageview(this.buildURL());
				// console.info('ANALYTICS | Track Pageview | ' + this.buildURL());
			}
		}
	}
};

/**
 * The Event utility.
 * @namespace SD.util
 * @class Event
 * @static
 */
SD.util.Event = {
	/**
	 * A helper method that creates a function to call the specified function
	 * within the context of the specified object.
	 * @method createDelegate
	 * @param context {Object} The object that will become <code>this</code>
	 * when the specified function is called.
	 * @param func {Function} The function to be called.
	 * @return {Function}
	 */
	createDelegate: function (context, func) {
		return function (e) {
			e = e || {};
			// Forces currentTarget property of the Event object for browsers that don't correctly support it
			e.currentTarget = this;
			// Call function within context of specified object
			func.apply(context, [e]);
		};
	},
	/**
	 * Dummy event handler that prevents default event behavior
	 * @method dummyEventHandler
	 * @param e {Event}
	 */
	dummyEventHandler: function (e) { 
		e.preventDefault();
	}
};

/**
 * The Printer utility.
 * @namespace SD.util
 * @class Printer
 * @static
 */
SD.util.Printer = {
	print: function () {
		// Save current state of styles
		var $content = $(SD.ui.ContentScroller.container),
			$scroller = $content.parent(),
			contentStyle = {
				width: $content.css('width'),
				position: $content.css('position'),
				top: $content.css('top')
			},
			scrollerStyle = {
				height: $scroller.css('height'),
				width: $scroller.css('width')
			};
		
		// Clear out the problematic styles
		$content.css({
			width: 'auto',
			position: 'relative',
			top: '0'
		});
		
		$scroller.css({
			height: 'auto',
			width: 'auto'
		});
		
		// Print
		window.print();
		
		$scroller.css({
			height: scrollerStyle.height,
			width: scrollerStyle.width
		});
	}
};
