// Optimization of function from
// http://delete.me.uk/2005/03/iso8601.html
Date.prototype.setISO8601 = function () {
	var REG_EXP = /(\d\d\d\d)(?:\-?(\d\d)(?:\-?(\d\d)(?:[T ](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(?:Z|(?:([\-+])(\d\d)(?::?(\d\d))?)?)?)?)?)?/;
	return function (string) {
		var d, offset, date, time;

		d		= string.match(REG_EXP);
		offset	= 0;
		date	= new Date(d[1], 0, 1);

		if (d[2]) { date.setMonth(d[2] - 1); }
		if (d[3]) { date.setDate(d[3]); }
		if (d[4]) { date.setHours(d[4]); }
		if (d[5]) { date.setMinutes(d[5]); }
		if (d[6]) { date.setSeconds(d[6]); }
		if (d[7]) { date.setMilliseconds(Number("0." + d[7]) * 1000); }
		if (d[8]) {
				offset = (Number(d[9]) * 60) + Number(d[10]);
				offset *= ((d[8] === '-') ? 1 : -1);
		}
		offset -= date.getTimezoneOffset();
		time = Number(date) + (offset * 60 * 1000);
		this.setTime(time);
	};
}();
Date.ISO8601 = function(string) {
	var d = new Date();
	d.setISO8601(string);
	return d;
};
// JS version of Ruby on Rails' distance_of_time_in_words
Date.distance_of_time_in_words = function (from_time, to_time, include_s) {
	var include_seconds, distance_in_minutes, distance_in_seconds;
	include_seconds = include_s || false;
	distance_in_minutes = Math.round(Math.abs(to_time - from_time) / 60000);
	distance_in_seconds = Math.round(Math.abs(to_time - from_time) / 1000);
	if (distance_in_minutes < 2) {
		if (include_seconds) {
			if (distance_in_seconds < 5) { return 'less than 5 seconds'; }
			if (distance_in_seconds < 10) { return 'less than 10 seconds'; }
			if (distance_in_seconds < 20) { return 'less than 20 seconds'; }
			if (distance_in_seconds < 40) { return 'half a minute'; }
			if (distance_in_seconds < 59) { return 'almost a minute'; }
			return '1 minute';
		}
		return (distance_in_minutes === 0) ? 'less than a minute' : '1 minute';
	}
	if (distance_in_minutes < 45) { return distance_in_minutes + ' minutes'; }
	if (distance_in_minutes < 89) { return 'about 1 hour'; }
	if (distance_in_minutes < 1439) { return 'about ' + Math.round(distance_in_minutes / 60) + ' hours'; }
	if (distance_in_minutes < 2879) { return '1 day'; }
	if (distance_in_minutes < 43199) { return Math.round(distance_in_minutes / 1440) + ' days'; }
	if (distance_in_minutes < 86399) { return 'about 1 month'; }
	if (distance_in_minutes < 525599) { return Math.round(distance_in_minutes / 43200) + ' months'; }
	if (distance_in_minutes < 1051199) { return 'about 1 year'; }
	return 'over ' + Math.round(distance_in_minutes / 525600) + ' years';
};
Date.prototype.time_ago_in_words = function (include_seconds) {
	var now, direction;
	now = new Date();
	direction = (now - this > 0) ? ' ago' : ' from now';
	return Date.distance_of_time_in_words(this, now, include_seconds) + direction;
};

nfl.namespace('nfl.global.sitelife.comments');
nfl.global.sitelife.comments = {
	blocked: function(ecm_id) {
		if(nfl.global.sitelife.comments.KillSwitch && typeof nfl.global.sitelife.comments.KillSwitch != 'undefined'){ return true }
		if(nfl.global.sitelife.comments.blockedIds && typeof nfl.global.sitelife.comments.blockedIds != 'undefined'){
			/* checked blocked id's */
			return (typeof nfl.global.sitelife.comments.blockedIds[ecm_id] != 'undefined' && nfl.global.sitelife.comments.blockedIds[ecm_id] == true)?true:false
		}
		return false
	},
	visible: function(ecm_id){
		if(nfl.global.sitelife.comments.KillSwitch && typeof nfl.global.sitelife.comments.KillSwitch !== 'undefined'){ return false }
		if(nfl.global.sitelife.comments.blockedIds && typeof nfl.global.sitelife.comments.blockedIds !== 'undefined'){
			/* checked blocked id's */
			if(typeof nfl.global.sitelife.comments.blockedIds[ecm_id] === 'undefined'){ return true }
			if(nfl.global.sitelife.comments.blockedIds[ecm_id] === 'hidden' || nfl.global.sitelife.comments.blockedIds[ecm_id] === 'true' || nfl.global.sitelife.comments.blockedIds[ecm_id] === true){ return false }
		}
		return true
	},
	locked: function(ecm_id){
		if(nfl.global.sitelife.comments.KillSwitch && typeof nfl.global.sitelife.comments.KillSwitch !== 'undefined'){ return true }
		if(nfl.global.sitelife.comments.blockedIds && typeof nfl.global.sitelife.comments.blockedIds !== 'undefined'){
			/* checked blocked id's */
			if(typeof nfl.global.sitelife.comments.blockedIds[ecm_id] === 'undefined'){ return false }
			if(nfl.global.sitelife.comments.blockedIds[ecm_id] === 'locked'){ return true }
		}
		return false
	}
};

nfl.namespace('news');
nfl.news.SetArticleTime = function (ref) {
	var time_el, date;
	// Change the date to time ago in words
	time_el	= $(ref);
	date = Date.ISO8601(time_el.getAttribute('title'));
	if (! isNaN(date)) {
		time_el.update(date.time_ago_in_words());
	}
};
nfl.news.Paginator = (function() {
	var MAX_PAGES_DISPLAYED = 5,
	    SPREAD              = 2;
	return {
		/**
		 * Creates a range of pages
		 * 
		 * @param Number
		 *            page The current page
		 * @param Number
		 *            pages The total number of pages
		 * @returns Range The range of pages to show
		 */
		getRange: function(page, pages) {
			var start, end;

			start = page - SPREAD;
			if (pages - page < SPREAD && page - SPREAD > 0) {
				start -= SPREAD - (pages - page);
			}
			if (start < 1) { start = 1; }
			
			end = page + SPREAD;
			if (end > pages || pages < MAX_PAGES_DISPLAYED) { end = pages; }
			else if (end < MAX_PAGES_DISPLAYED && pages >= MAX_PAGES_DISPLAYED) {
				end = MAX_PAGES_DISPLAYED;
			}

			return $R(start, end);
		}
	};
})();

/**
 * NFL SiteLife module data models KILL_SWITCH provides a means to remove the
 * SiteLife integration from nfl.com. All implementations of this module should
 * verify its existence via `if (nfl.SiteLife) { doSomething() }`.
 */
nfl.news.Comments = function () {
	// Constants
	var BM, // delay on this one to allow for scripts loading in different orders

	    SITELIFE_URL		= nfl.global.SITELIFE_URL + '/ver1.0/Direct/Process',
	    EVENT_PREFIX		= 'nfl:sitelife:',
	    EVENTS				= ['COMMENT', 'RECOMMEND', 'REPORT', 'META_DATA', 'DISCOVERED_CONTENT'],
	    BEGINS_WITH_SLASH	= /^\// ,
	    IS_BLANK			= /^\s*$/,
	    ESCAPED_DELIMITER	= /#%7B([^%]+)%7D/g,
	    ENCODED_AMPERSANDS	= /\&amp;/g,
	    LESS_THANS          = /</g,
	    ENCODED_LESS_THAN   = '&lt;',
	    ELLIPIS             = "\u2026",
	    DOMAIN				= window.location.protocol + '//' + window.location.host,
	    NO_USER_IMAGE_RE    = /\/images\/no\-user\-image\.gif$/,
	    NO_USER_IMAGE       = nfl.global.imagepath + '/img/community/profile/no-avatar.png',
	    SiteLifeEvent,
	    AuthenticationEvent	= nfl.events.AuthenticationEvent,
	    MAX_COMMENT_LENGTH	= 2000,
	    MAX_ABUSE_REPORTS	  = 2,
	    SORT				= {
	    		DATE_ASC: 'TimeStampAscending',
			DATE_DESC: 'TimeStampDescending',
			RECOMENDED: 'RecommendationsDescending'
	    },
	    current_user		= nfl.global.Authentication.getUser(),
	    CURRENT_USER		= (current_user ? current_user.username : ''),
	    CURRENT_TEAM		= (current_user ? current_user.team : ''),
	    COMMENTS_PER_PAGE	= 10,
	    CLASS_NAME = {
	    	CURRENT: 'current',
			PREVIOUS: 'previous',
			NEXT: 'next',
			REPORT: 'report',
			REPORTED: 'reported',
			RECOMMENDED: 'recommended',
			REPORTING: 'reporting',
			RECOMMEND: 'recommend',
			ABUSIVE: 'abusive',
			PAGE: 'page'
	    },
	    LAST_COMMENT_PREFIX = '-lc-',
	    PROFILE_URL_PREFIX  = '/registration/profile/',
	    HEADLINE_DELIMITER  = '||',
	    ATTR = {
	    	RECOMMENDATIONS: 'data-recommendations',
			COMMENT_KEY: 'data-comment-key'
	    },
	    MESSAGING = {
	    	TOO_LONG: new Template('Your #{type} is #{length} characters long. Please limit your #{type} to ' + MAX_COMMENT_LENGTH + ' characters.'),
			BLANK: new Template('Please enter a #{type}.'),
			ABUSIVE: new Template('Comment is abusive and has been removed.')
	    },
	    PLUCK_COMMENT_KEY_PARAM = /[\?\&]plckFindCommentKey=CommentKey:[^\&]*/,
	    IE_HREF_REGEXP = new RegExp(
	    	'href="' +
			window.location.protocol +
			'//' +
			window.location.host +
			window.location.pathname +
			'#\{'
	    ),
	    IE_HREF_REPLACE = 'href="#{',
	    KILL_SWITCH			= false; // Removes the SiteLife module if true
	try{ KILL_SWITCH		= (nfl.global.sitelife.comments.KillSwitch && typeof nfl.global.sitelife.comments.KillSwitch != 'undefined')?nfl.global.sitelife.comments.KillSwitch:KILL_SWITCH; }catch(e){}
	
	// Private Methods, common across application

	/* Methods for conveting this section to use BatchManager */
	function requestCommentCount(_contentId) {
		var prefix   = this.prefix,
		    template = this.template;
		
		if ( Object.isUndefined(BM) ) { BM = nfl.sitelife.BatchManager; }
		
		BM.AddToRequest( new ArticleKey(_contentId), function(_response) {
			var article    = BM.findArticlePage(_response, _contentId),
			    noArticle  = Object.isUndefined(article),
			    container  = $(prefix + _contentId),
			    comments   = noArticle ? 0 : parseInt(article.Comments.NumberOfComments, 10),
			    recommends = noArticle ? 0 : parseInt(article.Recommendations.NumberOfRecommendations, 10);

			// since request is asynchronous, we have to check this
			if ( ! container ) { return; }
			container.
				update(template.evaluate({
					comments_count: comments,
					comments_plural: (comments === 1 ? '' : 's'),
					recommendations_count: recommends,
					recommendations_plural: (recommends === 1 ? '' : 's')
				})).
				show();
		});
	}
	/**/



	// Event creation funciton for use with EVENTS#inject
	function create_events (object, evt) {
		var name = EVENT_PREFIX + evt.toLowerCase().replace('_', '');
		object[evt] = name;
		document.observe(name, log_event);
		return object;
	}
	// logs a custom event along with its meme (console safe)
	function log_event (event) {
		nfl.log(event.eventName + ': ' + $H(event.memo).inspect());
	}
	function keyify ( className ) {
		return function( el ) { return new className( el ); };
	}
	function get_comment_from_object(comment) {
		var className, body, classNames = [], avatarUrl;
		body = comment.CommentBody;
		if (comment.CurrentUserHasRecommended === 'True') {
			classNames[classNames.length] = CLASS_NAME.RECOMMENDED;
		}
		if (comment.CurrentUserHasReportedAbuse === 'True') {
			classNames[classNames.length] = CLASS_NAME.REPORTED;
		}
		if (
			parseInt(comment.AbuseReportCount) > MAX_ABUSE_REPORTS ||
			comment.ContentBlockingState === 'BlockedByAdmin' ||
			(comment.Author.IsBlocked === 'True' && comment.Author.DisplayName !== CURRENT_USER)
		) {
			classNames[classNames.length] = CLASS_NAME.ABUSIVE;
			body = MESSAGING.ABUSIVE.evaluate(comment);
		}
		classNames[classNames.length] = comment.Author.UserTier.toLowerCase();
		className	= classNames.join(' ');
		avatarUrl   = comment.Author.AvatarPhotoUrl;

		return {
			avatar: NO_USER_IMAGE_RE.test(avatarUrl) ? NO_USER_IMAGE : avatarUrl,
			author_name: comment.Author.DisplayName,
			author_url: PROFILE_URL_PREFIX + comment.Author.ExtendedProfile.u,
			className: className,
			content: body,
			date: new Date(Date.parse(comment.PostedAtTime_UTC)).time_ago_in_words(),
			key: comment.CommentKey.Key,
			recommendations_count: parseInt(comment.NumberOfRecommendations) || '&nbsp;',
			recommendations_plural: (comment.NumberOfRecommendations == 1)? '' : 's'
		};
	}
	
	function get_comment_from_activity (activity) {
		var comment			= get_comment_from_object(activity.Comment);
		// http:// www.nfl.com/news/story?id=09000d5d80f8347d&template=without-video-with-comments&confirm=true&plckFindCommentKey=CommentKey:b56a1df8-5e0e-4448-ab1b-845a1b6742a4
		comment.url			= activity.Url.replace( PLUCK_COMMENT_KEY_PARAM, '');
		comment.headline	= activity.Title.split( HEADLINE_DELIMITER )[0];
		return comment;
	}
	
	function message_ok (m) { return m.Message === 'ok'; } 
	function message_not_ok (m) { return ! message_ok(m); }
	function get_first_with( property ) {
		return function( response ) { return !! response[property]; }
	}
	
	function logPluckResponse ( response ) {
		console.log('Pluck Response', response);
	}
	
	// Events
	nfl.events.SiteLifeEvent = EVENTS.inject({}, create_events);
	SiteLifeEvent = nfl.events.SiteLifeEvent;

	// Models
	return KILL_SWITCH ? false : {
		// Controllers
		ArticleController: function () {
			var COMPONENT 	  = 'nfl.SiteLife.ArticleController',
			    SORT_TEMPLATE = new Template("#sort:#{sort}/page:#{page}");

			// Private Methods
			function on_comment_submit(event) {
				var request, trimmed_text, comment_text;
				
				event.stop();
				console.log('comment submit', this);
				trimmed_text = comment_text = event.findElement('form').select('textarea').first().value.replace( LESS_THANS, ENCODED_LESS_THAN );
				
				if ( trimmed_text.length > 150 ) {
					trimmed_text = comment_text.truncateAtLastWord( 150 ) + ELLIPIS;
				}
				
				// Don't process the comment if it is too long
				if (comment_text.length > MAX_COMMENT_LENGTH) {
					alert(MESSAGING.TOO_LONG.evaluate({ type: 'comment', length: comment_text.length }));
					return;
				}
				
				// Don't process the comment if it is blank
				if (IS_BLANK.test(comment_text)) {
					alert(MESSAGING.BLANK.evaluate({ type: 'comment' }));
					return;
				}
				var request;
				
				request = new RequestBatch();

				// Create the comment
				request.AddToRequest(
					new CommentAction(new ArticleKey(this.ecm_id), this.url, this.headline, comment_text)
				);
				
				// If we have the section, update the most recent comment as
				// well
				if ( this.section ) {
					request.AddToRequest(
						new UpdateCustomItemAction(
							new CustomItemKey( nfl.global.ENV + LAST_COMMENT_PREFIX + this.section.toLowerCase() ),
							'Last ' + this.section + ' Comment',
							'application/x-www-form-urlencoded',
							'Comment',
							Object.toQueryString({
								u:  this.url,
								h:  this.headline,
								t:  trimmed_text,
								c:  parseInt(this.commentsCount || 0, 10) + 1
							}),
							false
						)
					);
				}
				this.getData( request, false, on_comment );
			}
			function on_comment (response) {
				if (response.Messages[0].Message === 'ok') {
					document.fire(SiteLifeEvent.COMMENT, { component: COMPONENT });
				}
				else {
					alert(response.Messages[0].Message);
				}
			}
			function on_article_page_comment (e) {
				this.trackSuccessfulComment();
				window.location = $(this.comment_form).action;
			}
			function on_comment_page_comment (e) {
				this.trackSuccessfulComment();
				$(this.comment_form).select('textarea').first().value = '';
				e.stop();
			}
			function on_site_life_data (response) {
				logPluckResponse(response);
				if ( this.showingComments ) {
					on_comments_list.call( this, response );
				}
				if ( this.showingMetaData ) {
					on_meta_data.call( this, response );
				}
			}
			function on_comments_list (response) {
				var list, html, comment_page, comments, template, pagination, report,
						page, sort_link, sort_re, pages, page_html, pagination, sort;
				list		= $(this.comments_list);
				if (response.Responses.length === 0) {
					$(this.container).hide();
					list.hide();
					return;
				}
				comment_page = response.Responses.find( get_first_with( 'CommentPage' )).CommentPage;
				template	 = this.comments_template;
				html		 = comment_page.Comments.collect(get_comment_from_object).inject('', function (acc, comment) {
					return acc + template.evaluate(comment);
				});

				if (! html) {
					return this.onNoComments();
				}
				// get the report form out of the way so it isn't blown away
				report = $(this.report_form);
				if (report && report.parentNode.nodeName.toLowerCase() === 'li') {
					report.hide();
					list.parentNode.appendChild(report);
				}
				
				list.update(html);

				// Update the object with comments count
				this.commentsCount         = comment_page.NumberOfComments;
				
				// Create Pagination
				if ( this.pagination ) {
					page_html	= '';
					pagination	= $(this.pagination);
					page		= parseInt(comment_page.OnPage, 10);
					pages		= Math.ceil(comment_page.NumberOfComments / comment_page.NumberPerPage);
					sort		= comment_page.Sort;
	
					template	= this.page_template;
	
					if (pages > 1) {
						if (page > 1) {
							page_html += template.evaluate({ className: CLASS_NAME.PREVIOUS, pageURL: SORT_TEMPLATE.evaluate({ sort: sort, page: page - 1 }), pageName: 'Previous'});
						}
						nfl.news.Paginator.getRange(page, pages).each(function (current) {
							var className = CLASS_NAME.PAGE;
							if (current == page) { className += (' ' + CLASS_NAME.CURRENT);}
							page_html += template.evaluate({ className: className, pageURL: SORT_TEMPLATE.evaluate({ sort: sort, page: current }), pageName: current});
						});
						if (page < pages) {
							page_html += template.evaluate({ className: CLASS_NAME.NEXT, pageURL: SORT_TEMPLATE.evaluate({ sort: sort, page: page + 1 }), pageName: 'Next'});
						}
						pagination.update(page_html);
						pagination.show();
					}
					else {
						pagination.hide();
					}
				}
				if ( this.sort_div ) {
					sort_re		= new RegExp("#[^\?\/]*sort:" + sort);
					sort_link	= $(this.sort_div).childElements().find(function(a) { return sort_re.test(a.href); });
					sort_link.addClassName(CLASS_NAME.CURRENT);
					sort_link.siblings().invoke('removeClassName', CLASS_NAME.CURRENT);
				}
				list.show();

				show_container.call(this);
			}
			
			/**
			 * returns an iterator that returns true if the iterated list of
			 * categories contains a member whose name is not in the supplied
			 * list of strings.
			 */  
			function hasACategoryNotIn(_categories) {
				return function(_cat) {
					return ! _categories.include(_cat.Name.toLowerCase());
				};
			}
			
			function on_meta_data (response) {
				var article, responses, secondRequest, memo, articleResponse;
				
				responses = response.Responses;
				
				articleResponse = responses.find(get_first_with('Article'));

				if ( articleResponse ) {
					article = articleResponse.Article;
				}

				if (
					! responses ||
					! article ||
					article.PageUrl !== this.url ||
					article.PageTitle !== this.headline ||
					( this.section && ! article.Section ) ||
					( this.section && article.Section.Name.toLowerCase() !== this.section.toLowerCase() ) ||
					( (! this.section) && article.Section ) ||
					( this.categories.length !== article.Categories.length ) ||
					article.Categories.any(hasACategoryNotIn(this.categories))
				) {

					// Update article metadata if it is missing
					console.log('Forced to make section request, article details changed.');
					console.log.apply( console, ['old'].concat( article ? [ article.PageUrl, article.PageTitle, article.Section, article.Categories ] : [ undefined ] ) );
					console.log('new', this.url, this.headline, this.section, this.categories );
					
					secondRequest = new RequestBatch();
					secondRequest.AddToRequest(
						new UpdateArticleAction(
							this.key,
							this.url,
							this.headline,
							(this.section ? new Section(this.section) : null),
							this.categories.map( keyify(Category) )
						)
					);
					secondRequest.BeginRequest(SITELIFE_URL, logPluckResponse);
				}

				if ( article ) {
					this.current_user_has_recommended = article.Recommendations.CurrentUserHasRecommended === 'True';
					memo = {
						comments_count:			article.Comments.NumberOfComments || 0,
						recommendations_count:	article.Recommendations.NumberOfRecommendations || 0
					};
				}
				else {
					this.current_user_has_recommended = false;
					memo = {
						comments_count:			0,
						recommendations_count:	0
					};
				}
				memo.comments_plural		= memo.comments_count == 1 ? '' : 's';
				memo.recommendations_plural	= memo.recommendations_count == 1 ? '' : 's';
				
				document.fire(SiteLifeEvent.META_DATA, memo);
			}

			function on_sign_in (e) {
				var signed_in;
				$(this.comment_form).select('textarea').first().disabled = false;
				if (this.signed_in_messaging) {
					signed_in = $(this.signed_in_messaging);
					signed_in.update(this.signed_in_template.evaluate(e.memo));
					signed_in.show();
				}
				if (this.signed_out_messaging) {
					$(this.signed_out_messaging).hide();
				}
			}

			function on_sign_out (e) {
				$(this.comment_form).select('textarea').first().disabled = true;
				if (this.signed_in_messaging) {
					signed_in = $(this.signed_in_messaging);
					signed_in.update('');
					signed_in.hide();
				}
				if (this.signed_out_messaging) {
					$(this.signed_out_messaging).show();
				}
			}
			
			function on_hash_change (e) {
				var params, sort_by, options, page, request, viewport_offset, sorter_top;
				params	= window.location.hashparams.get();
				sort_by	= params.get('sort');
				page	= params.get('page');
				if (this.allow_recommendations && params.get('recommend')) {
					on_recommend_article.call(this, e);
				}
				if (this.comments_list && sort_by && page) {
					options = {};
					if (sort_by) {
						options.sort = sort_by;
					}
					options.page = page ? page : 1;
					// Scroll up to the sorter if the window is scrolled below
					// it
					viewport_offset	= document.viewport.getScrollOffsets();
					sorter_top		= $(this.sort_div).viewportOffset().top;
					if (sorter_top < 10) {
						window.scroll(viewport_offset.left, viewport_offset.top + sorter_top - 10);
					}
					this.showComments(options);
				}
			}

			function on_recommend_article(e) {
				if (this.current_user_has_recommended) return;
				request = new RequestBatch();
				request.AddToRequest(new RecommendAction(this.key));
				request.AddToRequest(this.key);
				request.BeginRequest(SITELIFE_URL, on_article_recommended.bind(this));
			}
			
			function on_article_recommended (response) {
				logPluckResponse(response);
				var messages = response.Messages;
				if (messages.all(message_ok)) {
					on_meta_data.call(this, response);
				}
				else  {
					alert(messages.find(message_not_ok));
				}
			}

			function on_comment_click (e) {
				var el, li;
				el	= e.element();
				li	= e.findElement('li');
				if (! li) { return;}
				if (el.hasClassName(CLASS_NAME.RECOMMEND) || el.up().hasClassName(CLASS_NAME.RECOMMEND)) {
					return on_recommend_comment.call(this, e);
				}
				if (el.hasClassName(CLASS_NAME.REPORT)) {
					return on_toggle_report_form.call(this, e);
				}
			}
			
			function on_recommend_comment(e) {
				var el, li, key;

				e.stop();
				el	= e.element();
				if (el.nodeName !== 'EM') {
					el = el.select('em').first();
				}
				li	= el.up('li');
				if (li.hasClassName(CLASS_NAME.RECOMMENDED)) { return;}
				key = li.getAttribute(ATTR.COMMENT_KEY);
				li.addClassName(CLASS_NAME.RECOMMENDED);
				request = new RequestBatch();
				request.AddToRequest(new RecommendAction(new CommentKey(key)));
				request.BeginRequest(SITELIFE_URL, function (response) {
					logPluckResponse(response);
					var recommendations, current_recommendations;
					if (response.Messages[0].Message === 'ok') {
						li.addClassName(CLASS_NAME.RECOMMENDED);
						current_recommendations = parseInt(li.getAttribute(ATTR.RECOMMENDATIONS));
						if (isNaN(current_recommendations)) { current_recommendations = 0; }
						recommendations	= current_recommendations + 1;
						li.setAttribute(ATTR.RECOMMENDATIONS, recommendations);
						el.innerHTML	= recommendations;
					}
					else {
						alert(response.Messages[0].Message);
					}
					el = li = null;
				});
			}
			
			function is_being_reported( _li ) {
				return _li.hasClassName( CLASS_NAME.REPORTING );
			}
			
			// Shows/hides the report form on the appropriate comment
			function on_toggle_report_form (e) {
				var el, report, li, dimensions, size, list, oldLi;
				el			= e.element();
				li			= e.findElement('li');
				report		= $(this.report_form);
				list		= $(this.comments_list);
				// If the clicked LI has been reported already
				if (li && li.hasClassName(CLASS_NAME.REPORTED)) {
					// If it's not hidden, hide it
					if ( report.visible() ) { report.hide(); }
					return;
				}
				// Otherwise position the report to the LI
				else if (li && ! li.hasClassName( CLASS_NAME.REPORTING ) ) {
					li.appendChild(report);
					dimensions	= li.positionedOffset();
					report.setStyle({ top: '100%', right: '0', position: 'absolute' });
					report.select('select').first().selectedIndex = 0;
					report.select('textarea').first().value = '';
					report.select('input').first().value = li.getAttribute(ATTR.COMMENT_KEY);
					report.show();
					
					li.addClassName(CLASS_NAME.REPORTING);

					oldLi = li.siblings().find(is_being_reported);
					if ( oldLi) {
						oldLi.removeClassName(CLASS_NAME.REPORTING);
					}
				}
				// If not, just hide the form
				else {
					list.select('li.' + CLASS_NAME.REPORTING).invoke('removeClassName', CLASS_NAME.REPORTING);
					report.hide();
				}
				e.stop();
			}
			
			// Sends the comment report
			function on_report_comment (e) {
				e.stop();
				var form, data, key, list;
				form	= this.report_form;
				data	= $(form).serialize(true);
				key		= data.reportThisKey;
				list	= this.comments_list;
				if (data.abuseDescription.length > 3000) {
					alert(MESSAGING.TOO_LONG.evalutate({ type: 'description', length: data.abuseDescription.length }));
					return;
				}
				request = new RequestBatch();
				request.AddToRequest(new ReportAbuseAction(new CommentKey(key), data.abuseReason, data.abuseDescription));
				request.BeginRequest(SITELIFE_URL, function (response) {
					logPluckResponse(response);
					if (response.Messages[0].Message === 'ok') {
						var li = $(list).select('li[' + ATTR.COMMENT_KEY + '=' + key + ']').first();
						$(form).hide();
						li.addClassName(CLASS_NAME.REPORTED);
						li.removeClassName(CLASS_NAME.REPORTING);
					}
					else {
						alert(response.Messages[0].Message);
					}
				});
			}
			
			function show_first_page(e) { this.showComments({ sort: SORT.DATE_DESC, page: 1 }) }
			
			function on_sort (e) {
				var el = e.findAlement('a');
				if (! el) { return;}
				show_sort(el);
			}
			function show_sort (ref) {
				var el = $(ref);
				el.addClassName(CLASS_NAME.CURRENT);
				el.siblings().invoke('removeClassName', CLASS_NAME.CURRENT);
			}
			function show_container() {
				Element.show(this.container);
			}
			function stop_observing_metadata( _f ) {
				document.stopObserving( SiteLifeEvent.META_DATA, _f );
			}
			
			function has_submitted_comment( _request ) {
				return !! _request.CommentAction;
			}
			
			return Class.create({
				initialize: function (options) {
					console.log('ArticleController#initialize()', options);
					var date, time_el, signed_in_messaging, params;

					this.options	= options;
					
					this.ecm_id		= options.ecm_id;
					if (options.headline) {
						this.headline	= options.headline.strip();
					}
					this.url		= DOMAIN + options.url.replace(ENCODED_AMPERSANDS, '&');
					this.key		= new ArticleKey(this.ecm_id);
					params			= window.location.hashparams.get() || new Hash();
					this.sort		= params.get('sort') || SORT.DATE_DESC;
					this.page		= params.get('page') || 1;
					if ( options.section) {
						this.section   = options.section;
						this.trackLast = options.trackLast || false;
					}
					this.categories = options.categories ? $A(options.categories).invoke('toLowerCase') : [];

					if ( options.onNoComments ) {
						this.onNoComments = options.onNoComments;
					}

					if (options.signed_in_messaging) {
						signed_in_messaging			= $(options.signed_in_messaging);
						this.signed_in_messaging	= signed_in_messaging.identify();
						this.signed_in_template		= signed_in_messaging.templatize();
					}
					if (options.signed_out_messaging) {
						this.signed_out_messaging = $(options.signed_out_messaging).identify();
					}
					
					this._onHashChange = on_hash_change.bindAsEventListener(this);
					// Listen for a state changes via the hash
					document.observe('window:hashchange', this._onHashChange );
				},
				onNoComments: function() {
					$(this.container).hide();
				},
				showComments: function (options) {
					console.log('ArticleController#showComments()', options);
					var page, sort, list, report, container, pagination, toggle,
					    report, reportHeight, containerBottom;
					if (typeof options == 'undefined') { options = {}; }
					if (options.list) {
						list					= $(options.list);
						container				= $(options.container);
						this.container			= container.identify();
						this.comments_list		= list.identify();
						this.comments_template	= list.templatize();
						try {
							this.sort_div		= container.select('div.sort').first().identify();
						}
						catch(e) { console.log('sorry, no sorting.') }
						this.perPage            = options.perPage || COMMENTS_PER_PAGE;
						
						if (options.pagination) {
							pagination			= $(options.pagination);
							this.pagination		= pagination.identify();
							this.page_template	= pagination.templatize();
						}
						
						if (options.report_form) {
							report				= $(options.report_form);
							this.report_form	= report.identify();

							if ( options.padReportForm ) {
								reportHeight       = $(this.report_form).getHeight();
								containerBottom    = parseInt(container.getStyle('paddingBottom'));
								container.setStyle({ paddingBottom: ((containerBottom > reportHeight) ? containerBottom : reportHeight) + 'px' });
							}
							
							report.observe('submit', on_report_comment.bind(this));
							report.hide();
							report.select('div.close img').first().observe('click', on_toggle_report_form.bind(this));
						}

						container.hide();
						list.observe('click', on_comment_click.bind(this));
					}

					this.sort = options.sort ? options.sort : this.sort;
					this.page = options.page ? options.page : this.page;

					this.showingComments = true;

					/*
					 * // When a comment is posted, refresh comment list with //
					 * current options this._showFirstPage =
					 * show_first_page.bindAsEventListener(this);
					 * document.observe( SiteLifeEvent.COMMENT,
					 * this._showFirstPage );
					 */
					if ( options.batchRequests ) {
						console.log('batching comments requests');
						return; 
					}
					// backwards compatibility
					this.getData();
				},
				
				// Comment totals are used as
				showMetaData: function (el) {
					try {
					console.log('ArticleController#showMetaData()', el);
					var element, template, id, listener;
					element		= $(el);
					template	= element.templatize();
					id			= element.identify();
					element		= null;
					listener    = function (e) {
						var el = $(id);
						if(el){
							el.update(template.evaluate(e.memo));
							el.show();
						}
					};
					this._metaDataObservers[this._metaDataObservers.length] = listener;
					document.observe(SiteLifeEvent.META_DATA, listener);
					this.showingMetaData = true;
					}
					catch(e) { console.log('error!', e); }
				},
				showingComments: false,
				showingMetaData: true,
				_metaDataObservers: [],
				_onComment: Prototype.emptyFunction,
				_onSignIn: Prototype.emptyFunction,
				_onSignOut: Prototype.emptyFunction,
				// _showFirstPage: Prototype.emptyFunction,
				_onSiteLifeData: Prototype.emptyFunction,
				name: 'ArticleController',
				/**
				 * Keeps backwards compatiblity. Do not use.
				 */
				getMetaData: function () { this.getData(); },
				enableComments: function (options) {
					console.log('ArticleController#enableComments()', options);
					var listener, form;
					
					form				= $(options.comment_form);
					form.show();
					this._onComment		= ((options.is_comment_page) ? on_comment_page_comment : on_article_page_comment).bind(this);
					this.comment_form	= form.identify();
					this.trackingName   = options.trackingName;
					document.observe( SiteLifeEvent.COMMENT, this._onComment );
					form.observe('submit', on_comment_submit.bind(this));
					if ( CURRENT_USER ) {
						on_sign_in.call(this, { memo: { username: CURRENT_USER, team: CURRENT_TEAM } });
					}
					this._onSignIn  = on_sign_in.bindAsEventListener(this);
					this._onSignOut = on_sign_out.bindAsEventListener(this);
					document.observe( AuthenticationEvent.SIGN_IN, this._onSignIn );
					document.observe( AuthenticationEvent.SIGN_OUT, this._onSignOut );
				},
				enableRecommendations: function () {
					console.log('ArticleController#enableRecommendations()');
					this.allow_recommendations = true;
				},
				getData: function( _request, _batch, _callBack ) {
					console.log('ArticleController#getData()');
					var onSiteLifeData, request;
					if ( (! this._onSiteLifeData) || this._onSiteLifeData === Prototype.emptyFunction ) {
						this._onSiteLifeData = on_site_life_data.bind(this);
					}

					request        = _request || new RequestBatch();
					onSiteLifeData = this._onSiteLifeData;
					if ( _request && _request.Requests.any( has_submitted_comment ) ) {
						this.sort = SORT.DATE_DESC;
						this.page = 1;
					}
					if ( this.showingMetaData ) {
						request.AddToRequest(this.key);
					}
					if ( this.showingComments ) {
						request.AddToRequest(new CommentPage(this.key, this.perPage, this.page, this.sort));
					}
					if ( _batch ) { return request; }
					console.log('getData', $A(arguments), request, this, this._onSiteLifeData );

					request.BeginRequest(
						SITELIFE_URL,
						_callBack ?
							function( _response ) {
								_callBack( _response );
								onSiteLifeData( _response );
							} :
							onSiteLifeData
					);
				},
				trackSuccessfulComment: function() {
					s_analytics.trackLinkClick(35, this.trackingName);
				},
				destroy: function() {
					console.log( this.name + '#destroy()' );
					document.stopObserving( AuthenticationEvent.SIGN_OUT, this._onSignOut );
					document.stopObserving( AuthenticationEvent.SIGN_IN, this._onSignIn );
					document.stopObserving( SiteLifeEvent.COMMENT, this._onComment );
					document.stopObserving( "window:hashchange", this._onHashChange );
					// document.stopObserving( SiteLifeEvent.COMMENT,
					// this._showFirstPage );
					if(this._metaDataObservers !== null){this._metaDataObservers.each( stop_observing_metadata );}			
					for ( var i in this ) {
						this[i] = null;
					}
				}
			})
		}(),
		CountArticleComments: function(_config) {
			_config.ids.each(requestCommentCount, _config );
		},
		EnableRecommendations: (function () {
			var isRecommendLink = /#recommend$/,
			    idAttr          = 'data-id';
			return function(_config) {
				document.observe('click', function(_e) {
					var el = _e.element(), id, parent, newCount;
					console.log('click!', el, 'a' === el.nodeName.toLowerCase(), isRecommendLink.test(el.href))
					// if we're not clicking on a recommend link, nevermind
					if ( ! (el && 'a' === el.nodeName.toLowerCase() && isRecommendLink.test(el.href))) { return; }
					// get the id or return if it doesn't exist
					id = el.getAttribute(idAttr);
					if ( ! ( id && (parent = $(_config.prefix + id)) && el.descendantOf(parent) ) ) {
						console.log( id, parent, parent ? el.descendantOf(parent) : 'no parent with id: "' + _config.prefix + id + '"' );
						return;
					}
					// send the recommendation
					BM.AddToRequest( new RecommendAction( new _config.contentClass( id ) ) );
					// update the view with new data
					newCount = parseInt(el.down(_config.valueSelector).innerHTML, 10) + 1;
					console.log('newCount: ', newCount, 'oldcount', el.down(_config.valueSelector).innerHTML );
					el.update(
						_config.
							template.
							evaluate({
								recommendations_count: newCount,
								recommendations_plural: newCount === 1 ? '' : 's'
							})
					);
					// stop the event
					_e.stop();
				});
			};
		}()),
		RecentActivityController: (function(){
			
			function on_error(message) {
				nfl.log('RecentActivityController error: ' + message);
				var list = $(this.list);
				list.update(this.error_template.evaluate({}));
				list.show();
				
				$(this.container).show();
			}

			function is_comment(user_activity) {
				return user_activity.Comment !== null;
			}

			function has_no_metadata (comment) {
				return (! comment.url || ! comment.headline);
			}
			function add_placeholder_data (comment) {
				comment.url			= '/goto?id=' + comment.commented_on_key;
				comment.headline	= 'An NFL.com article';
			}

			function get_commented_on_keys (comment) {
				return comment.commented_on_key;
			}

			function on_comments(response) {
				var comments, html, errorHandler, request, template, list;
				errorHandler = on_error.bind(this);
				nfl.response = response;

				if (response.Messages[0].Message !== 'ok') {
					return errorHandler(response.Messages[0].Message);
				}
				comments = response.Responses[0].RecentUserActivity.UserActivities.select(is_comment).collect(get_comment_from_activity);

				if (comments.length === 0) {
					return errorHandler('no comments available');
				}
				list		= this.list;

				// Add placeholders for comments that didn't get any metadata
				comments.findAll(has_no_metadata).each(add_placeholder_data);

				// Generate HTML & update the container
				list	= $(this.list);
				template	= this.template;
				
				list.update(comments.inject('', function (acc, comment) { return acc + template.evaluate(comment);}));
				list.show();
				
				// show container
				$(this.container).show();
			}

			return Class.create({
				initialize: function (options) {
					this.username		= options.username;
					this.list			= options.list;
					this.template		= $(options.list).templatize();
					this.error_template	= $(options.error_message).up().templatize();
					this.container		= options.container;
					this.section		= options.section; // does not look
															// like this is used
															// anywhere.
					this.key			= new UserKey(this.username);
				},
				getRecentActivity: function ( _request, _batch ) {
					var request = _request || new RequestBatch();
					request.AddToRequest(new RecentUserActivity(this.key));

					if ( _batch ) { return request; }

					request.BeginRequest(SITELIFE_URL, on_comments.bind(this));
				}
			});
		})(),
		
		TrackRegistrations: (function () {
			var article, AE, registration_re, type;

			function on_sign_out(e) {
				document.observe('click', on_registration_click);
			}
			function on_sign_in (argument) {
				document.stopObserving('click', on_registration_click);
			}
			function on_registration_click (e) {
				var s_analytics, a = e.findElement('a');
				if (! (a && registration_re.test(a.href))) { return;}

				// Do special Omniture Stuff.
				s_analytics = s_gi(s_account);
				s.tl(a, 'o', 'Pluck: Register from ' + type );
			}
			
			registration_re	= /\/registration\/register/;
			AE				= nfl.events.AuthenticationEvent;

			return function ( _type ) {
				type = _type || 'Article';
				
				document.observe(AE.SIGN_IN,  on_sign_in);
				document.observe(AE.SIGN_OUT, on_sign_out);
				on_sign_out();
			}
		})(),
		MostActivityController: (function () {
			var DEFAULT_MAX        = 10;
			var DEFAULT_AGE        = 15;
			var DEFAULT_SECTIONS   = [ 'All' ];
			var DEFAULT_CATEGORIES = [ 'All' ];
			var DEFAULT_USER_TIERS = [ 'Standard', 'Trusted', 'Featured', 'Editor' ];
			var DEFAULT_ACTIVITIES = [ 'Commented', 'Recommended' ];
			var DEFAULT_CONTENT_TYPE = 'Article';

			function getActivityCleaner(sActivity) {
				switch(sActivity) {
				case 'Commented':
					return function(oArticle) { oArticle.count = oArticle.Comments.NumberOfComments; }
				case 'Recommended':
					return function(oArticle) { oArticle.count = oArticle.Recommendations.NumberOfRecommendations; }
				case 'Rated':
					return function(oArticle) { oArticle.count = oArticle.Ratings.AverageRating; }
				case 'Reviewed':
					return function(oArticle) { oArticle.count = oArticle.Reviews.NumberOfReviews; }
				}
				return Prototype.emptyFunction;
			}
			
			function sortObjectsOnCount(a, b) {
				return b.count - a.count;
			}
			
			function on_results ( response ) {
				logPluckResponse( response );
				this.results = {};
				var i, l, responses = response.Responses, dca, activity;
				for ( i = 0, l = response.Responses.length; i < l; i++ ) {
					if ( responses[i].DiscoverContentAction ) {
						dca      = responses[i].DiscoverContentAction;
						dca.DiscoveredContent.each(getActivityCleaner(dca.Activity.Name));
						dca.DiscoveredContent.sort(sortObjectsOnCount);
						document.fire( SiteLifeEvent.DISCOVERED_CONTENT, dca );
					}
				}
			}
			
			return Class.create({
				initialize: function( options ) {
					if ( ! options ) { options = {}; }
					
					// This list part isn't used, could probably be removed
					var list = $( options.list );
					if ( list ) {
						list.hide();
						this.list        = list.identify();
					}
					// This template part isn't used, could probably be removed
					if ( options.template ) {
						this.template    = $( options.template ).templatize();
					}
					this.sections    = ( options.sections || DEFAULT_SECTIONS ).map( keyify( Section ) );
					this.categories  = ( options.categories || DEFAULT_CATEGORIES ).map( keyify( Category ) );
					this.userTiers   = ( options.userTiers || DEFAULT_USER_TIERS ).map( keyify( UserTier ) );
					this.activities  = ( options.activities || DEFAULT_ACTIVITIES ).map( keyify( Activity ) );
					this.contentType = new ContentType( options.contentType || DEFAULT_CONTENT_TYPE );
					this.age         = options.age || DEFAULT_AGE;
					this.max         = options.max || DEFAULT_MAX;
				},
				find: function( _request, _batch ) {
					var self = this, request = _request || new RequestBatch();
					this.activities.each(function( activity ) {
						request.AddToRequest(
							new DiscoverContentAction( self.sections, self.categories, self.userTiers, activity, self.contentType, self.age, self.max )
						);
					});
					
					if ( _batch ) { return request; }
					request.BeginRequest( SITELIFE_URL, on_results.bind( this ) );
				},
				name: 'nfl.news.Comments.MostActivityController'
			});
		})(),
		LastCommentInSection: (function () {
			
			function onBeforeUnload ( _e ) {
				this.el = null;
			}
			
			function onResults ( _response ) {
				var customItem, commentObject, headlines;

				logPluckResponse( _response );
				
				// Hide this widget if there are no responses
				if ( _response.Responses.length === 0) {
					return this.hide();
				}
				
				customItem    = _response.Responses.find( get_first_with('CustomItem') );
				
				if ( ! customItem ) { return this.hide(); }

				commentObject               = customItem.CustomItem.Content.toQueryParams();
				commentObject.cp            = parseInt( commentObject.c ) === 1 ? '' : 's';
				commentObject.rp            = parseInt( commentObject.r ) === 1 ? '' : 's';
				commentObject.author        = customItem.CustomItem.Author.DisplayName;
				commentObject.author_url    = PROFILE_URL_PREFIX + customItem.CustomItem.Author.ExtendedProfile.u;
				headlines                   = commentObject.h.split( HEADLINE_DELIMITER );
				commentObject.longHeadline  = headlines[0];
				commentObject.shortHeadline = headlines[ ( headlines.length > 1 && headlines[1].length ) ? 1 : 0 ];
				this.customizer( commentObject );
				this.el.update( this.template.evaluate( commentObject ) );
				this.show();
			}
			
			return Class.create({
				initialize: function( _ref, _section, _batch ) {
				
					this.el      = $( _ref );
					this.section = _section;
					if ( ! this.el ) { return console.log('Could not find target element ', _ref); }
					Event.observe( window, 'beforeunload', onBeforeUnload.bind(this) );

					this.template = this.el.templatize();
					console.log('finding!');
					this.find( _batch );
					console.log('made request!');
				},
				find: function( _batch ) {
					
					var request = _batch || new RequestBatch();
					request.AddToRequest( new CustomItemKey( nfl.global.ENV + LAST_COMMENT_PREFIX + this.section.toLowerCase() ) );

					if ( _batch ) { return request; }
					request.BeginRequest( SITELIFE_URL, this.getCallback() );
				},
				getCallback: function() {
					return onResults.bind( this );
				},
				customizer: Prototype.emptyFunction,
				/* Override these methods if show/hide is more complex */
				hide: function() {
					this.el.hide();
				},
				show: function() {
					this.el.show();
				}
			});
		})(),
		GetCommentFromObject: get_comment_from_object
	}
}();
