/**
 * This file is for things that need to be just about anywhere.
 **/
YUI.add('nfl-lang', function (Y) {
	var PI_FIND    = /(\d)(\d{3}(?:,\d{3})*(?:\.\d+)?)$/,
	    PI_REPLACE = "$1,$2", COLOR_RE = /^#(?:[\dA-F]{3}){1,2}$/,
		NON_WORD   = /[^\w\-]/g;
	
	Y.namespace('String');
	Y.String = Y.merge(Y.String, {
		// From http://github.com/sstephenson/prototype/blob/master/src/lang/string.js
		// with unicode elipsis
		capitalize: function (string) {
			return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
		},
		truncate: function (string, length, truncation) {
			length = length || 30;
			truncation = Y.Lang.isUndefined(truncation) ? "\u2026" : truncation;
			return string.length > length ?
				string.slice(0, length - truncation.length) + truncation : string;
		},
		truncateAtLastWord: function (string, length, truncation) {
			return string.length > length ?
		    	Y.String.truncate(string, string.substring(0, length).lastIndexOf(' ') + 1, truncation) :
				string;
		},
		urlify: function (value) {
			return (value + '').replace(NON_WORD, '').toLowerCase();
		}
	});

	Y.Lang = Y.merge(Y.Lang, {
		isINT: function (value) {
			return Y.Lang.isNumber(value) && Math.floor(value) === value;
		},
		isUINT: function (value) {
			return Y.Lang.isINT(value) && value >= 0;
		},
		isColor: function (value) {
			return COLOR_RE.test(value); 
		},
		toInt: function (value) {
			return parseInt(value, 10);
		},
		toPrettyInt: function (n, max) {
			var val = parseInt(n, 10), workingString, valAsString;
			if (isNaN(val)) {
				Y.log('Y.Lang.toPrettyInt(' + n + ', ' + max + ') -> NaN');
				return "0";
			}
			if (max && Math.abs(val) > Math.abs(max)) {
				val = max;
			}
			
			valAsString = val.toString();

			while (workingString !== valAsString) {
				workingString = valAsString;
				valAsString   = valAsString.replace(PI_FIND, PI_REPLACE);
			}
			if (val === max) {
				valAsString += '+';
			}
			return valAsString;
		},
		toString: function (value) {
			return value + '';
		},
		escapeHTML: function (string) {
			return string.replace(/\&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt');
		},
		// Prototype's K function
		K: function (a) {
			return a;
		},
		// Prototype's emptyFunction
		emptyFunction: function () {},
		/**
		 * Adds parameters to a URL, honoring existing parameters/hashes.
		 */
		addParamsToURL: function (url, params) {
			var hashArray, hash = '';
			if (! url) {
				return '';
			}
			if (url.indexOf('#') > -1) {
				hashArray = url.split('#');
				url = hashArray[0];
				hash = '#' + hashArray[1];
			}
			return url +
				(url.indexOf('?') > -1 ? '&' : '?') +
				(Y.Lang.isString(params) ? params : Y.QueryString.stringify(params)) +
				hash;
		}
	});
}, "3.1.1", { requires: ['querystring'] });

/**
 * Y.NFL.TemplatePlugin
 *
 * The TemplatePlugin class provides a reusable object to duplicate
 * Prototype's Template class functionality. 
 * 
 * By default, this class uses Prototype's syntax for creating templates
 * from mark-up. E.g. the HTML:
 *
 * <div id="template"><a data-href="#{url}" target="#{target}">#{text.en.value}</a></div>
 * <script>
 * var el = Y.one('#template');
 * YUI().use('nfl-template-plugin', function (Y) {
 *   el.plug(Y.NFL.Template);
 *   el.template.update({
 *     url: '/',
 *     target: '_blank',
 *     text: { en: { value: 'home' }},
 *   });
 * });
 * </script>
 *
 * Yields:
 *
 * <div id="template"><a href="/" target="_blank">home</a></div>
 * 
 * Optionally, you can dynamically supply the template pattern as a
 * config property or an attribute, although there is a slight
 * change in template syntax:
 *
 * <div id="template"></div>
 * <script>
 * YUI().use('nfl-template-plugin', function (Y) {
 *   var el = Y.one('#template');
 *   el.plug(Y.NFL.Template, {
 *     pattern: '<a href="{url}" target="{target}">{text en.value}</a>'
 *   });
 *   el.template.update({
 *     url: '/',
 *     target: '_blank',
 *     text: { en: { value: 'home' }},
 *   });
 * });
 * </script>
 *
 * If adding multiple values to the `class=""` attribute via templates,
 * be sure that the element's class attribute contians multiple values
 * when the page is rendered.
 *
 * @namespace NFL
 * @class TemplatePlugin
 */
YUI.add('nfl-template-plugin', function (Y) {
	var $L = Y.Lang,
		DATA_RE      = / data\-(href|src|action|style)="([^"]*)"/g,
	    DATA_REPLACE = ' $1="$2"',
	    PROTOTYPE_RE = /#\{([^\}\.]+)(?:\.([^\}]+))?\}/g,
	    YUI_REPLACE  = "{$1 $2}";
	
	/**
	 * Returns the object value, or nested properties:
	 *
	 * Y.substitute("{default}/{level1 value}/{level1 level2.value}", {
	 *   default: "a",
	 *   level1: {
	 *     value: "b",
	 *     level2: {
	 *       value: "c"
	 *     }
	 *   } 
	 * }, getNested); // "a/b/c"
	 */
	function getNested(field, value, meta) {
	    var fields, obj, i, l, temp;
	    if (! (meta && $L.isObject(value))) {
	        return value;
	    }
	    fields = meta.split('.');
	    obj = value;
	    for (i = 0, l = fields.length; i < l; i = i + 1) {
	        temp = fields[i];
	        if ($L.isUndefined(obj[temp])) {
	            return '';
	        }
	        obj = obj[temp];
	    }
	    return obj;
	}
	
	function prototypeTemplate(string) {
		return string.replace(DATA_RE, DATA_REPLACE).replace(PROTOTYPE_RE, YUI_REPLACE);
	}
	
	function noProcessing(string) {
		return string;
	}
	
	Y.namespace('NFL').TemplatePlugin = Y.Base.create('nfl-template', Y.Plugin.Base, [], {
		initializer: function (config) {
			var host = this.get('host'),
				html = host.get('innerHTML');
			
			host.setContent('');
			this.set('originalHTML', html);
			
			if (config.processor) {
				this.set('processor', config.processor);
			}
			this.set('pattern', config.pattern ? config.pattern : this.get('processor')(html));
		},
		update: function (obj) {
			this.get('host').setContent(
				Y.substitute(this.get('pattern'), obj, this.get('manipulator'))
			);
		},
		destructor: function () {
			this.get('host').setContent(this.get('originalHTML')).setStyle('display', 'none');
		}
	}, {
		NS:   'template',
		MANIPULATE_GET_NESTED: getNested,
		PROCESS_PROTOTYPE_TEMPLATE: prototypeTemplate,
		NO_PROCESSING: noProcessing,
		ATTRS: {
			/**
			 * Template string passed to Y.substitute.
			 */
			pattern: {
				value: '',
				validator: $L.isString
			},
			/**
			 * Original HTML saved for unplug()
			 */
			originalHTML: {
				value: '',
				validator: $L.isString
			},
			/**
			 * Pre-process the hosts innerHTML to get a template string.
			 */
			processor: {
				value: prototypeTemplate,
				validator: $L.isFunction
			},
			/**
			 * Manipulator function passed to Y.substitute.
			 */
			manipulator: {
				value: getNested,
				validator: $L.isFunction
			}
		}
	});
}, "3.1.1", { requires: ['node', 'substitute', 'plugin', 'base-build']});

/**
 * Y.NFL.User
 *
 * The User class provides static methods to get information associated with a user.
 *
 * In order to be logged in, you must have all three NFL cookie: userId, at &
 * ptnr.
 *
 * @namespace NFL
 * @class User
 */
