nfl.namespace('events');
nfl.events.ProfileEvent = {
	ON_USER: "nfl:profile:user"
};
nfl.namespace('community');
nfl.community.profile = (function() {
	var AUTH = nfl.global.Authentication,
    	BM, isTrue, Paginator,
	    AuthenticationEvent     = nfl.events.AuthenticationEvent,
	    ProfileEvent            = nfl.events.ProfileEvent,
	    IS_FRIEND_RESPONSE      = /(?:Self|Pending|Friend|NotFriend)/,
	    RELATIONSHIP            = { SELF: 'Self', PENDING: 'Pending', FRIEND: 'Friend', NONE: 'NotFriend' },
	    HEADLINE_DELIMITER      = '||',
	    TEMPLATE_ATTR           = 'data-template',
	    DELIM_ATTR              = 'data-delim',
	    PROFILE_BASE            = '/registration',
	    PROFILE_PATH            = PROFILE_BASE + '/profile/',
		NO_USER_IMAGE           = /\/images\/no\-user\-image\.gif$/,
		PLUCK_COMMENT_KEY_PARAM = /[\?\&]plckFindCommentKey=CommentKey:[^\&]*/,
		ABUSE_THRESHOLD         = 3,
	    DEFAULT_CUSTOM_ANSWERS  = $H({
			"Greatest NFL memory": "",
			"College": "",
			"Favorite player": "",
			"Read messages": "0"
		}),
		SECTION                 = {
			MESSAGES: '/shout-outs',
			ACTIVITY: '/activity',
			SETTINGS: '/settings',
			EDIT:     '/edit-profile',
			FRIENDS:  '/friends'
		},
	    user, alertEl, alertElOffset, p, isFriend;
	
	function isFriendMessage (_messageObj) {
		return IS_FRIEND_RESPONSE.test(_messageObj.Message);
	}
	
	function lazyLoad () {
		if (Object.isUndefined(BM)) {
			BM        = nfl.sitelife.BatchManager;
			isTrue    = nfl.sitelife.isTrue;
			Paginator = nfl.sitelife.Paginator;
		}
	}
	
	// returns mark-up for a user's avatar unless their behavior warrants otherwise
	function getUserAvatar (_user) {
		return (
			NO_USER_IMAGE.test(_user.AvatarPhotoUrl) ||
			isTrue(_user.CurrentUserHasReportedAbuse) ||
			isTrue(_user.IsBlocked) ||
			(parseInt(_user.AbuseReportCount, 10) > ABUSE_THRESHOLD)
		) ? '' : ('<img src="' + _user.AvatarPhotoUrl + '" alt="" />');
	}
	
	function onPluckUser(_response) {
		var isFriendObj = _response.Messages.find(isFriendMessage);

		user     = BM.find(_response, 'User');
		isFriend = isFriendObj ? isFriendObj.Message : RELATIONSHIP.NONE;
		document.fire(ProfileEvent.ON_USER, { user: user, isMe: isMe(), relationship: isFriend });
	}

	function isMe(_username) {
		var name = _username ?
		    _username : 
			Object.isUndefined(user) ? 
				null :
				user.UserKey.Key;

		if ( ! name ) { return false; }
		return AUTH.isAuthenticated() && name.toLowerCase() === AUTH.getUser().username.toLowerCase();
	}
	
	function slideToAlert () {
		if ( 0 > alertEl.viewportOffset().top ) {
			new Effect.ScrollTo( alertEl );
		}
	}
	
	function updateCurrentUser (_values, _callback) {
		user = BM.updateUserProfile(user, _values, _callback);
	}
	window.ucu = updateCurrentUser;
	p = {
		Activity: (function () {
			var el, ul, template, titleTemplate, toUserId,
			    MESSAGE_TO_RE = /^Message to: ([^\s]*)/;
			
			function getActivityHTML(_acc, _a) {
				var obj, result;
				if ( _a.Comment ) {
					obj    = _a.Comment;
					result = {
						activity: "Comment on",
						content: obj.CommentBody,
						timestamp: obj.PostedAtTime_UTC,
						url: _a.Url.replace(PLUCK_COMMENT_KEY_PARAM, ''),
						name: _a.Title.split( HEADLINE_DELIMITER )[0]
					};
				}
				else if (_a.PersonaMessage) {
					toUserId = _a.Title.match(/^Message to: ([^\s]*)/)[1];
					obj      = _a.PersonaMessage;
					result   = {
						activity: "Shout-out to",
						content: obj.Body,
						timestamp: obj.CreatedOn_UTC,
						url: p.ProfileURL(toUserId),
						name: toUserId
					}
				}
				result.title = titleTemplate.evaluate({
					activity: result.activity,
					name: result.name,
					url: result.url
				});
				result.date = new Date(Date.parse(result.timestamp)).time_ago_in_words();
				return _acc + template.evaluate(result);
			}
			
			function onActivity(_response) {
				var activity = BM.find(_response, 'RecentUserActivity'), activities;

				activities = activity.UserActivities.length === 0 ? 
					"<li>No recent activity.</li>":
					activity.UserActivities.inject('', getActivityHTML);

				if ( activity ) {
					ul.
						update( activities).
						show();
					el.appear();
				}
				
				// clean up references
				el = ul = template = titleTemplate = null;
			}
			
			return function(_el, _user) {
				el            = $(_el);
				ul            = el.down('ul');
				template      = el.down('ul').templatize();
				titleTemplate = new Template(ul.getAttribute('data-title'));
				lazyLoad();
				BM.AddToRequest(new RecentUserActivity( new UserKey(_user)), onActivity);
			};
		}()),
		isMe: isMe,
		GetUser: function(_user) {
			var user = AUTH.getUser();
			
			lazyLoad();
			BM.AddToRequest(new UserKey(_user), onPluckUser);
			if ( user ) {
				BM.AddToRequest(new IsFriend( new UserKey(_user), new UserKey(user.username) ), Prototype.emptyFunction);
			}
		},
		AboutMe: (function () {
			var el, template;
			
			function getElValue (_selector, _value, _show) {
				
				var parent = el.down(_selector);
				
				// if there's no show value, show/hide the parent based on
				// whether the value is not empty. Otherwise, evaluate show.
				if ( (Object.isUndefined(_show) && _value) || ((! Object.isUndefined(_show)) && _show )) {
					parent.show();
					return _value;
				}
				else {
					parent.hide();
					return "";
				}
			}
			
			return function(_el, _user) {
				var el = $(_el), u = _user,
				    template = el.templatize(), obj,
				    faveTeam = "", favePlayer = "",
				    faveCollege = "",
				    teamAbbr = u.ExtendedProfile.ft || '';
				
				//favePlayer  = "Test";
				//faveCollege = "Test";
				about       = u.AboutMe;
				
				if (teamAbbr) {
					faveTeam = nfl.data.TEAMS.get(teamAbbr);
				}
				
				obj         = $H({
					location: u.Location || '',
					team: teamAbbr.blank() ? '' : '<a href="' + faveTeam.teamPage + '">'+ faveTeam.fullName() + '</a>',
				//	player: favePlayer,
				//	college: faveCollege,
					age: u.Age || '',
					about: about.replace(/\n+/, "<br><br>"),
					memory: u.CustomAnswers["Greatest NFL memory"]
				});
				el.update( template.evaluate(obj) ).show();
			};
		}()),
		Alert: function(_message) {
			alertEl.
				setStyle({ visibility: 'visible' }).
				down('span.message').update(_message);
			
			alertEl.blindDown({ afterFinish: slideToAlert });
			
		},
		AlertEl: function(_el) {
			alertEl       = $(_el);
			alertElOffset = alertEl.cumulativeOffset();
			alertEl.
				blindUp({ duration: 0 }).
				down('div.close a').
					observe('click', function(_e) {
						if ( Object.isUndefined(alertEl) ) { return; }
						alertEl.blindUp();
						_e.stop();
					});
			/*
			if ( Object.isUndefined(alertEl)) {
				Event.observe(window, 'unload', function(_e) { alertEl = null; });
			}
			*/
		},
		Buzz: (function(){
			var el, TEAMS, ft, select, team = "", template, news, videos,
			    videosTemplate, newsTemplate, linksTemplate,
			    linksDelim, data, game, widgets,
			    TOP_10_URL = "/ajax/community/toptenvideos",
			    TEAM_PARAM = "teamAbbr",
			    CHANNEL_LABELS = $H({ satelliteTv: 'DirecTV', network: 'TV', radioSatellite: 'Sirius' }),
			    GC_TABS = {
					PRE: $H({ "Preview": "/preview", "Analyze": "/analyze", "Discuss": "/discuss" }),
					ACTIVE: $H({ "Track": "/track", "Analyze": "/analyze", "Discuss": "/discuss" }),
					POST: $H({ "Recap": "/recap", "Box Score": "/analyze/box-score", "Watch": "/watch" })
			    };

			function getChannelLabels (_pair) {
				var dataValue = this[_pair.key];
				return dataValue.blank() ? null : _pair.value + ": " + dataValue;
			}
			function compileNewsHTML(_acc, _article) {
				_article.Comments.Plural = parseInt(_article.Comments.NumberOfComments, 10).pluralEnding();
				_article.title = _article.PageTitle.split(HEADLINE_DELIMITER)[0];
				return _acc + newsTemplate.evaluate(_article);
			}
			function compileVideoHTML (_acc, _video ) {
				return _acc + videosTemplate.evaluate(_video);
			}
			function compileGCLink (_pair) {
				this.tabPath = _pair.value;
				this.tabName = _pair.key;
				return linksTemplate.evaluate(this);
			}
			function render () {
				widgets.update(template.evaluate(data));
				// remove these items so sibling selectors work.
				if ( data.get('newsItems').blank() ) { $(news).remove(); }
				if ( data.get('videoItems').blank() ) { $(videos).remove(); }
				if ( Object.isUndefined(data.get('gameId')) ) { $(game).remove(); }
				if ( team.blank() ) { el.down('p.subhead').remove(); }
				el.show();
			}
			
			function onChooseTeam (_e) {
				var value = $F(select);
				if ( _e.type === 'submit' ) { _e.stop(); }
				if ( team === value ) { return; }
				team = value;
				getData();
			}
			function sortOnCommentCount (a, b) {
				return b.Comments.NumberOfComments - a.Comments.NumberOfComments;
			}
			function onDiscoveredContent (_resp) {
				var dca, dc, result;
	
				dca = BM.find(_resp, 'DiscoverContentAction');
				if ( dca ) {
					dc     = dca.DiscoveredContent;
					dc.sort(sortOnCommentCount);
					result = dc.inject("", compileNewsHTML);
				}
				else {
					result = "";
				}
				data.set('newsItems', result);

				// if we don't have video data yet, return.
				if ( Object.isUndefined(data.get('videoItems')) ) { return; }
				render();
			}
			function onAjaxContent (_transport) {
				var json = _transport.responseJSON, game = json.gameSchedule,
				    channelsArray = [], awayTeam, homeTeam, teamInfo = json.teamInfo,
				    profileTeam = nfl.data.TEAMS.get(team);
				
				
				data = data.merge(
					team.blank() ? 
					{
						team: "NFL",
						teamNewsURL: "/news",
						teamVideosURL: "/videos"
					} :
					{
						team: profileTeam.nickname,
						teamURL: profileTeam.teamPage,
						teamSiteURL: profileTeam.url,
						ticketsURL: teamInfo.ticketSiteUrl,
						nflShopTeamId: teamInfo.nflShopTeamId,
						alertsURL: teamInfo.alertUrl,
						teamNewsURL: "/search/?query=" + encodeURIComponent(profileTeam.fullName()) + "&sortBy=date",
						teamVideosURL: "/videos/" + profileTeam.videoChannelName(),
						teamScheduleURL: "/teams/" + teamInfo.linkname + "/schedule?team=" + json.team,
						channels: CHANNEL_LABELS.map(getChannelLabels, game).compact().join(', ')
					}
				);
				
				data.set('videoItems', json.videos.inject("", compileVideoHTML));
				
				if ( ! Object.isUndefined(game.gameId) ) {
					data.set('gameId', game.gameId + "");

					awayTeam = nfl.data.TEAMS.get(game.visitorTeamAbbr);
					data.set('gameScheduleAwayNick', awayTeam.shortNick());
					data.set('gameScheduleAwayAbbr', awayTeam.abbr);
					game.awayLCNick = awayTeam.nickname.toLowerCase();
					
					homeTeam = nfl.data.TEAMS.get(game.homeTeamAbbr);
					data.set('gameScheduleHomeNick', homeTeam.shortNick());
					data.set('gameScheduleHomeAbbr', homeTeam.abbr);
					game.homeLCNick = homeTeam.nickname.toLowerCase();

					data.set('gameDate', new Date(game.gameDateTime).toAPStyle(true));
					data.set('linksContent', GC_TABS[game.gameState].map(compileGCLink, game).join(linksDelim));
				}
				// if we don't have Pluck data yet, return.
				if ( Object.isUndefined(data.get('newsItems')) ) { return; }
				render();
			}
			function onNoAjaxContent (_transport) {
				data = data.merge({
					team: "NFL",
					teamNewsURL: "/news",
					teamVideosURL: "/videos",
					videoItems: ""
				});
				// if we don't have Pluck data yet, return.
				if ( Object.isUndefined(data.get('newsItems')) ) { return; }
				render();
			}
			function getData () {
				var categories = [ 'All' ], parameters = {};
				if ( ! team.blank() ) {
					categories[0] = parameters[TEAM_PARAM] = team;
				}

				el.hide();
				el.className = team;
				data = new Hash();
				
				new Ajax.Request(TOP_10_URL, {
					parameters: parameters,
					method: 'get',
					onSuccess: onAjaxContent,
					onFailure: onNoAjaxContent
				});
				lazyLoad();
				BM.discoverContent({ activity: "Commented", categories: categories, age: 1 }, onDiscoveredContent);
			}
			function optionFromTeam (_acc, _team) {
				return _acc + '<option value="' + _team.abbr + '">' + _team.fullName() + '</option>';
			}
			return function(_config) {
				var linksContainer, teamsArray;

				el      = $(_config.el);
				widgets = el.down('div.widgets');
				ft      = team = _config.team;
				TEAMS   = nfl.data.TEAMS;
				news    = _config.news;
				videos  = _config.videos;
				game    = _config.game;
				
				teamsArray = nfl.data.TEAMS.values();
				teamsArray.sort(nfl.data.ProfileTeam.SORT_BY_FULLNAME);
				
				select  = el.
					down('form').
						observe('submit', onChooseTeam).
						down('select').
						insert( teamsArray.inject("", optionFromTeam)).
						observe('blur', onChooseTeam).
						observe('change', onChooseTeam);
				if ( ft.blank() ) {
					select.selectedIndex = 0;
				}
				else {
					select.value = ft;
				}
				
				// this dies in IE7 when using the back button, but
				// doesn't seem to cause any trouble. 
				try {
					newsTemplate   = new Template($(news).down('ol.item-list').getAttribute(TEMPLATE_ATTR));
					videosTemplate = new Template($(videos).down('ol.item-list').getAttribute(TEMPLATE_ATTR));
					linksContainer = $(game).down('p.links');
					linksTemplate  = new Template(linksContainer.getAttribute(TEMPLATE_ATTR));
					linksDelim     = linksContainer.getAttribute(DELIM_ATTR);
					template       = widgets.templatize();

					widgets.show();
					Event.observe(window, 'unload', function(_e) { el = select = null;});
					getData();
				}
				catch(e) {
					if (! Prototype.Browser.IE) { nfl.log(e.message); }
				}
			};
		}()),
		DisplayingUpdater: Class.create({
			element: function() {
				return $(this.el);
			},
			initialize: function(_el) {
				var el        = $(_el);
				this.el       = el.identify();
				this.template = el.templatize();
			},
			update: function(_opts) {
				var displaying = this.element(),
				    page       = parseInt(_opts.page, 10),
				    perPage    = parseInt(_opts.perPage, 10),
				    total      = parseInt(_opts.total, 10),
				    min        = (page - 1) * perPage + 1,
				    max        = min + perPage - 1;
				
				if ( total === 0 ) { displaying.hide(); }
				else {
					if ( max > total ) { max = total; }

					displaying.update( this.template.evaluate({
						min: min,
						max: max,
						total: total
					})).show();
				}
			}
		}),
		EditAvatar: (function() {
			var el, avatarEl, form, lightBox, iframe, errorRE = /error/;
			    iFrameStates = { CLOSED: -1, OPEN: 0, SUBMITTED: 1 }, iframeState = iFrameStates.CLOSED;
			
			function showEditDialog (_e) {
				if (_e) {
					_e.stop()
				}
				resetIframe();
				lightBox.setStyle({ height: (document.height || document.body.offsetHeight) + 'px' });
				lightBox.show();
			}
			
			function closeEditDialog (_e) {
				if (_e) { _e.stop(); }
				lightBox.hide();
				iframeState = iFrameStates.CLOSED;
			}
			
			function getIframeDoc() {
				return iframe.contentDocument || iframe.contentWindow.document;
			}
						
			function appendStyleSheets(_link) {
				var l = (this.document || this.ownerDocument).createElement('link');
				l.rel = _link.rel;
				l.href = _link.href;
				l.type = _link.type;
				this.appendChild(l);
			}
			
			function removeIframeListener () {
				// if the iframe doesn't exist, this should die slowly.
				try {
					Event.stopObserving(getIframeDoc().getElementsByTagName('form')[0], 'submit', onAvatarFormSubmit);
				}
				catch(e){}
			}
			
			function onAvatarFormSubmit(_e) {
				removeIframeListener();
				iframeState = iFrameStates.SUBMITTED;
				iframe.hide();
			}
			
			function resetIframe (_e) {
				var doc = getIframeDoc(), newForm;
				
				if (_e) { _e.stop(); }
				
				removeIframeListener();
				
				// reset the page
				doc.open();
				doc.write("<!DOCTYPE html><html><head><title></title><script>document.domain='nfl.com';</script></head><body></body></html>");
				doc.close();
				
				// add stylesheets
				$$('link[rel=stylesheet]').each(appendStyleSheets, doc.getElementsByTagName('head')[0]);
				
				// add form, this breaks in IE
				try {
					newForm = form.cloneNode(true);
					doc.body.appendChild(newForm);
				}
				catch(e) {
					doc.body.innerHTML += form.outerHTML;
					newForm = doc.body.getElementsByTagName('form')[0];
				}
				Event.observe(newForm, 'submit', onAvatarFormSubmit);
				
				// set iframe state
				iframeState = iFrameStates.OPEN;
				
				success.hide();
				failure.hide();
				iframe.show();
			}
			
			function onIframeLoad(_e) {
				var body = getIframeDoc().body;
				body.className = 'community-widget';
				switch ( iframeState ) {
					case iFrameStates.CLOSED:
						break;
					case iFrameStates.SUBMITTED:
						if ( errorRE.test(Element.text(body).strip()) ) {
							failure.show();
						}
						else {
							success.show();
							p.GetUser(AUTH.getUser().username);
							s_analytics.trackLinkClick('35', 'Avatar');
						}
						break;
				}
			}
			
			function onUser (_e) {
				var avatar = getUserAvatar(_e.memo.user),
				    img;
				
				avatarEl.select('img').invoke('remove');
				if (avatar.blank()) { return; }
				avatarEl.insert(avatar);
			}
			return function(_el, _lightbox) {
				var blackBox, shim, lbContent;
				
				el        = $(_el);
				avatarEl  = el.down('div.avatar');
				lightBox  = $(_lightbox);
				form      = lightBox.down('form').remove();
				success   = lightBox.down('p.success').hide();
				failure   = lightBox.down('p.failure').hide();
				lbContent = lightBox.down('div.content');
				
				document.body.appendChild(lightBox);
				if ( Prototype.Browser.IE ) {
					lbContent.insert('<iframe src="/widget/blank" frameborder="0" scrolling="no"></iframe>');
				}
				else {
					lbContent.appendChild(document.createElement('iframe'));
				}
				iframe = lbContent.down('iframe');
				iframe.setAttribute('frameborder', '0');
				iframe.setAttribute('scrolling', 'no');
				
				// once it's been added to the DOM, iframe now has a document
				iframe.observe('load', onIframeLoad);
				
				lightBox.down('div.more a').observe('click', closeEditDialog);
				failure.down('a').observe('click', resetIframe);
				
				el.down('a').observe('click', showEditDialog);
				document.observe(ProfileEvent.ON_USER, onUser);
				Event.observe(window, 'unload', function(_e) { el = avatarEl = form = null; });
			};
		}()),
		FriendList: (function () {
			var DEFAULTS = $H({
					OnPage: 1,
					NumberPerPage: 10,
					IsPendingList: false,
					FilterKey: '',
					FilterValue: ''
				});
			
			function onFriends(_response) {
				var fp             = BM.find(_response, 'FriendPage'),
				    friends        = fp.Friends,
				    totalFriends   = parseInt(fp.NumberOfFriends, 10),
				    perPage        = parseInt(fp.NumberPerPage, 10),
				    page           = parseInt(fp.OnPage, 10),
				    totals         = { page: page, perPage: perPage, total: totalFriends },
				    list           = this.list,
				    el             = this.el,
				    pagination     = this.pagination,
				    template       = this.template,
				    noFriends      = this.noFriends;

				// if we're past the number of available pages, go
				// back to the last page.
				if ( friends.length === 0 && page > 1 && totalFriends > 1) {
					new FriendPage(
						p.FriendList.UserKey,
						fp.NumberPerPage,
						pages,
						fp.IsPendingList,
						fp.FilterKey,
						fp.FilterValue
					),
					arguments.callee
				}

				// update list of friends
				list.update((friends.length === 0) ?
					'<li class="no-avatar">' + noFriends + '</li>' :
					friends.inject('', function(_acc, _friend) {
						var className;
						this.i            = this.i + 1;
						className         = this.odd ? 'odd' : 'even';
						this.odd          = ! this.odd;
						if ( this.l === this.i ) {
							className    += ' last';
						}
						_friend.className = className;
						_friend.avatar    = getUserAvatar(_friend);
						return _acc + template.evaluate(_friend);
					}, { odd: true, l: friends.length, i: 0 })
				).show();

				// update displaying
				this.displaying.update(totals);

				// update pagination
				this.pagination.update(totals);
				
				// show the container
				el.show();
			}
			
			return {
				UserKey: '',
				GetFriends: function(_config) {
					var params = _config.args ? DEFAULTS.merge(_config.args) : DEFAULTS;
					
					BM.AddToRequest(
						new FriendPage(
							p.FriendList.UserKey,
							params.get('NumberPerPage'),
							params.get('OnPage'),
							params.get('IsPendingList'),
							params.get('FilterKey'),
							params.get('FilterValue')
						),
						onFriends.bind({
						    list       : $(_config.list),
						    el         : $(_config.el),
						    pagination : _config.pagination,
						    displaying : _config.displaying,
						    template   : _config.template,
						    noFriends  : _config.noFriends
						})
					);
				}
			};
		}()),
		Friends: (function () {
			var el, list, listTemplate,
			    displaying, userId,
			    pageIsMe, pagination;
			
			function getFriends (_page) {
				p.FriendList.GetFriends({
					args:       { OnPage: _page || 1 },
					list:       list,
				    el:         el,
				    pagination: pagination,
				    displaying: displaying,
				    template:   listTemplate,
					noFriends:  (pageIsMe ? 'You have' : userId + ' has') + ' not added any friends.'
				});
			}
			function onPageChange (_page) {
				s_analytics.trackAnotherPageView();
				getFriends(_page);
			}
			
			function onRemoveClick(_e) {
				var userKey, li;
				if ( ! _e.element().up('div').hasClassName('remove') ) { return; }
				_e.stop();
				li      = _e.findElement('li');
				if ( li.hasClassName('removed-friend') ) { return; }
				userKey = li.down('h3').text();
				if (! confirm('Do you really want to remove ' + userKey + ' as a friend?') ) { return; }
				BM.AddToRequest(new RemoveFriendAction(new UserKey(userKey)), function(_response) {
					var message = _response.Messages[0].Message;
					
					if ( 'ok' === message ) {
						li.addClassName('removed-friend');
						s_analytics.trackLinkClick('35', 'Remove Friend_Private');
					}
					else {
						p.Alert('There was a problem removing your friend. Please try again.');
						try { console.log('RemoveFriendAction', userKey,message); } catch(e) {}
					}
				});
			}
						
			return function(_el, _user, _page) {
				el                 = $(_el);
				list               = el.down('ul');
				listTemplate       = list.templatize();
				displaying         = new p.DisplayingUpdater(el.down('p.subhead'));
				pagination         = new Paginator({ el: el.down('div.pagination'), callback: onPageChange });
				userId             = _user;
				pageIsMe           = isMe(_user);

				p.FriendList.UserKey = new UserKey(_user);
				
				if ( isMe(userId) ) {
					list.observe('click', onRemoveClick).addClassName('my-friends-list');
				}
				getFriends();
			};
		}()),
		FriendsSummary: (function () {
			var el, list, listTemplate, more, username;
			
			function getFriendsHTML (_acc, _friend) {
				_friend.avatar = getUserAvatar(_friend);
				return _acc + listTemplate.evaluate(_friend);
			}
			function onFriends (_resp) {
				var fp         = BM.find(_resp, 'FriendPage'), numberOfFriends = parseInt(fp.NumberOfFriends, 10),
				    uk         = fp.UserKey.Key;
				    verbPhrase = isMe(uk) ? 'You have' : uk + ' has';
				
				list.update(
					numberOfFriends === 0 ?
					'<li class="no-avatar">' + verbPhrase + ' not added any friends.</li>' :
					fp.Friends.inject('', getFriendsHTML)
				);

				el.show();
			}
			
			return function(_el, _user) {
				el           = $(_el);
				list         = el.down('ul.item-list');
				listTemplate = list.templatize();
				more         = el.down('div.more a');

				if (isMe(_user)) {
					more.down('span.public').hide();
					more.down('span.private').show();
				}

				list.show();
				BM.AddToRequest(
					new FriendPage( new UserKey( _user ), 5, 1, false, '', '' ),
					onFriends
				);
			};
		}()),
		Header: (function(){
			var el,
			    overview,
			    overviewTemplate,
			    actions,
			    myActions,
			    actionTemplate,
			    reportForm,
			    isBadHeaderLink = /profile\/($|\/)/,
			    comments = 0, recommends = 0, friends = 0,
			    newMessages = 0, requests = 0;
			
			function fixBadHeaderLink(_link) {
				if (! isBadHeaderLink.test(_link.href) ) { return; }
				_link.href = _link.href.replace(isBadHeaderLink, 'profile/' + this.username + '$1');
			}
			
			function onSignIn (_e) {
				if (! isMe()) {
					return onSignOut();
				}

				actions.hide();
				myActions.
					update( actionTemplate.evaluate({
						friend_requests: requests,
						friend_requests_plural: requests.pluralEnding(),
						messages: newMessages,
						messages_plural: newMessages.pluralEnding()
					})).
					show().
					select('a').
						each(fixBadHeaderLink, { username: _e.memo.username });

				el.select('div.navigation li.private').invoke('show');
				if (0 === requests) {
					el.down('div.my-actions div.friends').setStyle({ visibility: 'hidden' });
				}
				if (0 === newMessages) {
					el.down('div.my-actions div.messages').setStyle({ visibility: 'hidden' });
				}
			}
			
			function onSignOut () {
				actions.show();
				myActions.hide();
				el.select('div.navigation li.private').invoke('hide');
			}
			
			function onUser (_e) {
				var m = _e.memo, u = m.user, addFriend;
				if ( ! _e.memo.user ) { return;}
				comments     = parseInt(u.NumberOfComments, 10);
				if ( comments === 4294967295 ) { comments = 0; }
				recommends   = parseInt(u.NumberOfRecommendations, 10);
				friends      = parseInt(u.NumberOfFriends, 10);
				requests     = parseInt(u.NumberOfPendingFriends, 10);
				
				newMessages  = parseInt(u.NumberOfMessages, 10) - parseInt((u.CustomAnswers['Read messages'] || 0), 10);
				
				if (newMessages < 0) { newMessages = 0; }

				if ( isTrue(u.CurrentUserRecommendedProfile) ) {
					actions.down('div.recommend').addClassName('recommended');
				}
				addFriend = actions.down('div.add');

				switch ( m.relationship ) {
					case RELATIONSHIP.NONE:
						addFriend.setStyle({ visibility: 'visible' });
						break;
					case RELATIONSHIP.PENDING:
						addFriend.addClassName('pending');
						addFriend.setStyle({ visibility: 'visible' });
						break;
				}

				el.select('a').each(fixBadHeaderLink, { username: u.ExtendedProfile.u });
				
				overview.
					update( overviewTemplate.evaluate({
						avatar: getUserAvatar(u),
						comments: comments,
						comments_plural: comments.pluralEnding(),
						friends: friends,
						friends_plural: friends.pluralEnding(),
						recommendations: recommends,
						recommendations_plural: recommends.pluralEnding(),
						username: u.DisplayName
					})).
					show();
				
				onSignIn({ memo: { username: u.ExtendedProfile.u, team: u.ExtendedProfile.ft }});
			}
			
			function onAddFriend (_e) {
				// if we're not authenticated, go directly to the login.
				if ( ! AUTH.isAuthenticated() ) { return; }
				// stop the event
				_e.stop();
				// if we have any relationship other than NONE, we're done here.
				if ( isFriend !== RELATIONSHIP.NONE ) { return; }
				_e.findElement('div.add').addClassName('pending');
				s_analytics.trackLinkClick('35', 'Add Friend_Public');
				BM.AddToRequest( new AddFriendAction( new UserKey( user.UserKey.Key )), Prototype.emptyFunction );
				p.Alert('Friend request sent.');
			}
			
			function onRecommend (_e) {
				
				var highFivesEl     = el.down('span.high-fives'),
				    highFivesValue  = highFivesEl.down('span.value'),
				    highFivesPlural = highFivesEl.down('span.plural'),
				    highFives       = parseInt(highFivesValue.innerText || highFivesValue.textContent, 10) + 1,
				    btn             = _e.findElement('div.replaced');

				_e.stop();

				if ( isTrue(user.CurrentUserRecommendedProfile) || btn.hasClassName('recommended') ) { return; }

				highFivesValue.update(highFives);
				highFivesPlural.update(highFives.pluralEnding());
				btn.addClassName('recommended');
				s_analytics.trackLinkClick('35', 'High Five_Public');
				BM.AddToRequest( new RecommendAction( new UserKey( user.UserKey.Key )), Prototype.emptyFunction );
			}
			
			function closeReport(_e) {
				if (_e) { _e.stop(); }

				reportForm.hide();
				reportForm.down('select').selectedIndex = 0;
				reportForm.down('textarea').value = '';
			}
			function onReport (_e) {
				_e.stop();
				reportForm.show();
			}
			function onReportComplete (_reponse) {
				var successful = _reponse.Messages[0].Message === 'ok';
				p.Alert( successful ?
					'Your report has been submitted.' :
					'There was a problem submitting your report. Please try again.'
				);
				if ( successful ) {
					s_analytics.trackLinkClick('35', 'Report Complete');
				}
				
			}
			function onReportSubmit (_e) {
				_e.stop();
				closeReport();
				BM.AddToRequest(
					new ReportAbuseAction( new UserKey( user.UserKey.Key ), $F(reportForm.down('select')), $F(reportForm.down('textarea')).truncateAtLastWord(400) ),
					onReportComplete
				);
			}
			
			function onUnload (_e) {
				el = overview = actions = myActions = null;
			}
			
			return function(_el) {
				el               = $(_el);
				overview         = el.down('div.overview');
				overviewTemplate = overview.templatize();
				actions          = el.down('div.actions');
				myActions        = el.down('div.my-actions');
				actionTemplate   = myActions.templatize();
				reportForm       = el.down('div.report form');
				
				reportForm.setStyle({ display: 'none', right: 0 });
				

				actions.down('div.add a').observe('click', onAddFriend);
				actions.down('div.recommend a').observe('click', onRecommend);
				actions.down('div.report div.link a').observe('click', onReport);
				
				// Prevents IE6 CSS bug
				if (Prototype.Browser.IE && navigator.appVersion.indexOf('MSIE 6.0') !== -1) {
					el.select('div.navigation li').invoke('setStyle', { 'float' : 'left' });
				}
				
				reportForm.observe('submit', onReportSubmit);
				reportForm.down('div.close img').observe('click', closeReport);
				document.observe(ProfileEvent.ON_USER, onUser);
				Event.observe(window, "unload", onUnload);
				document.observe(AuthenticationEvent.SIGN_IN, onSignIn);
				document.observe(AuthenticationEvent.SIGN_OUT, onSignOut);
			};
		}()),
		MessageForm: (function () {
			var c;
			
			function stopEvent (_e) { _e.stop(); }
			
			function onFormSubmit (_e) {
				var form = _e.element();
				_e.stop();
				
				BM.AddToRequest(
					new AddPersonaMessageAction( this.userKey, form.down('textarea').getValue().escapeHTML() ),
					this.onPluck
				);
			}
			
			function onPluckResponse (_response) {
				var firstMessage = _response.Messages[0].Message,
				    textarea     = $(this.form).down('textarea'),
				    message      = $F(textarea);
				
				if (firstMessage !== 'ok') {
					return alert(firstMessage);
				}

				textarea.value = '';
				
				this.onSubmit(this, message);
			}
			
			function onUser(_e) {
				var u = _e.memo.user;
				
				if (
					AUTH.isAuthenticated() &&
					(! isMe(u.UserKey.Key)) && 
					(
						isTrue(u.MessagesOpenToEveryone) ||
						isTrue(u.CurrentUserIsFriend)
					)
				) {
					$(this.form).
						observe('submit', this.onForm).
						show();
					this.onReady();
				}
			}
			
			c = Class.create({

				initialize: function(_config) {
					this.form     = $(_config.form).identify();
					this.userKey  = new UserKey(_config.user);
					this.onForm   = AUTH.isAuthenticated() ? onFormSubmit.bindAsEventListener(this) : stopEvent;
					this.onPluck  = onPluckResponse.bind(this);
					this.onSubmit = _config.onSubmit || c.REDIRECT_TO_MESSAGES;
					this.onReady  = _config.onReady || Prototype.emptyFunction;
					
					document.observe(ProfileEvent.ON_USER, onUser.bindAsEventListener(this));
				}

			});
			c.REDIRECT_TO_MESSAGES = function(_messageForm, _message) {
				window.location = p.ProfileURL(_messageForm.userKey.UserKey.Key, SECTION.MESSAGES);
			};
			
			return c;
		}()),
		MessageList: (function () {
			var DEFAULT_PAGE     = 1,
			    DEFAULT_PER_PAGE = 10,
			    DEFAULT_SORT     = "TimeStampDescending";

			function getMessageHTML (_acc, _message) {
				_message.avatar         = getUserAvatar(_message.FromUser);
				_message.timeAgoInWords = new Date(Date.parse(_message.CreatedOn_UTC)).time_ago_in_words();
				
				return _acc + this.template.evaluate(_message);
			}

			function onMessages (_response) {
				var pmp     = BM.find(_response, 'PersonaMessagePage'),
				    page    = parseInt(pmp.OnPage, 10),
				    perPage = parseInt(pmp.NumberPerPage, 10),
				    total   = parseInt(pmp.NumberOfMessages, 10);
				
				// Check to make sure our options haven't changed.
				// If they have, the user has made another request
				// in the interim--just return.
				if (
					this.options.get('page') !== page ||
					this.options.get('perPage') !== perPage ||
					this.options.get('sort') !== pmp.Sort
				) {
					return;
				}
				
				$(this.el).update(
					total === 0 ?
						'<li class="no-avatar">' + (p.isMe() ? 'You have' : this.userKey.UserKey.Key + ' has') + ' no shout-outs.</li>' :
						pmp.Messages.inject('', getMessageHTML, this)
				).show();

				if (Object.isFunction( this.callback )) {
					this.callback.call(this, pmp);
				}
			}
			
			return Class.create({
				initialize: function(_config) {
					var el           = $(_config.el);
					this.el          = el.identify();
					this.template    = el.templatize();
					this.options     = $H({
						page:          _config.page || DEFAULT_PAGE,
						perPage:       _config.perPage || DEFAULT_PER_PAGE,
						sort:          _config.sort || DEFAULT_SORT
					});
					this.userKey     = new UserKey(_config.user);
					this.callback    = _config.callback || false;
					
					this.onMessages  = onMessages.bind(this);
					this.getMessages();
				},
				getMessages: function(_opts) {
					this.options = this.options.merge(_opts);
					
					BM.AddToRequest(
						new PersonaMessagePage( this.userKey, this.options.get('perPage'), this.options.get('page'), this.options.get('sort') ),
						this.onMessages
					);
				}
			});
		}()),
		MessagesPage: (function () {
			var pagination, displaying, form, list, totalViewed, containerId, initialLoad = true;
			
			
			function onPageChange(_page) {
				s_analytics.trackAnotherPageView();
				list.getMessages({ page: parseInt(_page, 10) });
			}
						
			function onListClick (_e) {
				var target = _e.findElement('a'), li;

				// if we're not on the right element, let the defaults happen
				if ( (! target) || document === target || (! target.up().hasClassName('delete')) ) {
					return;
				}

				// stop the event 
				_e.stop();

				// confirm that they really really want to delete the message.
				if (! confirm('Really delete this message? There is no undo.')) {
					return;
				}
				
				li = target.up('li');
				
				// delete the message
				BM.AddToRequest(
					new RemovePersonaMessageAction(
						new PersonaMessageKey(li.getAttribute('data-key'))
					),
					Prototype.emptyFunction
				);
				updateCurrentUser({ 'Read messages' : (parseInt(user.CustomAnswers['Read messages'], 10) - 1) + '' });

				// fade the li
				new Effect.Opacity(li, { duration: 0.5, to: 0.25 });
			}
			
			function onResults (_pmp) {
				var totals = {
						page: parseInt(_pmp.OnPage, 10),
						perPage: parseInt(_pmp.NumberPerPage, 10),
						total: parseInt(_pmp.NumberOfMessages, 10)
					};
				
				// update displaying
				displaying.update(totals);
				
				// update pagination
				pagination.update(totals);
				
				// if it's not the initial load, scroll to the top.
				if (initialLoad) { initialLoad = false;}
				else { Effect.ScrollTo(containerId); }
				
				// if we are the current user, update their read count
				if (! isMe() ) { return; }
				
				// update total viewed, if necessary.
				if (user && Object.isUndefined(totalViewed)) {
					totalViewed = parseInt(user.CustomAnswers['Read messages'], 10);
				}
				
				// that might result in totalViewed === NaN, so fix it
				if (isNaN(totalViewed)) {
					totalViewed = 0;
				}
				// if totalViewed !== total messages, update the profile
				if (totals.total === totalViewed) { return; }
				
				updateCurrentUser({ 'Read messages' : totals.total + '' });
			}
			
			return function (_config) {
				var listEl = $(_config.list);
				
				pagination = new Paginator({
					el: _config.pagination,
					callback: onPageChange
				});
				displaying = new p.DisplayingUpdater(_config.displaying);
				
				list = new p.MessageList({
					el: listEl,
					user: _config.user,
					callback: onResults,
					displaying: _config.displaying
				});

				form = new p.MessageForm({
					form: _config.form,
					onReady: function() {
						Element.show(_config.formContainer);
					},
					onSubmit: function(_messageForm, _message) {
						list.getMessages();
					},
					user: _config.user
				});
				
				if (isMe(_config.user)) {
					listEl.addClassName('private');
				}
				listEl.observe('click', onListClick);
				containerId = listEl.up('div.col').identify();
			};
		}()),
		MessagesSummary: function(_el, _user) {
			var el = $(_el),
			    id = el.identify(),
			    user = _user,
			    form = new p.MessageForm({
					form: el.down('form'),
					user: _user
				}),
			    list = new p.MessageList({
					el: el.down('ul'),
					user: _user,
					callback: function() {
						$(id).appear();
					},
					perPage: 3
				}),
				more = el.down('div.more');

			if ( isMe(_user) ) {
				more.down('span.public').hide();
				more.down('span.private').show();
			}
			
			more = el = null;
		},
		PendingRequests: (function () {
			var el, list, listTemplate,
			    displaying, pagination;
			
			function getFriends( _page ) {
				p.FriendList.GetFriends({
					args:       { IsPendingList: true, OnPage: _page || 1 },
					list:       list,
				    el:         el,
				    pagination: pagination,
				    displaying: displaying,
				    template:   listTemplate,
					noFriends:  'You have no pending friends.'
				});
			}
			function onLIClick(_e) {
				var btn = _e.element().up('div'), li, userKey, approved;
				
				if (! btn.hasClassName('action-button')) { return; } 
				_e.stop();
				li       = btn.up('li');
				if ( li.hasClassName('accepted-request') || li.hasClassName('ignored-request')) { return; }
				userKey  = li.down('h3').text();
				approved = btn.hasClassName('accept');
				BM.AddToRequest( new ApproveFriendAction( new UserKey(userKey), approved ), function(_response) {
					var message = _response.Messages[0].Message;
					
					if ( 'ok' === message ) {
						li.addClassName((approved ? 'accepted' : 'ignored') + '-request');
						s_analytics.trackLinkClick('35', (approved ? 'Approve' : 'Ignore') + ' Friend Request_Private');
					}
					else {
						p.Alert('There was a problem ' + (approved ? 'approving' : 'ignoring') + ' this request. Please try again.');
						try { console.log('RemoveFriendAction',userKey,message); } catch(e) {}
					}
				});
			}
						
			return function(_el) {
				el                 = $(_el);
				list               = el.down('ul');
				listTemplate       = list.templatize();
				displaying         = new p.DisplayingUpdater(el.down('p.subhead'));
				pagination         = new Paginator({ el: el.down('div.pagination'), callback: getFriends });
				p.FriendList.UserKey = new UserKey(user.UserKey.Key);
				list.observe('click', onLIClick);
				getFriends();
			};
		}()),
		ProfileURL: function(_user, _section) {
			return Object.isUndefined(_section) ?
				PROFILE_PATH + _user :
				(_section === SECTION.EDIT || _section === SECTION.SETTINGS) ? 
					PROFILE_BASE + _section :
					PROFILE_PATH + _user + _section;
		},
		Settings: (function () {
			var form, user, notifications = "IsEmailNotificationsEnabled", messaging = "MessagesOpenToEveryone";
			
			function onPluckUpdate (_resp) {
				p.Alert( _resp.Messages[0].Message === 'ok' ?
					"Your profile has been updated." :
					"There was an error updating your profile."
				);
			}
			
			function onFormSubmit(_e) {
				var results = form.serialize(true);
	
				// don't allow the form to be sent before the user is known.
				if (form.select('input[disabled]').length > 0) { return; }
				
				// fix notifications because checkboxes don't have a default.
				if ( results[notifications] !== 'True' ) {
					results[notifications] = 'False';
				}
				// stop the event
				_e.stop();

				// send the request to Pluck
				updateCurrentUser({
					MessagesOpenToEveryone: results[messaging],
					IsEmailNotificationsEnabled: results[notifications]
				}, onPluckUpdate);
			}
			
			function enableElement (_el) {
				_el.disabled = false;
			}
			
			function onUser(_e) {
				user = _e.memo.user;
				form.elements[notifications].checked = isTrue(user[notifications]);
				form.down('input[name=' + messaging + '][value=' + user[messaging ] + ']').checked = true;
				form.select('input[disabled]').each(enableElement);
			}
			
			return function(_config) {
				form          = $(_config.form);

				form.observe('submit', onFormSubmit);
				document.observe(ProfileEvent.ON_USER, onUser);
			};
		}())
	};
	return p;
}());
nfl.namespace('data');
nfl.data.ProfileTeam = (function () {
	var c = Class.create({
		fullName: function() {
			return this.city + ' ' + this.nickname;
		},
		initialize: function(_obj) {
			for ( var i in _obj ) {
				if ( _obj.hasOwnProperty(i) ) {
					this[i] = _obj[i];
				}
			}
		},
		shortNick: function() { return this.nickname === 'Buccaneers' ? 'Bucs' : this.nickname; },
		videoChannelName: function() {
			return this.fullName().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/\-\-+/g, '-');
		}
	});
	c.SORT_BY_FULLNAME = function(a, b) {
		var fnA = a.fullName(), fnB = b.fullName();
		return fnA > fnB ? 1 :
		       fnA < fnB ? -1 :
		       0;
	};
	return c;
}());
