/*
 * BuzzFeed
 * Author: Phil Harvey
 * Copyright (c) The Lampo Group Inc., all rights reserved.
 * 
 * Requires: Prototype 1.6.0.3, Scriptaculous effects.js 1.8.3
 */

// CONFIGURATION
var BUZZFEED_MAX_VISIBLE = 10;
var BUZZFEED_UPDATE_DELAY = 8;
var BUZZFEED_RETRY_DELAY = 5;
var BUZZFEED_CONTAINER_ID = 'buzzfeed';
var BUZZFEED_AJAX_URL = '?event=getBuzzFeed';

// HELPER FUNCTIONS
get_unix_timestamp = function() {
	return new Date().getTime().toString().substring(0, 10);
};

String.prototype.unEntify = function() {
	var result = this;
	result = result.replace(/&amp;/g, '&');
	result = result.replace(/&quot;/g, '"');
	result = result.replace(/&apos;/g, '\'');
	return result;
}

// HOOKS
Event.observe(window, 'load', function() {
	BuzzFeed.load();
});
var playerPlay = function(clip) {
	BuzzFeed.pause();
};
var playerPause = function(clip) {
	BuzzFeed.resume();
};

// CLASSES
var BuzzFeed = Class.create({
	initialize: function(comments_json) {
		var ul = Builder.node('ul');
		
		this.container = $(BuzzFeed.config.containerId);
		this.container.appendChild(ul);
		this.container.ul = ul;
		
		this.loadJSON(comments_json);
		this.update();
		
		this.periodicalExecuter = new PeriodicalExecuter(this.update.bind(this), BuzzFeed.config.updateDelay);
		this.container.observe('mouseover', this.onMouseOver.bindAsEventListener(this));
		this.container.observe('mouseout', this.onMouseOut.bindAsEventListener(this));
	},
	loadJSON: function(comments_json) {
		this.comments = comments_json;
		this.visible_comments = [];
		this.count = 0;
		
		this.resume();
		
		for(var position = 0; position < BuzzFeed.config.maxVisible && position < this.comments.length; position++) {
			var comment_json = this.comments.pop();
			this.visible_comments.unshift(comment_json);
			
			var comment_id = 'comment_' + (position+1).toString();
			var comment = new Comment(comment_id, comment_json);
			
			// use existing comment node, otherwise create a new comment node
			var li = $(comment_id) || comment.create();
			
			this.container.ul.appendChild(li);
		}
	},
	update: function() {
		// if paused, skip update
		if(this.paused) { return; }
		if(this.count >= this.comments.length) {
			this.pause();
			new Ajax.Request(BuzzFeed.config.ajaxUrl + '&t=' + get_unix_timestamp(), {
				method: 'get',
				requestHeaders: {
					Accept: 'application/json'
				},
				onSuccess: function(transport) {
					var comments = transport.responseText.evalJSON(true);
					BuzzFeed.getInstance().loadJSON(comments);
					BuzzFeed.resume();
				},
				onFailure: function() {
					BuzzFeed.resume();
				}
			});
		}
		
		// cleanup after last animation
		$A(this.container.ul.childNodes).each(function(node) {
			node.setAttribute('style', '');
		});
		
		// rotate comments
		this.visible_comments.unshift(this.comments.pop());
		this.comments.unshift(this.visible_comments.pop());
		
		// pull bottom comment off the list
		var comment_li = this.getBottomComment();
		var comment = new Comment(comment_li.identify(), this.visible_comments[0]);
		
		// update comment
		comment_li = comment.update(comment_li);
		
		// animate comment
		comment.animate(comment_li);
		
		// insert comment onto the top of the list
		var ul = $(this.container.getElementsByTagName('ul')[0]);
		ul.insert({ top: comment_li });
		
		this.count++;
	},
	getBottomComment: function() {
		var li = this.container.select('li')[this.visible_comments.length-1];
		var ul = this.container.select('ul')[0];
		return li;
	},
	onMouseOver: function(event) {
		event.stop();
		if(this.paused) {
			this.wasAlreadyPaused = true;
		}
		this.pause();
	},
	onMouseOut: function(event) {
		event.stop();
		if(!this.wasAlreadyPaused) {
			this.resume();
		}
	},
	pause: function() {
		this.paused = true;
	},
	resume: function() {
		this.paused = false;
		this.wasAlreadyPaused = false;
	}
});
Object.extend(BuzzFeed, {
	getInstance: function() {
		if(window.buzzfeed) {
			return window.buzzfeed;
		}
		BuzzFeed.error('was not initialized');
		return null;
	},
	load: function() {
		try {
			if(BUZZFEED_COMMENTS_JSON) {
				var comments = BUZZFEED_COMMENTS_JSON;
				window.buzzfeed = new BuzzFeed(comments);
			} else {
				new Ajax.Request(BuzzFeed.config.ajaxUrl + '&t=' + get_unix_timestamp(), {
					method: 'get',
					requestHeaders: {
						Accept: 'application/json'
					},
					onSuccess: function(transport) {
						var comments = transport.responseText.evalJSON(true);
						window.buzzfeed = new BuzzFeed(comments);
					},
					onFailure: function(transport) {
						try {
							BuzzFeed.pause();
							// try again later
							BuzzFeed.load().delay(BuzzFeed.config.retryDelay);
						} catch(ex) {
							// fail gracefully
						}
					}
				});
			}
		} catch(ex) {
			// just eat it and fail gracefully
		}
	},
	error: function(s) {
		/*
		var message = 'BuzzFeed error: ' + s.toString();
		if(console && console.log && console.trace) {
			console.trace();
			console.log(message);
		} else {
			alert(message);
		}*/
	},
	pause: function() {
		if(window.buzzfeed) {
			BuzzFeed.getInstance().pause();
		}
	},
	resume: function() {
		if(window.buzzfeed) {
			BuzzFeed.getInstance().resume();
		}
	},
	config: {
		maxVisible: BUZZFEED_MAX_VISIBLE,
		updateDelay: BUZZFEED_UPDATE_DELAY,
		retryDelay: BUZZFEED_RETRY_DELAY,
		containerId: BUZZFEED_CONTAINER_ID,
		ajaxUrl: BUZZFEED_AJAX_URL
	}
});