YUI.add('nfl-user', function (Y) {
	var COOKIE_USER = 'userId',
		COOKIE_SITELIFE = 'at',
		COOKIE_PARTNER = 'ptnr',
		COOKIE_PARTNER2 = 'partner',
		COOKIE_FANTASY = 'fan',
		SUCCESS_EVENT = 'fantasydata',
		FAILURE_EVENT = 'fantasydatafailure',
		INPUT       = "<input type=\"hidden\" />",
		GIGYA_CID   = "nfl_global_",
		GIGYA_CONF  = nfl.constants.GIGYA_CONF,
		SOCIAL_PROVIDER_ADDED_EVENT = "socialProviderAdded",
		SOCIAL_PROVIDER_REMOVED_EVENT = "socialProviderRemoved",
		YLang = Y.Lang, YCookie = Y.Cookie, YArray = Y.Array, YObject = Y.Object,
		yQueryStringParse = Y.QueryString.parse, yQueryStringStringify = function (obj, c) {
		    var qs = [],
		        // Default behavior is false; standard key notation.
		        s = c && c.arrayKey ? true : false,
		        key, i, l;

		    for (key in obj) {
		        if (obj.hasOwnProperty(key)) {
		            if (Y.Lang.isArray(obj[key])) {
		                for (i = 0, l = obj[key].length; i < l; i++) {
		                    qs.push((s ? key + '[]' : key) + '=' + (obj[key][i]));
		                }
		            }
		            else {
		                qs.push(key + '=' + obj[key]);
		            }
		        }
		    }

		    return qs.join('&');
		},
		PLUSES = /\+/g, SPACE = ' ', Constants = nfl.constants, User,
		GlobalEnv = YUI.namespace("Env.NFLUser"),
		gigya = Y.config.win.gigya;

	function getSubcodedValue(value) {
	    var v = value.split(':');
	    return {
	        id: v[0],
	        name: decodeURIComponent(v[1]).replace(PLUSES, SPACE)
	    };
	}

	function parseLData(sData) {
	    var aData = YArray.map(sData.split(','), getSubcodedValue);
		return {
			id: aData[0].id,
			name: aData[0].name,
			team: aData[1],
			draftDate: '',
			draftTime: '',
			draftType: ''
		};
	}

	function handleGigyaLoginResponse(response) {
		Y.use("node", function (Y) {
			var cn   = Y.Node.create,
				form = cn('<form action="' + nfl.constants.ID_MANAGER + '/social/login" method="POST" target="_self" style="display:none"><div></div></form>'),
				user = response.user,
				inputs;
			
			if (response.errorCode + "" === "0") { // success!
					
				inputs = YArray.map([ // loop through all of the user fields we use and create form fields for them
					"UID", "UIDSig", "UIDSignature", "age", "birthDay",
					"birthMonth", "birthYear", "city", "email", "firstName", "gender",
					"lastName", "nickname", "photoURL", "signatureTimestamp", "state",
					"thumbnailURL", "zip", "isSiteUID"
				], function (field) {
					return cn(INPUT).setAttrs({
						name: field,
						value: user[field]
					});
				}).concat([
					// mark the logged-in provider
					cn(INPUT).setAttrs({
						name: "provider",
						value: response.requestParams.provider
					}),
					// create a returnTo for the current page
					cn(INPUT).setAttrs({
						name: "returnTo",
						value: window.location.href
					})
					/* allow the SSO experience to be skinned 
					cn(INPUT).setAttrs({
						name: "s",
						value: self.get("ssoSkin")
					})
					*/
				]);
				
				// add the form to the page
				form.one("div").append(Y.all(inputs));
				Y.one("body").append(form);
				// submit it
				form.submit();
			}
		});
	}
	
	function callGigyaMethod(method, config) {
		Y.use("gigya-socialize", function () {
			Y.config.win.gigya.services.socialize[method](nfl.constants.GIGYA_CONF, config);
		});
	}

	function loginWithProvider(provider) {
		callGigyaMethod("login", {
			provider: provider,
			cid: GIGYA_CID + provider,
			pendingRegistration: true,
			callback: handleGigyaLoginResponse
		});
	}


	// TODO: Abstract into a generic User class and a CurrentUser class
	// that extends user
	User = Y.Base.create('nfl-user', Y.Base, [], {
		initializer: function (config) {
			if (config) {
				if (config.u) {
					this.set('username', config.u);
				}
				if (config.t) {
					this.set('team', config.t);
				}
				if (config.sps) {
					YArray.each(config.sps.split(","), function (provider) {
						this.set("providers." + provider, true);
					}, this);
				}
				if (config.p) {
					this.set("rememberMe", true);
				}
				if (config.la) {
					this.set("lastAccess", new Date(config.la * 1));
				}
			}
			this.originalConfig = Y.clone(config);
			this.publish(SUCCESS_EVENT, {
				emitFacade: true,
				fireOnce: true,
				preventable: false
			});
			this.publish(FAILURE_EVENT, {
				emitFacade: true,
				fireOnce: true,
				preventable: false
			});
			this.publish(SOCIAL_PROVIDER_ADDED_EVENT, {
				emitFacade: true,
				broadcast: 2,
				preventable: true,
				defaultFn: function (event) {
					event.target.setProvider(event.provider, true);
				}
			});
			this.publish(SOCIAL_PROVIDER_REMOVED_EVENT, {
				emitFacade: true,
				broadcast: 2,
				preventable: true,
				defaultFn: function (event) {
					event.target.setProvider(event.provider, false);
				}
			});
			this._fdsRequest = {
				request: '',
				callback: {
					success: Y.bind("_onSuccess", this),
					failure: Y.bind("_onFailure", this)
				}
			};
		},
		_onSuccess: function (response) {
			this.fire(SUCCESS_EVENT, response.data || response.response.results[0]);
		},
		_onFailure: function (response) {
			this.fire(FAILURE_EVENT);
		},
		_setUserName: function (value) {
			this.set('profilePageURL', '/fans/profile/' + encodeURIComponent(value));
		},
		_generateJSONPDataSource: function () {
			var oldDataSource = this.get('fantasyDataSource'),
				dataSource = new Y.DataSource.Get({
					source: Constants.FANTASY_API + this.get('apiURL')
				});
			if (oldDataSource) {
				oldDataSource.destroy();
			}
			this.set('fantasyDataSource', dataSource);
			return dataSource;
		},
		_onConnectionAdded: function (response) {
			console.log("[User] _onConnectionAdded(", response , ")");
			if (! response.errorCode) {
				this.fire(SOCIAL_PROVIDER_ADDED_EVENT, {
					provider: response.requestParams.provider
				});
			}
		},
		addConnection: function (provider, force) {
			var providers = this.get("providers");
			
			// connection is already added do nothing
			if (providers[provider]) { 
				return;
			}
			// otherwise, if the user has at least one provider, send the addConnection
			else if (force || YArray.some(YObject.values(providers), function (value) { return value;})) {
				callGigyaMethod("addConnection", {
					provider: provider,
					cid: GIGYA_CID + provider,
					callback: Y.bind("_onConnectionAdded", this)
				});
			}
			// if there are no providers do a getInfo to see if they're registered with gigya
			else {
				callGigyaMethod("getUserInfo", {
					callback: Y.bind(function (response) {
						if (response.user.isSiteUser) {
							this.addConnection(provider, true);
						}
						else {
							this.registerWithProvider(provider);
						}
					}, this)
				});
			}
		},
		_onConnectionRemoved: function (response) {
			console.log("[User] _onConnectionRemoved(", response , ")");
			if (! response.errorCode) {
				this.fire(SOCIAL_PROVIDER_REMOVED_EVENT, {
					provider: response.requestParams.provider				
				});
			}
		},
		setProvider: function (name, value) {
			var providers = [];
			this.set("providers." + name, value);
			YObject.each(this.get("providers"), function (value, key, obj) {
				if (value) {
					providers.push(key);
				}
			});
			User.mergeWithCookie({
				sps: providers.join(",")
			});
		},
		removeConnection: function (provider) {
			var providers = this.get("providers");
			if (providers[provider]) {
				callGigyaMethod("removeConnection", {
					provider: provider,
					cid: GIGYA_CID + provider,
					callback: Y.bind("_onConnectionRemoved", this)
				});
			}
		},
		_onRegisterResponse: function (response) {
			console.log("[User] _onRegisterResponse(", response , ")");
			if (! response.errorCode) {
				this.fire(SOCIAL_PROVIDER_ADDED_EVENT, {
					provider: response.requestParams.provider				
				});
			}
		},
		registerWithProvider: function (provider) {
			callGigyaMethod("login", {
				provider: provider,
				cid: GIGYA_CID + provider,
				pendingRegistration: true,
				callback: this._onRegisterResponse,
				context: this
			});
		},
		getFantasyData: function (force) {
			var fds = this.get('fantasyDataSource');
			if ((!fds) || force) {
				fds = this._generateJSONPDataSource();
			}
			fds.sendRequest(this._fdsRequest);
		},
		destructor: function () {
			var dataSource = this.get('dataSource');
			if (dataSource) {
				dataSource.destroy();
			}
		}
	}, {
		SOCIAL_PROVIDER_ADDED_EVENT: SOCIAL_PROVIDER_ADDED_EVENT,
		SOCIAL_PROVIDER_REMOVED_EVENT: SOCIAL_PROVIDER_REMOVED_EVENT,
		loginWithProvider: loginWithProvider,
		ATTRS: {
			apiURL: {
				value: "/internal/user/leagues?format=json&"
			},
			fantasyDataSource: {
				value: null
			},
			lastAccess: {
				valueFn: function () {
					return new Date();
				}
			},
			profilePageURL: {
				value: null
			},
			providers: {
				valueFn: function () {
					return YArray.reduce(Constants.GIGYA_CONF.enabledProviders.split(","), {}, function (init, provider) {
						init[provider] = false;
						return init;
					});
				}
			},
			rememberMe: {
				value: false,
				validator: YLang.isBoolean
			},
			team: {
				value: ' ' // Space means no favorite team. Go fig.
			},
			username: {
				value: null,
				setter: '_setUserName'
			}
		},
		/**
		 * Parses data from the fantasy cookie into a similar format to the JSON-P
		 * response. This static method is public and can be used by other apps,
		 * although the prefered method is <code>Y.NFL.User.getCurrent().getFantasyData()</code>.
		 */
		parseFantasyCookie: function () {
			var data = arguments[0] || YCookie.get(COOKIE_FANTASY, yQueryStringParse);

			return {
				leagues: YLang.isString(data.l) && data.l ? YArray.map(data.l.split('^'), parseLData) : [],
				autopicks: YLang.isString(data.a) && data.a ? YArray.map(data.a.split('^'), getSubcodedValue) : [],
				user: {
					id: data.fu || ''
				}
			};
		},
		/**
		 * Retreives the currently logged in user, as an instance of the User class
		 *
		 * @returns {User} the currently logged in user.
		 */
		getCurrent: function () {
			// ensure only on user ever gets created
			if (GlobalEnv.user) {
				return GlobalEnv.user;
			}
			
			var nflCookie       = YCookie.get(COOKIE_USER, yQueryStringParse),
				pluckCookie     = YCookie.get(COOKIE_SITELIFE, yQueryStringParse),
				partnerCookie   = YCookie.get(COOKIE_PARTNER, yQueryStringParse),
				fantasyCookie   = YCookie.get(COOKIE_FANTASY, yQueryStringParse),
				username        = nflCookie ? nflCookie.u : '',
				u;
			
			if (
				// ensure the user has all of our cookies
				nflCookie && pluckCookie && partnerCookie /* && partnerCookie2 */ &&
				// ensure all of the usernames match.
				username === pluckCookie.u && username === partnerCookie.u /* && username === partnerCookie2.u*/) {
				u = new User(nflCookie);
				if (fantasyCookie && fantasyCookie !== '0') {
					u.set('fantasyDataSource', new Y.DataSource.Local({
						source: User.parseFantasyCookie(fantasyCookie)
					}));
				}
				u.after("providersChange", function (event) {
					var providers = [];
					
					YObject.each(event.newVal, function (value, key) {
						if (value) {
							providers.push(key);
						}
					});
					User.mergeWithCookie({
						sps: providers.join(",")
					});
				});
				
				/* Login session reset... */
				(function () {
					var userSessionReset,			
						userSessionResetMouseHandler,
						userSessionResetKeyHandler;

					if (!GlobalEnv.trackingLastAction) {
						GlobalEnv.trackingLastAction = true;

						userSessionReset = function (e) {
							// Detatch events manually just in case
							Y.detach(userSessionResetMouseHandler);
							Y.detach(userSessionResetKeyHandler);

							// change cookie date				
							User.mergeWithCookie({
								la: new Date().getTime()
							});

							setTimeout(function(){
								userSessionResetMouseHandler = Y.once('mousedown', userSessionReset, document);
								userSessionResetKeyHandler = Y.once('keydown', userSessionReset, document);
							}, 10000);
						};
						userSessionResetMouseHandler = Y.once('mousedown', userSessionReset, document);
						userSessionResetKeyHandler = Y.once('keydown', userSessionReset, document);
					}
				}());
				
				GlobalEnv.user = u;
				return u;
			}
			YCookie.remove(COOKIE_USER);
			YCookie.remove(COOKIE_SITELIFE);
			YCookie.remove(COOKIE_PARTNER);
			YCookie.remove(COOKIE_PARTNER2);
			return false;
		},
		mergeWithCookie: function (obj) {
			var cookie = Y.merge(YCookie.get(COOKIE_USER, yQueryStringParse), obj),
				config = {
					path: "/",
					domain: ".nfl.com"
				}, expiry;
			
			// if the p ("permanent") is true, set the expiry for one year from date of issue ("d")
			if (cookie.p === "true") {
				expiry = new Date(cookie.d * 1);
				expiry.setUTCFullYear(expiry.getUTCFullYear() + 1);
				config.expires = expiry;
			}

			YCookie.set(COOKIE_USER, yQueryStringStringify(cookie), config);
		},
		FANTASY_DATA: SUCCESS_EVENT,
		FANTASY_FAILURE: FAILURE_EVENT
	});
	// get the NFL user initially
	User.getCurrent();
	
	// we should stop using Y.NFL.x
	Y.NFLUser = Y.namespace("NFL").User = User;
	
}, "3.3.0", { requires: ['array-extras', 'base-build', 'cookie', 'querystring', 'datasource-local', 'datasource-get', "plugin", 'nfl-lang'] });

