/*
 * PledgeFeed
 * 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 PLEDGEFEED_MAX_VISIBLE = 14;
var PLEDGEFEED_UPDATE_DELAY = 3;
var PLEDGEFEED_RETRY_DELAY = 5;
var PLEDGEFEED_UPDATE_COUNT_DELAY = 30;
var PLEDGEFEED_CONTAINER_ID = 'pledgefeed';
var PLEDGEFEED_AJAX_URL = '?event=getPledges';

// HELPER FUNCTIONS
get_unix_timestamp = function() {
	return new Date().getTime().toString().substring(0, 10);
};

function format_count(n)
{
	n += '';
	x = n.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
}

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() {
	PledgeFeed.load();
});
var playerPlay = function(clip) {
	PledgeFeed.pause();
};
var playerPause = function(clip) {
	PledgeFeed.resume();
};

// CLASSES
var PledgeFeed = Class.create({
	initialize: function(pledges_json) {
	/*
		var ul = Builder.node('ul');
		var h1 = Builder.node('h1', format_count(pledges_json.pledge_count.toString()));
		var top_p = Builder.node('p', 'Since April 23rd');
		var bottom_p = Builder.node('p', ['people have refused to participate', Builder.node('br'), 'in the recession!']);
		var div = Builder.node('div', [top_p, h1, bottom_p]);
		var counter = Builder.node('div', { id: 'pledge_count' }, div);
	*/	

		var top_p = Builder.node('p', 'These Americans chose');
		var bottom_p = Builder.node('p', 'and you can too!');
		var h1 = Builder.node('h1', 'HOPE');
		var ul = Builder.node('ul');
		var div = Builder.node('div', [top_p, h1, bottom_p]);
		var counter = Builder.node('div', { id: 'pledge_count' }, div);
		
		this.container = $(PledgeFeed.config.containerId);
		this.container.appendChild(counter);
		this.container.counter = counter;
		this.container.counter.h1 = h1;
		this.container.appendChild(ul);
		this.container.ul = ul;
		
		this.pledge_count = pledges_json.pledge_count;
		
		this.loadJSON(pledges_json);
		this.update();
		
		this.periodicalExecuter = new PeriodicalExecuter(this.update.bind(this), PledgeFeed.config.updateDelay);
		//this.countUpdater = new PeriodicalExecuter(this.updateCount.bind(this), PledgeFeed.config.updateCountDelay);
		this.container.observe('mouseover', this.onMouseOver.bindAsEventListener(this));
		this.container.observe('mouseout', this.onMouseOut.bindAsEventListener(this));
		
		$('pledge_submit_button').observe('click', this.onPledgeSubmit.bindAsEventListener(this));
	},
	onPledgeSubmit: function(event) {
		event.stop();
		var fields = $('pledge_form').serialize(true);
		var name = fields.pledgeXXname;
		var location = fields.pledgeXXlocation;
		
		var name_error = $('pledgeXXname_error');
		var location_error = $('pledgeXXlocation_error');
		var errors = false;
		
		if(name.strip().length == 0) {
			name_error.update('Please enter a name');
			new Effect.Pulsate(name_error, { pulses: 2, duration: 1 });
			errors = true;
		} else {
			name_error.update('');
		}
		
		if(location == 'NULL') {
			location_error.update('Please choose a location')
			new Effect.Pulsate(location_error, { pulses: 2, duration: 1 });
			errors = true;
		} else {
			location_error.update('');
		}
		
		if(errors) return;
		
		PledgeFeed.insertPledge(name, location);
		
		function getFirstName(name) {
			return /^[a-zA-Z]+/.exec(name);
		}
		
		var div = $('take_action_header');
		div.select('h1')[0].update('Thank You #{name}!'.interpolate({name:getFirstName(name)}));
		
		div.select('form')[0].hide();
		$('pledge_tell_a_friend').show();
		var request = new Ajax.Request('?event=savePledge', {
			method: 'post',
			parameters: fields
		});
	},
	updateCount: function() {
		var request = new Ajax.Request('?event=getPledgeCount', {
			method: 'get',
			onSuccess: function(transport) {
				var count = parseInt(transport.responseText.strip(), 10);
				if(!isNaN(count) && count > this.pledge_count) {
					//this.displayCount(count);
					this.pledge_count = count;
				}
			}.bind(this)
		});
	},
	displayCount: function(count) {
		if(this.pledged) count++;
		this.container.counter.h1.update(format_count(count));
	},
	insertPledge: function(name, location) {
		this.pledges.push({name: name, location: location, highlight: true});
		this.pledged = true;
		//this.displayCount(this.pledge_count);
	},
	loadJSON: function(pledges_json) {
		this.pledges = pledges_json.pledges;
		this.visible_pledges = [];
		this.count = 0;
		
		this.resume();
		
		for(var position = 0; position < PledgeFeed.config.maxVisible && position < this.pledges.length; position++) {
			var pledge_json = this.pledges.pop();
			this.visible_pledges.unshift(pledge_json);
			
			var pledge_id = 'pledge_' + (position+1).toString();
			var pledge = new Pledge(pledge_id, pledge_json);
			
			// use existing pledge node, otherwise create a new pledge node
			var li = $(pledge_id) || pledge.create();
			
			this.container.ul.appendChild(li);
		}
	},
	update: function() {
		// if paused, skip update
		if(this.paused) { return; }
		if(this.count >= this.pledges.length) {
			this.pause();
			var request = new Ajax.Request(PledgeFeed.config.ajaxUrl + '&t=' + get_unix_timestamp(), {
				method: 'get',
				requestHeaders: {
					Accept: 'application/json'
				},
				onSuccess: function(transport) {
					var pledges = transport.responseText.evalJSON(true);
					PledgeFeed.getInstance().loadJSON(pledges);
					PledgeFeed.resume();
				},
				onFailure: function() {
					PledgeFeed.resume();
				}
			});
		}
		
		// cleanup after last animation
		$A(this.container.ul.childNodes).each(function(node) {
			node.setAttribute('style', '');
		});
		
		// rotate pledges
		this.visible_pledges.unshift(this.pledges.pop());
		this.pledges.unshift(this.visible_pledges.pop());
		
		// pull bottom pledge off the list
		var pledge_li = this.getBottomPledge();
		var pledge = new Pledge(pledge_li.identify(), this.visible_pledges[0]);
		
		// update pledge
		pledge_li = pledge.update(pledge_li);
		
		// animate pledge
		pledge.animate(pledge_li);
		
		// insert pledge onto the top of the list
		var ul = $(this.container.getElementsByTagName('ul')[0]);
		ul.insert({ top: pledge_li });
		
		this.count++;
	},
	getBottomPledge: function() {
		var li = $A(this.container.select('li')).last();
		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(PledgeFeed, {
	getInstance: function() {
		if(window.pledgefeed) {
			return window.pledgefeed;
		}
		PledgeFeed.error('was not initialized');
		return null;
	},
	load: function() {
		try {
			if(PLEDGEFEED_JSON) {
				var pledges = PLEDGEFEED_JSON;
				window.pledgefeed = new PledgeFeed(pledges);
			} else {
				var request = new Ajax.Request(PledgeFeed.config.ajaxUrl + '&t=' + get_unix_timestamp(), {
					method: 'get',
					requestHeaders: {
						Accept: 'application/json'
					},
					onSuccess: function(transport) {
						var pledges = transport.responseText.evalJSON(true);
						window.pledgefeed = new PledgeFeed(pledges);
					},
					onFailure: function(transport) {
						try {
							PledgeFeed.pause();
							// try again later
							PledgeFeed.load().delay(PledgeFeed.config.retryDelay);
						} catch(ex) {
							// fail silently
						}
					}
				});
			}
		} catch(ex) {
			// fail silently
		}
	},
	error: function(s) {
		/*
		var message = 'PledgeFeed error: ' + s.toString();
		if(console && console.log && console.trace) {
			console.trace();
			console.log(message);
		} else {
			alert(message);
		}
		*/
	},
	pause: function() {
		if(window.pledgefeed) {
			PledgeFeed.getInstance().pause();
		}
	},
	resume: function() {
		if(window.pledgefeed) {
			PledgeFeed.getInstance().resume();
		}
	},
	insertPledge: function(name, location) {
		if(window.pledgefeed) {
			PledgeFeed.getInstance().insertPledge(name, location);
		}
	},
	config: {
		maxVisible: PLEDGEFEED_MAX_VISIBLE,
		updateDelay: PLEDGEFEED_UPDATE_DELAY,
		updateCountDelay: PLEDGEFEED_UPDATE_COUNT_DELAY,
		retryDelay: PLEDGEFEED_RETRY_DELAY,
		containerId: PLEDGEFEED_CONTAINER_ID,
		ajaxUrl: PLEDGEFEED_AJAX_URL
	}
});

var Pledge = Class.create({
	initialize: function(id, json) {
		this.id = id;
		this.json = json;
	},
	create: function() {
		var name = Builder.node('div', { className: 'pledge_name' }, this.json.name.unEntify());
		var location = Builder.node('span', { className: 'pledge_location' }, this.json.location.unEntify());
		var statement = Builder.node('div', { className: 'pledge_statement' }, ['from ', location, ' chooses Hope!']);
		var wrapper = Builder.node('div', { className: 'pledge_wrapper' }, [name, statement]);
		var li = Builder.node('li', { id: this.id, className: 'pledge' }, wrapper);
		
		// store references to nodes for later (used when updating pledge content)
		li.content_parts = {
			name: $(name),
			location: $(location),
			statement: $(statement)
		};
		return this.update(li);
	},
	update: function(li) {
		if(!li.content_parts) {
			PledgeFeed.error('content_parts is missing from li: #' + li.identify());
		} else {
			li.content_parts.name.update(this.json.name.unEntify());
			li.content_parts.location.update(this.json.location);
		}
		if(this.json.highlight) {
			li.setAttribute('class', 'pledge pledge_highlighted');
		} else {
			li.setAttribute('class', 'pledge');
		}
		return li;
	},
	animate: function(li) {
		var animation = 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;
				var animation = 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
		});
	}
});