var Comment = Class.create({
	initialize: function(id, json) {
		this.id = id;
		this.json = json;
		this.json.body = this.json.comment;
	},
	create: function() {
		var header = Builder.node('div', { className: 'comment_header' });
		var inner_body = Builder.node('div', this.json.body.unEntify());
		var body = Builder.node('div', { className: 'comment_body' }, inner_body);
		
		var name = Builder.node('strong', this.json.name.unEntify());
		var source = Builder.node('a', { target: '_blank' });
		var footer = Builder.node('div', { className: 'comment_footer' }, Builder.node('div', [ name, ' from ', source]));
		
		var comment = Builder.node('div', { className: 'comment_outer_wrapper' }, [ Builder.node('div', { className: 'comment_wrapper' }, [ header, body, footer ]) ]);
		var li = Builder.node('li', { id: this.id, className: 'comment' }, comment);
		
		// store references to nodes for later (used when updating comment content)
		li.content_parts = {
			body: $(inner_body),
			name: $(name),
			source: $(source)
		};
		return this.update(li);
	},
	update: function(li) {
		if(!li.content_parts) {
			BuzzFeed.error('content_parts is missing from li: #' + li.identify());
		} else {
			li.content_parts.body.update(this.json.body.unEntify());
			li.content_parts.name.update(this.json.name.unEntify());
			li.content_parts.source.setAttribute('href', this.json.source.url);
			li.content_parts.source.update(this.json.source.name);
		}
		
		return li;
	},
	animate: function(li) {
		new Effect.SlideDown(li.identify(), {
			beforeStart: function(effect) {
				var li = effect.element;
				li.setOpacity('0');
				li.hide();
				var ul = $(li.parentNode);
				li = ul.removeChild(li);
				ul.insert(li);
			},
			afterFinish: function(effect) {
				var li = effect.element;
				new Effect.Appear(li.identify(), {
					afterFinish: function(effect) {
						// clean up animation
						effect.element.setAttribute('style', '');
					}
				});
			},
			transition: Prototype.Browser.IE ? Effect.Transitions.full : Effect.Transitions.sinoidal,
			duration: 2
		});
	}
});