YUI.add('nfl-subscriptions', function (Y) {
	
	Y.namespace('NFL').Subscriptions = Y.Base.create("nfl-subscriptions", Y.Base, [], {
        initializer: function(config) {
			this.publish('responded', {
				emitFacade: true,
				fireOnce: true,
				preventable: false
			});
			this.after('readyChange',this._afterResponded,this);
			if(config.onResponse){ this.on('responded',config.onResponse); } //allow pass in of callback to make this a one line piece of kit
			this.set('user',Y.NFL.User.getCurrent());
			if(this.get('user') === null || this.get('user') === false){ this.set('ready',true); return; } //no user, don't even bother checking the rest of it
			if(this._hasCookie() && this.setSubsFromCookie()){
				this.set('ready',true); return; //has cookie, grok that
			}
			//try the long way
			this.setSubsFromService();
		},
		_getCookie: function(){
			var _val = Y.Cookie.get("nflsubs");
			return ((typeof _val === 'undefined' || _val === null)? null : _val.replace(/^"|"$/g, ''));
		},
		_hasCookie: function(){
			return (this.get('cookie') !== null);
		},
		_afterResponded: function(_c){
			this.fire('responded',{subscriptions: this.get('subscriptions')}); //always deliver payload of subs
		},
		_onDataResponse: function(r){
			console.info('subscription service response',r);
			
			if(r.response === null){ this.set('ready',true); return; } // all fail
			if(r.response.results === null){ this.set('ready',true); return; } // more fail
			if(r.response.results.length === 0){ this.set('ready',true); return; } // less fail
			
			/* set up data */
			//var _subs	= eval('('+r.response.results[0].responseText+')');
			var _subs	= [];
			Y.Array.each(r.response.results,function(_s){
				if(_s.active !== false && Y.Array.indexOf(_subs,_s.type) < -0){ _subs.push(_s.type); }
			},this);
			
			this.set('subscriptions',_subs);
			this.set('ready',true);
		},
		_onDataFailure: function(){ this.set('ready',true); },
		hasSubscription: function(_subkey){
			// Current possible types are GAME_PASS, FIELD_PASS, GAME_REWIND, PRESEASON_LIVE, NETWORK_ONLINE
			
			if(this.get('subscriptions') !== null){
				if(this.get('subscriptions').length > 0){
					if(Y.Array.indexOf(this.get('subscriptions'), _subkey) > -1){ return true; }
				}
			}
			return false;
		},
		setSubsFromCookie: function(){
			var _c, _vals, _subs;
			_c	= this.get('cookie');
			if(_c === null){ return; } // no cookie, cannot process
			_vals	= _c.split('|');
			_subs	= [];
			
			if(this.get('user').get('username') === _vals[0]){
				// usernames match, go for it machete style
				this.set('subscriptions',((_vals[1].indexOf(',') > -1) ? _vals[1].split(",") : [_vals[1]]));
				return true;
			}
			return false;
		},
		setSubsFromService: function(){
			this.set('ds', new Y.DataSource.Get({source: "http://subscriptions.nfl.com/nflsubs/subcheck?"}));
			this.get('ds').sendRequest({
				callback: {
					success: Y.bind(this._onDataResponse,this),
					failure: Y.bind(this._onDataFailure,this)
				}
			});
		},
		destroy: function(){
			try{
				if(this.get('ds') !== null){ this.get('ds').destroy(); }
				if(this.get('user') !== null){ this.get('user').destroy(); }
			}catch(e){}
		}
	},{
		'NAME': "Subscriptions",
		'ATTRS':{
			'ds':{value: null},
			'user':{value: null},
			'ready':{value: false}, // artificial flag for checking if object has run through all it's checks
			'subscriptions':{value: []},
			'cookie':{getter: '_getCookie'}
		}
	});
	
}, "3.1.1", { requires: ['array-extras', 'base-build', 'cookie','datasource-get','event','event-custom', 'nfl-lang','nfl-user'] });

