/*
 *
 * Nathan Reed, 29/04/2010
 */

var Ui = {
	init: function() {
		this.current_ptr = {'count':0};

		this.counter = null;
		this.timers = [];
		this.target_list = [
			{'target': 0, 'remaining':0, 'element':'cd-tweet-timer-1'},
			{'target': 0, 'remaining':0, 'element':'cd-tweet-timer-2'},
			{'target': 0, 'remaining':0, 'element':'cd-tweet-timer-3'},
			{'target': 0, 'remaining':0, 'element':'cd-tweet-timer-4'}
		];

		this.show_timers();

		this.counter = this.default_counter();

		// now we need to add the timers. Calculate the targets
		// we are going to round to, then display the timer.
		var base_magnitude = 10000000;
		var cur_magnitude = base_magnitude;
		var cur_tweet = _rate_data.tweet_id + _rate_data.age * (1000 / _rate_data.short_rate);

		for(var i=0; i < this.target_list.length; i++) {
			var target_element = this.target_list[i].element;
			var target_tweet = this.generate_target(cur_tweet, cur_magnitude);

			if(target_tweet == this.generate_target(cur_tweet, cur_magnitude*10)) {
				// this target is a duplicate of the next one. Don't display it.
				$(target_element+ '-r').hide();
				cur_magnitude *= 10;
				continue;
			}

			// this will automatically update every second onc started
			var t = new TimerElement(target_element, {
				'current':cur_tweet,
				'target': target_tweet,
				'rate': 1000/((target_tweet - cur_tweet < 20E6) ? _rate_data.short_rate : _rate_data.long_rate)
				,'current_ptr': this.current_ptr
			}).start();

			this.timers.push(t);

			$(target_element+'-t').innerHTML = target_tweet.format();
			cur_magnitude *= 10;
		}

		// automatically reload the count data every so often. It is updated from twitter every
		// 15 minutes
		this.reload.periodical(5*60*1000, this);
	},

	default_counter: function() {
		return new CounterElement('cd-tweet-counter', {
			'rate': 1000 / _rate_data.short_rate,
			'start': _rate_data.tweet_id,
			'age': _rate_data.age,
			'current_ptr': this.current_ptr
		}).start();
	},

	generate_target: function(cur_tweet, magnitude) {
		return Math.ceil(cur_tweet / magnitude) * magnitude;
	},

	toggle_timers: function() {
		var current_state = Cookie.read('show_timers') || '1';

		if(current_state == 0) {
			// timers are hidden, so show them
			Cookie.create('show_timers', '1', 14);
		} else {
			Cookie.create('show_timers', '0', 14);
		}

		Ui.show_timers();
	},

	show_timers: function() {

		if((Cookie.read('show_timers') || '1') == 1) {
			$('cd-st-link').innerHTML = 'hide countdown timers...';
			$('cd-timer-row').show();
		} else {
			$('cd-st-link').innerHTML = 'show countdown timers...';
			$('cd-timer-row').hide();
		}
	},

	reload: function() {
		// use the get-rates.php api to reload the latest rate data from the server
		// this is an improvement from reloading the entire page as previously
		new Request({
			url: 'api/get-rates.php',
			onSuccess: function(responseText) {
				_rate_data = JSON.decode(responseText);
				this.reset();
			}.bind(Ui)
		}).get();
	},

	reset: function() {
		// reset counter to whatever is in _rate_data
		this.counter.stop();
		this.counter = this.default_counter();
	}

}

var TimerElement = new Class({
	initialize: function(e, params) {

		this.element = $(e);
		this.current = params.current.toInt() || 0;
		this.target = params.target.toInt() || 1000;
		this.rate = params.rate.toFloat() || 1;
		this.current_ptr = params.current_ptr;

		this.update();
	},

	start: function() {
		this.update.periodical(1000, this);
		return this;
	},

	update: function() {
		if($defined(this.current_ptr)) {
			// maybe we want to link this timer to a counter getting updated some where else.
			// in this case you can pass in a pointer to an object contianing this. No idea how
			// javascript deals with thread safety, so I will just ignore that issue for now.
			this.current = this.current_ptr.count;
		}

		this.element.innerHTML = longDateStr(this.seconds_remaining());
		this.current += this.rate;

	},

	seconds_remaining: function() {
		return (this.target - this.current) / this.rate;
	}

});

var CounterElement = new Class({

	initialize: function(e, params) {
		this.element = $(e);

		this.start_number = params.start.toInt() || 0;
		this.age = params.age.toInt() || 0;
		this.rate_per_sec = params.rate || 1;
		this.current_ptr = params.current_ptr || {'count':0};

		this.start_time = (new Date().getTime()/ 1000) - this.age;
		this.update_number();
	},

	start: function() {
		var update_delay_ms = 1000 / this.rate_per_sec;
		update_delay_ms = update_delay_ms.limit(70, 60000);

		this.update_display();
		this.timer_id = this.update_display.periodical(update_delay_ms, this);

		return this;
	},

	update_display: function() {
		this.update_number();
		if($defined(this.element)) {
			this.element.innerHTML = this.number.round().format();
		}
	},

	update_number: function() {
		var current_time = new Date().getTime() / 1000;

		this.age = current_time - this.start_time;
		this.number = this.start_number + this.age * this.rate_per_sec;
		this.current_ptr.count = this.number;
	},

	stop: function() {
		$clear(this.timer_id);
	}
});

/* from: http://javascript.internet.com/text-effects/add-commas.html */
window.addEvent('load', Number.implement({ format: function() {
	number = '' + this;
	if (number.length > 3) {
		var mod = number.length % 3;
		var output = (mod > 0 ? (number.substring(0,mod)) : '');
		for (i=0 ; i < Math.floor(number.length / 3); i++) {
			if ((mod == 0) && (i == 0))
				output += number.substring(mod+ 3 * i, mod + 3 * i + 3);
			else
				output+= ',' + number.substring(mod + 3 * i, mod + 3 * i + 3);
		}

		return (output);
	} else {
		return number;
	}
}}));

// gets the long duration string from duration. duration has the number
// or seconds, and longDateStr returns something like 2 days 4 hours 5 minutes
function longDateStr(duration)
{

	var datestr = '';

	// time consts
	var second = 1;
	var minute = second*60;
	var hour = minute*60;
	var day = hour*24;

	var timeconst = {
		len: [day, hour, minute, second],
		name: [" day",":",":",""]
	};

	unitcount = 0; // count of the number of diff units used so far.
	for(i=0; i < timeconst.len.length; i++) {
		if(duration >= timeconst.len[i]) {
			unitcount++;

			curtime = Math.floor(duration/timeconst.len[i]);

			// add a leading zero to the time stuff
			if(timeconst.name[i].length <= 1 && curtime < 10) {
				curtime = ('0'+curtime);
			}

			datestr += (curtime+timeconst.name[i]);
			duration -= (curtime*timeconst.len[i]);

			// does date string need a plural
			if(timeconst.name[i] == " day") {
				if(curtime > 1) {
					datestr += 's ';
				} else {
					datestr += ' ';
				}
			}

		} else {
			if(timeconst.name[i] != " day") {
				datestr += ('00'+timeconst.name[i]);
			}
		}
	}

	return datestr;
}

Element.implement({
	//implement show
	show: function() {
		this.setStyle('display','');
	},
	//implement hide
	hide: function() {
		this.setStyle('display','none');
	}
});


var Cookie = {
	create: function(name,value,days) {
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+value+expires+"; path=/";
	},

	read: function(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	},

	erase: function(name) {
		createCookie(name,"",-1);
	}
}

window.addEvent('load', Ui.init.bind(Ui));