/**
 * This Plugin provides internal navigation within a module.
 * 
 * Pluging this module into a Node will cause all clicks on
 * links within that node will be captured by the SubNavigation
 * instance, and the SubNavigation instance will fire an event
 * describing the navigation as well as set some class names on
 * the host element.
 * 
 * The SubNavgation.SECTION_CHANGE_EVENT fires whenever a user
 * clicks on a link within the SubNavgation instances host element.
 * SubNavgation uses anchor references in links, e.g. clicking on
 *
 *   <a href="#headlines-latest" />
 *
 * will indicates that the user is navigating to the `headlines-latest`
 * section. The SubNavgation instance will fire a SECTION_CHANGE event,
 * which uses a DOM event facade, with one additional property,
 * `section` which contains the indicated section. This even may be
 * prevented. If it is, the link click will behave as normal.
 *
 * In addition, the host element will receive a class name, e.g.
 * 
 *   yui3-nfl-subnav-s-headlines-latest
 *
 * allowing CSS styles to manage display as appropriate. Finally, the
 * class name
 *
 *   yui3-nfl-subnav-ready
 *
 * will be added to the host element when SubNavgation is initialized,
 * allowing progressive enhancement.
 */
YUI.add('nfl-subnav', function (Y) {

	function findHrefToNewVal(a) {
		var href = a.href;
		return href.substring(href.indexOf('#') + 1) === this.newVal;
	}

	Y.namespace('NFL').SubNavigation = Y.Base.create('nfl-subnav', Y.Plugin.Base, [], {
		initializer: function (config) {
			var host     = this.get('host');

			if (! this.get('id')) {
				this.set('id', host.get('id'));
			}
			host.addClass(this._getClassName(this.get('section')));
			this._navigateHandler = host.on('click', this._onNavigate, this);
			this._sectionChangeHandler = this.after('sectionChange', this._afterSectionChange, this);
		},
		_onNavigate: function (event) {
			var link = event.target.ancestor('a', true), newSection, href;
			if (! link) {
				return;
			}
			event.preventDefault();
			href = link.get('href');
			newSection = href.substring(href.indexOf('#') + 1);
			if (newSection !== this.get('section')) {
				this.set('section', newSection);
			}
		},
		_afterSectionChange: function (event) {
			var host = this.get('host'), li;
			
			host.replaceClass(this._getClassName(this.get('section')), this._getClassName(event.newVal));
			host.all('>li.current').removeClass('current');
			li = host.all('a[href$="#' + event.newVal + '"]');
			// IE gets a bad result here
			li = li.size() > 1 ?
				Y.one(Y.Array.find(host.all('a')._nodes, findHrefToNewVal, event)) :
				li.item(0);
			// ensure we get the proper parent LI
			try{
				do {
					li = li.ancestor('li');
				}
				while (li.get('parentNode') !== host);
				li.addClass('current');
			}catch(e){}
		},
		_getClassName: function (section) {
			return Y.ClassNameManager.getClassName(this.name, section);
		},
		destructor: function () {
			this.get('host').removeClass(this._getClassName('s-') + this.get('current'));
			this._navigateHandler.detach();
			this._sectionChangeHandler.detach();
		}
	}, {
		NS:   'subnav',
		SECTION_CHANGE: 'sectionChange',
		ATTRS: {
			/**
			 * Indicates the current section
			 */
			section: {
				value: null,
				validator: Y.Lang.isString
			},
			/**
			 * Represents the ID of the sub navigation.
			 */
			id: {
				value: null,
				validator: Y.Lang.isString
			} 
		}
	});
	
}, "3.1.1", { requires: [ 'node', 'plugin', 'base-build', 'classnamemanager', 'array-extras' ], optional: ['nfl-history-manager'] });
YUI.add("nfl-pagination", function (Y) {
	var $L = Y.Lang, Pagination;
	
	Pagination = Y.Base.create('lr-pagination', Y.Plugin.Base, [], {
		initializer: function (config) {
			var host     = this.get('host');
			
			this._clickHandler = host.on('click', this._onHostClick, this);
			this.after('pageChange', this._afterChanged, this);
			this.after('pagesChange', this._afterChanged, this);
			this._afterChanged();
		},
		_afterChanged: function (event) {
			var renderer = this.get('renderer'),
			    host     = this.get('host');

			if (renderer && host) {
				host.setContent(renderer.call(this));
			}
		},
		_onHostClick: function (event) {
			var link = event.target.ancestor('a', true), m, page, pages = this.get('pages');

			if (! link) {
				return;
			}
			m = link.get('href').match(this.get('urlRegExp'));
			if (! m) {
				return;
			}
			event.preventDefault();
			page = parseInt(m[1], 10);
			if (page === 0) {
				page = pages;
			}
			else if (page > pages) {
				page = 1;
			}
			this.set('page', page);
		},
		_validatePageNumber: function (value, name) {
			return $L.isUINT(value) && value <= this.get('pages');
		},
		destructor: function () {
			this._clickHandler.detach();
		}
	}, {
		NS: 'pagination',
		ATTRS: {
			page: {
				value: null,
				setter: $L.toInt
			},
			pages: {
				value: 1,
				setter: $L.toInt
			},
			renderer: {
				valueFn: function () {
					return Pagination.LEFT_RIGHT_RENDERER;
				},
				validator: $L.isFunction
			},
			spread: {
				value: 2,
				validator: $L.isUINT
			},
			maxDisplayed: {
				value: 5,
				validator: $L.isUINT
			},
			urlRegExp: {
				value: /#(?:.+\|)?page:(\d+)/
			},
			module: {
				value: null
			}
		},
		LEFT_RIGHT_RENDERER: function () {
			var page = this.get('page'), pages = this.get('pages'), module = this.get('module');
			
			return pages <= 1 ? '' :
				'<a aria-label="Previous" class="p-button previous' + (page === 1 ? ' disabled' : '') + '" href="#page:' + (this.get('page') - 1) + '"' + (module ? ' data-clickname="' + module + '_pagination_prev"': '') + '></a> ' +
				'<span class="page">' + this.get('page') + '</span> / ' +
				'<span class="pages">' + this.get('pages') + '</span> ' +
				'<a aria-label="Next" class="p-button next' + (page === pages ? ' disabled' : '') + '" href="#page:' + (this.get('page') + 1) + '"' + (module ? ' data-clickname="' + module + '_pagination_next"': '') + '></a> ';
		},
		LEFT_RIGHT_SCROLL_RENDERER: function () {
			var page = this.get('page'), pages = this.get('pages'), module = this.get('module');
			return pages <= 1 ? '' :
				'<a aria-label="Previous" class="p-button previous' + (page === 1 ? ' disabled' : '') + '" href="#page:' + (this.get('page') - 1) + '"' + (module ? ' data-clickname="' + module + '_pagination_prev"': '') + '></a> ' +
				'<a aria-label="Next" class="p-button next' + (page === pages ? ' disabled' : '') + '" href="#page:' + (this.get('page') + 1) + '"' + (module ? ' data-clickname="' + module + '_pagination_next"': '') + '></a> '+
				'<div class="pages-indicator"><span class="page">' + this.get('page') + '</span> / ' +
				'<span class="pages">' + this.get('pages') + '</span></div>';
		},
		PAGE_SPREAD_RENDERER: function () {
			var page = this.get('page'), pages = this.get('pages'),
			    spread = this.get('spread'), max = this.get('maxDisplayed'),
			    start, end, h = '', i, module = this.get('module');

			if (pages === 1) {
				return "";
			}

			// do I show the prev link?
			if (page > 1) {
				h += '<a class="previous" href="#page:' + (this.get('page') - 1) + '"' + (module ? ' data-clickname="' + module + '_pagination_prev"': '') + '>Previous</a> ';
			}

			// figure out the first page to show
			start = page - spread;
			if (pages - page < spread && page - spread > 0) {
				start -= spread - (pages - page);
			}
			if (start < 1) {
				start = 1;
			}

			// figure out the last page to show
			end = page + spread;
			if (end > pages || pages < max) {
				end = pages;
			}
			else if (end < max && pages >= max) {
				end = max;
			}
			
			// add all of the pages
			for (i = start; i <= end; i = i + 1) {
				h += '<a class="page' + (i === page ? ' current' : '') + '" href="#page:' + i + '"' + (module ? ' data-clickname="' + module + '_pagination_"' + i: '') + '>' + i + '</a> ';
			}
			
			// do I show the next link?
			if (page < pages) {
				h += '<a class="next" href="#page:' + (this.get('page') + 1) + '"' + (module ? ' data-clickname="' + module + '_pagination_next"': '') + '>Next</a> ';
			}
			return h;
		}
	});
	
	Y.namespace("NFL").Pagination = Pagination;
	
}, "3.1.1", { requires: ['plugin', 'base-build', 'nfl-lang'] });

YUI.add('nfl-carousel', function (Y) {
	var $L = Y.Lang;
	
	Y.namespace("NFL").Carousel = Y.Base.create('lr-carousel', Y.Plugin.Base, [], {
		initializer: function (config) {
			var host  = this.get('host'),
			    frame = host.one('ol');
			
			if ($L.isFunction(config.renderer)) {
				this.set('renderer', config.renderer);
			}
			this.set('pageWidth', config.pageWidth || 0);
			this.set('totalWidth', config.totalWidth || config.pageWidth);
			this.set('perPage', config.perPage || 1);
			if($L.isUINT(config.total)){
				this.set('total',config.total);
			}

			if (frame) {
				frame.removeClass('default');
				frame.setStyle('width', this.get('totalWidth') + 'px');
			}
			else {
				throw new Error("Could not find frame for carousel: #" + host.get('id') + '>OL');
			}
			this.set('frame', frame);
			this._elementsChangeHandler = this.after('elementsChange', this._afterElementsChange);
			if (config.elements) {
				this.set('elements', config.elements);
			}
		},
		advance: function () {
			var page    = this.get('page'),
			    pages   = this.get('pages'),
				newPage = page + 1;
			
			if (newPage >= pages && this.get('infinite')) {
				// TODO: implement infinite scrolling
			}
			else if (newPage >= pages) {
				page = 1;
			}
			this.set('page', newPage);
		},
		rewind: function () {
			var page = this.get('page');
			
			if (page === 1 && this.get('infinite')) {
				// TODO: implement infinite scrolling
			}
			else if (page === 1) {
				page = this.get('pages');
			}
			this.set('page', page - 1);
		},
		_setElements: function (value, name) {
			// create a dupe of the elements array (don't allow direct manipulation)
			var elements         = Y.Array.map(value, $L.K),
				numberOfElements = elements.length,
				perPage          = this.get('perPage');
			
			// constrain the carousel to full pages
			elements.length = Math.floor(numberOfElements / perPage) * perPage;
			return elements;
		},
		_render: function (init, value, index, arr) {
			var perPage = this.get('perPage'),
			    page    = Math.floor(index / perPage) + 1;
			
			return init + this.get('renderer')(value, index, page, perPage, this.get('module'));
		},
		// re-render the UI after elements have changed.
		_afterElementsChange: function (event) {
			var elements  = event.newVal,
				count     = (this.get('elements').length === 0 && this.get('total') > 0) ? this.get('total') : elements.length,
				frame     = this.get('frame'),
				pageWidth = this.get('pageWidth'),
				h         = "";
			
			if (elements.length && $L.isFunction(this.get('renderer'))) {
				h = Y.Array.reduce(event.newVal, "", this._render, this);
			}
			
			frame.setStyle('width', (pageWidth * count) + 'px');
			frame.setContent(h);
			this.set('page', 1);
		},
		_setPage: function (value, name) {
			var page     = $L.toInt(value),
				pages    = this.get('pages'),
				infinite = this.get('infinite'),
				target;
			
			// clean up values
			if (page < 1 && infinite) {
				// TODO: implement infinite scrolling
			}
			else if (page < 1) {
				page = 1;
			}
			if (page > pages && infinite) {
				
			}
			else if (page > pages) {
				page = pages;
			}
			
			// calculate the target left value
			target = -1 * (page - 1) * this.get('pageWidth');
			
			// gogo
			if (Y.Anim) {
				if (this._anim) {
					this._anim.stop();
					this._anim.destroy();
				}
				this._anim = new Y.Anim({
					node: this.get('frame'),
					to: {
						left: target
					},
					easing: Y.Easing.easeBoth
				});
				this._anim.run();
			}
			else {
				this.get('frame').setStyle('left', target + 'px');
			}
		},
		_getPages: function () {
			if(this.get('elements').length === 0 && this.get('total') > 0){
				return Math.floor(this.get('total') / this.get('perPage'));
			}
			return this.get('elements').length / this.get('perPage');
		},
		destructor: function () {
			this._elementsChangeHandler.detach();
		}
	}, {
		NS: 'carousel',
		ATTRS: {
			frame: {
				value: null
			},
			page: {
				value: 1,
				setter: '_setPage'
			},
			pages: {
				getter: '_getPages',
				readOnly: true
			},
			total: {
				value: 0
			},
			perPage: {
				value: 1,
				setter: $L.toInt
			},
			/**
			 * When false, calling advance() on the last page
			 * will rewind to 1; when true, the carousel will
			 * advance (forward) to the first page.
			 */
			infinite: {
				value: false,
				validator: $L.isBoolean
			},
			renderer: {
				value: function (obj, index, page, perPage, module) {
					var comments = obj.comments > 999 ? '999+' : obj.comments.toString(),
						modURL, cModURL, escapedHeadline = $L.escapeHTML(obj.headline);
					
					if (module) {
						modURL = $L.addParamsToURL(obj.url, { module: module });
						cModURL = $L.addParamsToURL(obj.commentsURL, { module: module });
					}
					
					return '<li data-cmsid="' + obj.id + '">' +
						'<div class="thumbnail">' +
							'<a href="' + (module ? modURL + '" name="&amp;lid=' + escapedHeadline + '&amp;lpos=' + index + '_image' : obj.url) + '">' +
								(obj.image ? '<img src="' + obj.image + '" alt="Image: ' + escapedHeadline + '" />' : '') +
								'<span></span>' +
							'</a>' +
						'</div>' +
						'<div class="content">' +
							'<h4 class="title">' +
								(obj.commentsURL ? '<a href="' + (module ? cModURL + '" name="&amp;lid=' + escapedHeadline + '&amp;lpos=' + index + '_comments' : obj.commentsURL) + '" class="comments" title="' + comments + ' comment' + (parseInt(comments, 10) === 1 ? '' : 's') + '">' + comments + '</a>' : '') +
								'<a href="' + (module ? modURL + '" name="&amp;lid=' + escapedHeadline + '&amp;lpos=' + index + '_headline' : obj.url) + '">' +
									obj.headline +
								'</a>' +
							'</h4>' +
							(obj.description ?'<div class="description">' + obj.description + '</div>' : '') +
							(obj.published ? '<div class="published">Published ' + obj.published + '</div>' : '') +
						'</div>' +
					'</li>';
				},
				validator: $L.isFunction
			},
			elements: {
				value: [],
				setter: '_setElements'
			},
			module: {
				value: null,
				validator: $L.isString
			},
			pageWidth: {
				value: 0,
				validator: $L.isUINT
			},
			totalWidth: {
				value: 0,
				validator: $L.isUINT
			}
		}
	});
	
}, "3.1.1", { requires: ['plugin', 'base-build', 'nfl-lang', 'array-extras'], optional: 'anim' });

YUI.add('widget-fold', function (Y) {
	var $L = Y.Lang, FOLD_DISTANCE = 'foldDistance', SRC_NODE_Y = '_wfold_srcNodeY';
	function WFold(config) {
		var fd = config[FOLD_DISTANCE],
			wrappedFoldCheck = function () {
				this._foldCheck();
			};

		if (fd) {
			this.set(FOLD_DISTANCE, fd);
		}
		this._wfold_onScroll = Y.on('scroll', wrappedFoldCheck, window, this);
		this._wfold_onResize = Y.on('resize', wrappedFoldCheck, window, this);
		this._wfold_afterRC  = Y.after(this._removeFoldListeners, this, "renderUI");
	}
	WFold.ATTRS = {
		foldDistance: {
			value: -1,
			validator: $L.isNumber,
			lazyAdd: false
		}
	};
	WFold.prototype = {
		_removeFoldListeners: function () {
			if (this._wfold_onScroll) {
				this._wfold_onScroll.detach();
				this._wfold_onResize.detach();
				this._wfold_afterRC.detach();
				delete this._wfold_onScroll;
				delete this._wfold_onResize;
				delete this._wfold_afterRC;
			}
		},
		_foldCheck: function () {
			var foldDistance = this.get(FOLD_DISTANCE), vBottom;
			
			// if foldDistance is still at its original value do nothing
			if (foldDistance === WFold.ATTRS[FOLD_DISTANCE].value) {
				return;
			}
			// if we don't have a Y value for the srcNode yet, get it.
			if ($L.isUndefined(this[SRC_NODE_Y])) {
				this[SRC_NODE_Y] = this.get('srcNode').getY();
			}
			vBottom = Y.DOM.viewportRegion().bottom;
			// the Y value of the srcNode is less than the foldDistance between
			// call render  
			if (this[SRC_NODE_Y] < vBottom + foldDistance) {
				this._removeFoldListeners();
				this.render();
			}
		},
		destructor: function () {
			this._removeFoldListeners();
		}
	};
	Y.WidgetFold = WFold;
}, "3.1.1", { requires: ['widget']});


YUI.add("nfl-iframe", function (Y) {
	function setHeightToContent(event) {
		this.setStyle('height', this.getInnerHeight() + 'px');
	}
	function getInnerHeight() {
		//console.info('getInnerHeight '+this.get('tagName').toLowerCase(),this);
		
		if (this.get('tagName').toLowerCase() !== 'iframe') {
			return this.get('offsetHeight');
		}
		//console.log('	getting from content document');
		try {
			var _node = Y.Node.getDOMNode(this),
				d = (_node.contentDocument) ? _node.contentDocument : _node.contentWindow.document,
			//	h = (document.all) ? d.body.offsetHeight  : d.body.scrollHeight;
				h = d.body.scrollHeight;
			return h;
		}
		catch (e) {
			console.error('getInnerHeight Error', e);
		}
		//console.log('	getting from height..');
		return this.get('height');
	}

	Y.namespace("NFL").IFrame = Y.Base.create('nfl-iframe', Y.Plugin.Base, [], {
		initializer: function (config) {
			//console.info('initializing Y.NFL.IFrame plug',this.get('host'));
			var host  = this.get('host');
			if (host) {
				this.set('iframeId', host.get('id'));
			}
			if (typeof config.resizeOnLoad !== 'undefined') {
				this.set('resizeOnLoad', config.resizeOnLoad);
			}

			// add new methods to DOM_NODES
			//Y.Node.addMethod('getInnerHeight', getInnerHeight); // returns document height for iframe, height for all other elements
			//Y.Node.addMethod('setHeightToContent', setHeightToContent);  // sets objects height to content height
			
			// add event listeners
			if (this.get('resizeOnLoad') === true) {
				Y.on('domready', this.resizeOnLoad, this);
			}
		},
		convertToDiv: function () {
			//TODO add support for converting iframes to HTMLFragments
			//var href	= this.get('iframe').get('src');
		},
		getInnerHeight: function () {
			//console.info('getInnerHeight '+this.get('tagName').toLowerCase(),this);
			if (this.get('host').get('tagName').toLowerCase() !== 'iframe') {
				return this.get('host').get('offsetHeight');
			}
			try {
				var _node	= Y.Node.getDOMNode(this.get('host')),
					d = (_node.contentDocument) ? _node.contentDocument : _node.contentWindow.document,
					w = (_node.contentWindow)? _node.contentWindow : _node,
					h = (document.all) ? d.body.offsetHeight  : d.body.scrollHeight,
					_oh, _sh;
					try{
						_oh	= d.body.offsetHeight;
						_sh	= d.body.scrollHeight;
						h = (_oh > _sh)? _oh : _sh;
						//h = (document.all) ? Math.round((((h / 100)* 5) + h)) : h ;
						if(typeof d.loaded !== 'undefined'){ if(d.loaded === false){ h = '';} } //this will cause the iframe to try again 2 seconds later
						if(typeof w.loading !== 'undefined'){ if(w.loading === true){ h = '';} }
						//console.log('Y.NFL.IFrame->getInnerHeight: document loaded? '+d.loaded +' | document loading? '+w.loading);
					}catch(e){}
				return h;
			}
			catch (e2) {
				console.error('getInnerHeight Error', e2);
			}
			//console.log('	getting from height..');
			return this.get('host').get('height');
		},
		setHeight: function (h) {
			//alert('iframe setHeight:'+h);
			try{
				this.get('host').setStyle('height', h + 'px');
				//console.log('Y.NFL.IFrame->setHeight '+h);
				return true;
			}catch(e){ console.log('Y.NFL.IFrame->setHeight Error: '+ e.message); return false; }
		},
		setHeightToContent: function (event) {
			//console.log('Y.NFL.IFrame->setHeightToContent');
			var _ih	= this.getInnerHeight();
			//console.log('	inner height: '+_ih+' '+(typeof _ih));
			if(typeof _ih !== 'number'){
				/* try again later */
				//alert('iframes height is not a number, try later');
				setTimeout(Y.bind(this.setHeightToContent,this),500);
				return;
			}
			if(!this.setHeight(_ih)){
				/* try again later */
				setTimeout(Y.bind(this.setHeightToContent,this),500);
			}
		},
		resizeOnLoad: function(){
			//console.log('Y.NFL.IFrame->resizeOnLoad');
			this.setHeightToContent();
		},
		destructor: function () {
		}
	}, {
		NS: 'iframe',
		ATTRS: { iframe: {value: null}, iframeId: {value: null}, isLoaded: {value: false}, resizeOnLoad: {value: true} }
	});
}, "3.1.1", { requires: ['plugin', 'base-build', 'node', 'io']});
YUI.add('nfl-centerpiece', function (Y) {
	var $L            = Y.Lang,
	    SubNavigation = Y.NFL.SubNavigation;
	
	Y.namespace("NFL").Centerpiece = Y.Base.create("nfl-centerpiece", Y.Widget, [], {
		initializer: function (config) {
			if (config.hasOwnProperty('inlineVideo')) {
				this.set('inlineVideo', config.inlineVideo);
			}
			this.set('srcNode',config.srcNode);
			if(typeof config.startOn !== 'undefined'){
				this.set('startOn',config.startOn);
				var li = false;
				if(this.get('startOn') === 'last' || this.get('startOn') === null){
					li = ((this.get('startOn') !== 'last') ? this.get('srcNode').one('.carousel>ol>li') : this.get('srcNode').one('.carousel > ol > li:last-child'));
				}else{
					if(Y.one('#'+this.get('startOn'))){
						li = Y.one('#'+this.get('startOn'));
					}
				}
				this.set('pane',(li ? li.get('id') : ''));
			}
			if(typeof config.direction !== 'undefined'){
				this.set('direction',config.direction);
			}
			if(typeof config.loop !== 'undefined'){
				this.set('loop',config.loop);
			}
			if(typeof config.autoStart !== 'undefined'){
				this.set('autoStart',config.autoStart);
				if(this.get('autoStart') === false){ this.set('idle', false); }
			}
			if(typeof config.syncGeometryOnEvent !== 'undefined'){
				Y.Global.on(config.syncGeometryOnEvent,Y.bind(this.syncGeometry,this));
			}
		},
		syncGeometry: function(){
			try{
				if(this.get('paneWidth') === 0){ 
					this.set('paneWidth', this.get('srcNode').one('.content-box').get('offsetWidth'));
					if(this.get('carousel')){ this.get('carousel').setStyle('width', (this.get('panes') * this.get('paneWidth')) + 'px'); }
				}
				if(this.get('subnavWidth') === 0){ 
					this.set('subnavWidth', (this.get('srcNode').one('.subnav>li') ? this.get('srcNode').one('.subnav>li').get('offsetWidth') : 0));
					var subnav   = this.get('srcNode').one('.subnav');
					if (this.get('panes') === 1 || this.get('panes') === 0) {
						if(subnav){ subnav.setStyle('display', 'none'); }
					}
					else {
						if(subnav){subnav.setStyle('width', (this.get('panes') * this.get('subnavWidth')) + 'px');}
					}
				}
			}catch(e){}
		},
		renderUI: function () {
			var srcNode  = this.get('srcNode'),
			    subnav   = srcNode.one('.subnav'),
				carousel = srcNode.one('.carousel>ol'),
				panes    = this.get('panes');
			
			if (panes === 1 || panes === 0) {
				if(subnav){ subnav.setStyle('display', 'none'); }
			}
			else {
				if(subnav){subnav.setStyle('width', (panes * this.get('subnavWidth')) + 'px');}
			}
			if(carousel){
				carousel.setStyle('width', (panes * this.get('paneWidth')) + 'px');
				this.set('carousel', carousel);
			}
			if (this.get('inlineVideo')) {
				this._videoClass = this.getClassName('video');
			}
		},
		bindUI: function () {
			var srcNode = this.get('srcNode'),
			    sn      = srcNode.one('.subnav');
			if(!sn){return;}
			sn.plug(SubNavigation, { section: this.get('pane') });
			this._sectionChangeHandler = sn.subnav.on('sectionChange', this._onNavigate, this);
			this.set('subnav', sn);
			this._idleTimer = Y.bind(this._onIdleTimer, this);
			this._idleChangeHandler = this.after('idleChange', this._afterIdleChange, this);
			this._subnavClickHandler = sn.on('click', this._onSubnavClick, this);
			this._carouselClickHandler = this.get('srcNode').one('.carousel').on('click', this._onCarouselClick, this);
		},
		syncUI: function () {
			var _s	= (this.get('startOn') === 'last') ?  '>li:last-child' : '>li',
				li;
			if(!this.get('subnav')){ return; }
			li = this.get('subnav').one(_s);
			if(this.get('startOn') !== null && this.get('pane') !== ''){this._gotoPane( this.get('pane') );}
			if (li) {
				li.addClass('current');
			}
			if(this.get('autoStart')){ this.startIdleTimer(); }
		},
		_afterIdleChange: function (event) {
			if (event.newVal) {
				this.startIdleTimer();
				if (! this._subnavClickHandler) {
					this._subnavClickHandler = this.get('srcNode').one('.subnav').on('click', this._onSubnavClick, this);
				}
			}
			else {
				this.stopIdleTimer();
				if (this._subnavClickHandler) {
					this._subnavClickHandler.detach();
				}
			}
		},
		startIdleTimer: function () {
			this.stopIdleTimer();
			if (this.get('idle')) {
				this._to = setTimeout(this._idleTimer, this.get('idleTimer'));
			}
		},
		stopIdleTimer: function () {
			if (this._to) {
				clearTimeout(this._to);
				this._to = null;
			}
		},
		loadVideo: function (id, relatedIds) {
			var player, contentBox, Video = Y.NFL.Video;
			this.get('boundingBox').addClass(this._videoClass);
			contentBox = this.get('contentBox');
			player = new Video.Player({
				srcNode: contentBox.one('div.player'),
				width: contentBox.get('offsetWidth'),
				height: contentBox.get('offsetHeight'),
				size: 'closeable',
				showAkamaiAttribution: false,
				contentId: id,
				autoplay: true,
				playerName: this.get('videoPlayerName'), //"HP_CP_Player",
				related: "byIds",
				relatedValue: relatedIds,
				dartURL: this.get('videoDartURL'),
				adRatio: this.get('videoAdRatio'),
				adSetting: this.get('videoAdSetting')
			});
			player.render();
			// this._playerDestroyHandler = player.on(Video.PlayerEvent.PLAYBACK_COMPLETE, this._onPlayerDestroy, this);
			this._playerCloseHandler = player.on(Video.PlayerEvent.CLOSE, this._onPlayerDestroy, this);
			this.set('player', player);
		},
		_onPlayerDestroy: function (event) {
			//this._playerDestroyHandler.detach();
			this._playerCloseHandler.detach();
			this.get('player').destroy();
			this.set('player', null);
			this.get('boundingBox').removeClass(this._videoClass);
			
			// reset the idle timer
			this.startIdleTimer();
		},
		_onSubnavClick: function (event) {
			// stop the idle timer once the CP has been interacted with
			this.set('idle', false);
		},
		_onCarouselClick: function (event) {
			var t = event.target;
			
			// if the click comes during a transition, ignore it
			if (this._anim && this._anim.get('running')) {
				event.preventDefault();
				return;
			}
			
			// stop the idle timer once the CP has been interacted with
			this.set('idle', false);
			
			// otherwise, do some magic based on the className of the click target
			if (t.get('className') === "video" && this.get('inlineVideo') && t.hasAttribute('data-chronicleId')) {
				this.loadVideo(t.getAttribute('data-chronicleId'), t.getAttribute('data-related'));
				event.preventDefault();
			}
		},
		_onIdleTimer: function () {
			var pane = this.get('pane'), newPane;
			if(!Y.one('#' + pane)){
				newPane = this.get('carousel').one('>li');
			}
			
			if (! newPane && this.get('direction') === 'forward') {
				newPane = pane ? Y.one('#' + pane).next() : false;
			} else {
				//reverse it
				newPane = pane ? Y.one('#' + pane).previous() : false;
			}
			
			// if the next pane doesn't exist, get the first one.
			if (! newPane && this.get('loop')) {
				newPane = this.get('carousel').one('>li');
			}
			// now if the next pane exists, show it.
			if (newPane) {
				this.get('subnav').subnav.set('section', newPane.get('id'));
			}
		},
		_gotoPane: function (pane) {
			var target;
			if (typeof pane === 'undefined' || pane === null) { return; }
			target = this.
				get('carousel').
				all('li').
				indexOf(Y.one('#' + pane)) * -1 * this.get('paneWidth');
			this.get('carousel').setStyle('left',target);
		},
		_onNavigate: function (event) {
			var target;
			// do nothing if the pane has not changed
			if (event.newVal === this.get('pane')) {
				return;
			}
			
			// set the pane to the new section
			this.set('pane', event.newVal);
			this.syncGeometry();
			
			// calcluate the target X
			target = this.
				get('carousel').
				all('li').
				indexOf(Y.one('#' + event.newVal)) * -1 * this.get('paneWidth');

			// update carousel
			if (this._anim) {
				this._anim.stop();
				this._anim.destroy();
			}
			this._anim = new Y.Anim({
				node: this.get('carousel'),
				to: {
					left: target
				},
				easing: Y.Easing.easeBoth
			});
			this._anim.run();
			
			// reset the idle timer
			this.startIdleTimer();
		},
		destructor: function () {
			var player = this.get('player');
			
			if (player) {
				player.destroy();
				this._playerDestroyHandler.detach();
				this._playerCloseHandler.detach();
			}
			this.get('subnav').unplug(SubNavigation);
			this._sectionChangeHandler.detach();
			this._idleChangeHandler.detach();
			this._paneChangeHandler.detach();
			this._carouselClickHandler.detatch();
			if (this._subnavClickHandler) {
				this._subnavClickHandler.detach();
			}
		}
	}, {
		HTML_PARSER: {
			paneWidth: function (srcNode) {
				return srcNode.one('.content-box').get('offsetWidth');
			},
			subnavWidth: function (srcNode) {
				var li = srcNode.one('.subnav>li');
				return li ? li.get('offsetWidth') : 0;
			},
			pane: function (srcNode) {
				var li = srcNode.one('.carousel>ol>li');
				return li ? li.get('id') : '';
			},
			panes: function (srcNode) {
				return srcNode.all('.carousel>ol>li').size();
			}
		},
		ATTRS: {
			startOn: {
				value: null
			},
			direction: {
				value: 'forward'
			},
			loop: {
				value: true,
				validator: $L.isBoolean
			},
			autoStart: {
				value: true,
				validator: $L.isBoolean
			},
			pane: {
				value: '',
				validator: $L.isString
			},
			panes: {
				value: 0,
				validator: $L.isUINT
			},
			paneWidth: {
				value: 0,
				validator: $L.isUINT
			},
			subnavWidth: {
				value: 0,
				validator: $L.isUINT
			},
			subnav: {
				value: null
			},
			carousel: {
				value: null
			},
			idle: {
				value: true,
				validator: $L.isBoolean
			},
			idleTimer: {
				value: 10000,
				validator: $L.isUINT
			},
			inlineVideo: {
				value: false,
				setter: function (value) {
					// if Video is undefined, don't allow playback
					return $L.isUndefined(Y.NFL.Video) ? false : value;
				},
				validator: $L.isBoolean
			},
			player: {
				value: null
			},
			videoPlayerName: {
				value: 'HP_CP_Player',
				setter: $L.toString
			},
			videoDartURL: {
				value: '',
				setter: $L.toString
			},
			videoAdSetting: {
				value: '0',
				setter: $L.toString
			},
			videoAdRatio: {
				value: '0',
				stter: $L.toString
			}
		}
	});
}, "3.1.1", { requires: ['node', 'anim', 'widget', 'base-build', 'nfl-lang', 'nfl-carousel', 'nfl-subnav' ], optional: ['nfl-video'] });


/**
 * Headlines Module
 * /home, /news
 * TODO: Move to separate module after rollup is complete
 */
YUI.add('nfl-headlines', function (Y) {
	var $L = Y.Lang,
		SubNavigation = Y.NFL.SubNavigation,
		YSiteLife = Y.SiteLife;

	function getMostCommentedHTML(init, value, index, array) {
		return init + this._getHTML(value, parseInt(value.Comments.NumberOfComments, 10), "Comment", index);
	}

	function getMostLikedHTML(init, value, index, array) {
		return init + this._getHTML(value, parseInt(value.Recommendations.NumberOfRecommendations, 10), "Like", index);
	}
	
	function sortByMostLiked(a, b) {
		return parseInt(b.Recommendations.NumberOfRecommendations, 10) -  parseInt(a.Recommendations.NumberOfRecommendations, 10);
	}
	function sortByMostCommented(a, b) {
		return parseInt(b.Comments.NumberOfComments, 10) -  parseInt(a.Comments.NumberOfComments, 10);
	}
	
	Y.namespace("NFL").Headlines = Y.Base.create('nfl-headlines', Y.Widget, [], {
		initializer: function (config) {
			if (config.template) {
				this.set('template', config.template);
			}
			if (config.module) {
				this.set('module', config.module);
			}
			if (config.maxCount) {
				this.set('maxCount', config.maxCount);
			}
			
			this._getMostCommentedHTML = Y.bind(getMostCommentedHTML, this);
			this._getMostLikedHTML = Y.bind(getMostLikedHTML, this);
		},
		bindUI: function () {
			var sn = this.get('srcNode').one('.subnav');
			
			sn.plug(SubNavigation, {
				section: this.get('section')
			});
			sn.subnav.on('sectionChange', this._onNavigate, this);
			this.set('subnav', sn);
			this._dataLoadHandler = this.get('srcNode').on('mouseover', this._loadData, this);
		},
		syncUI: function () {
			this.get('srcNode').addClass(this.getClassName('s-' + this.get('section')));
		},
		_onNavigate: function (event) {
			var srcNode = this.get('srcNode');
			srcNode.replaceClass(this.getClassName('s-' + event.prevVal), this.getClassName('s-' + event.newVal));
			this.set('section', event.newVal);
		},
		_loadSiteLifeContent: function (section, options, itemRenderer, sorter) {
			var selector = '#' + this.get('srcNode').get('id') + "-" + section;
			Y.SiteLife.discoverContent(options, function (r) {
				var dca     = Y.SiteLife.find(r, 'DiscoverContentAction');
				if (dca) {
					// fix Pluck boog http://jira.pluck.com/browse/NFL-90
					if (dca.DiscoveredContent.length > options.max) {
						dca.DiscoveredContent.length = options.max;
					}
					Y.one(selector).setContent(Y.Array.reduce(dca.DiscoveredContent.sort(sorter), "", itemRenderer));
				}
			});
		},
		_getHTML: function (obj, count, type, index) {
			var title = YSiteLife.getArticleTitle(obj.PageTitle, false);

			return Y.substitute(this.get('template'), {
				url: $L.addParamsToURL(obj.PageUrl, { module: this.get('module') }),
				title: title,
				escapedTitle: $L.escapeHTML(title),
				count: $L.toPrettyInt(count, this.get('maxCount')),
				plural: count === 1 ? '' : 's',
				type: type,
				index: index
			});
		},
		_loadMostCommented: function (event) {
			this._loadSiteLifeContent("commented", Y.merge(this.get('discoveryConfig'), { activity: "Commented"}), this._getMostCommentedHTML, sortByMostCommented);
			
			// this function should only run once
			this.set('commentedLoaded', true);
			this._loadMostCommented = $L.emptyFunction;
		},
		_loadMostLiked: function (event) {
			this._loadSiteLifeContent("liked", Y.merge(this.get('discoveryConfig'), { activity: "Recommended"}), this._getMostLikedHTML, sortByMostLiked);

			// this function should only run once
			this.set('likedLoaded', true);
			this._loadMostLiked = $L.emptyFunction;
		},
		_loadData: function () {
			this._loadMostCommented();
			this._loadMostLiked();
			this._loadData = function () {};
			this._dataLoadHandler.detach();
			this._dataLoadHandler = null;
		},
		destructor: function () {
			this.get('subnav').unplug(SubNavigation);
			if (this._dataLoadHandler) {
				this._dataLoadHandler.detach();
			}
		}
	}, {
		HTML_PARSER: {
			section: function (srcNode) {
				return srcNode.one('.content').get('id');
			}
		},
		ATTRS: {
			id: {
				value: null,
				validator: $L.isString
			},
			section: {
				value: null,
				validator: $L.isString
			},
			module: {
				value: '',
				validator: $L.isString
			},
			subnav: {
				value: null,
				writeOnce: true
			},
			commentedLoaded: {
				value: false,
				writeOnce: true
			},
			likedLoaded: {
				value: false,
				writeOnce: true
			},
			discoveryConfig: {
				value: {
					age: 2,
					max: 13,
					sections: ['News']
				}
			},
			template: {
				value: '<li><a class="primary" href="{url}" name="&amp;lid={escapedTitle}&amp;lpos={type}_{index}">{title}</a> | {count}</li>',
				validator: $L.isString
			},
			maxCount: {
				value: 99999,
				validator: $L.isUINT
			}
		}
	});
	
}, "3.1.1", { requires: ['array-extras', 'widget', 'node', 'nfl-subnav', 'base-build', 'nfl-lang', 'sitelife', 'substitute'] });

