var tw;
Event.observe(window, 'load', function(){
	var screen_name = $('screen_name').innerHTML;
	tw = new Twitladder(screen_name);
	tw.setFriends();
	tw.setTimeline(screen_name);
	Event.observe(document, 'keydown', function(e){
		switch(/*e.charCode || */e.keyCode){
			case 82:
				tw.setFriends();
				break;
			case 39: case 83:
				tw.next();
				setTimeout(function(){
					tw.scrollFriends();
				}, 500);
				break;
			case 37: case 65:
				tw.previous();
				setTimeout(function(){
					tw.scrollFriends();
				}, 500);
				break;
			case 33: case 38: case 75:
 				tw.scrollUp();
 				break;
 			case 34: case 40: case 74: case 32:
 				tw.scrollDown();
 				break;
			default:
				return true;
		}
		Event.stop(e);
	});
});

var Twitladder = Class.create();
Twitladder.prototype = {
	user: null,
	head: null,
	content: null,
	profile: null,
	users: null,
	direction: null,
	timeline: null,
	timelines: [],
	friends: [],
	current: null,
	positions: [],
	initialize: function(user){
		this.user = user;
		this.head = document.getElementsByTagName('head')[0];
		this.users = $('users');
		this.direction = $('direction');
		this.content = $('content');

		this.profile = $('profile');
		this.profile_tpl = new Template([
			'<a href="http://twitter.com/#{screen_name}" title="Twitter / #{screen_name}">',
			'<img src="#{profile_image_url}" width="48" height="48" alt="#{screen_name}">',
			'</a>',
			'<h3><strong><a href="/user/#{screen_name}">#{screen_name}</a></strong> / #{name}</h3>',
			'<p class="location">#{location}</p>',
			'<p class="url"><a href="#{url}" target="_blank">#{url}</a></p>',
			'<p class="description">#{description}</p>'
		].join(''));

		this.timeline = $('timeline');
	},
	setTimeline: function(user){
		var nodes = this.users.childNodes;
		var friends = this.friends;
		var current = this.current;
		(current && friends.indexOf(current) >= 0) && Element.removeClassName(nodes[friends.indexOf(current)], 'selected');
		(friends.indexOf(user) >= 0) && Element.addClassName(nodes[friends.indexOf(user)], 'selected');
		this.current = user;
		this.positions = [];
		if(this.timelines[user])this.appendTimeline(this.timelines[user]);
		else this.appendScript('http://twitter.com/statuses/user_timeline/' + user + '.json?callback=tw.appendTimeline');
	},
	setFriends: function(){
		this.current = '';
		this.friends = [];
		this.users.innerHTML = '<li class="message"><img src="/images/indicator.gif" width="16" height="16" alt="" />Loading...</li>';
		this.appendScript('http://twitter.com/statuses/friends/' + this.user + '.json?callback=tw.appendFriends');
	},
	next: function(){
		var friends = this.friends;
		var screen_name = this.current;
		var len = friends.length;
		if(!len)return false;
		this.setTimeline(friends[(friends.indexOf(screen_name) + 1 + len) % len]);
	},
	previous: function(){
		var friends = this.friends;
		var screen_name = this.current;
		var len = friends.length;
		if(!len)return false;
		var index = (friends.indexOf(screen_name) >= 0) ? ((friends.indexOf(screen_name) - 1 + len) % len) : (len - 1);
		this.setTimeline(friends[index]);
	},
	appendScript: function(url){
		var script = document.createElement('script');
		script.src = url;
		script.type = 'text/javascript';
		script.charset = 'utf-8';
		this.head.appendChild(script);
	},
	appendFriends: function(users){
		var self = this;
		var ol_users = this.users;
		ol_users.innerHTML = '';
		ol_users.scrollTop = 0;
		users.sort(function(a, b){
			if(!a['status'] || !a['status'].created_at)return 1;
			if(!b['status'] || !b['status'].created_at)return -1;
			var as = a['status'], bs = b['status'];
			if(!as.timestamp)as.timestamp = self.toTimestamp(as.created_at);
			if(!bs.timestamp)bs.timestamp = self.toTimestamp(bs.created_at);
			return bs.timestamp - as.timestamp;
		});

		var i = 0;
		var length = users.length;
		length && setTimeout(function(){
			var user = users[i];
			var status = user.status;
			var screen_name = user.screen_name;
			self.friends.push(screen_name);

			var li = document.createElement('li');

			var img = document.createElement('img');
			img.src = user.profile_image_url;
			img.width = '48';
			img.height = '48';

			var strong = document.createElement('strong');
			strong.innerHTML = screen_name;

			var text = document.createElement('span');
			text.innerHTML = status ? status.text : '';

			var date = document.createElement('span');
			Element.addClassName(date, 'date');
			date.innerHTML = status ? self.toDate(status.timestamp) : '';

			Event.observe(li, 'click', (function(screen_name){
				return function(){
					self.setTimeline(screen_name);
				}
			})(screen_name));

			ol_users.appendChild(li);
			li.appendChild(img);
			li.appendChild(strong);
			li.appendChild(document.createTextNode(' '));
			li.appendChild(text);
			li.appendChild(date);

			if(i < 2)self.preload(screen_name);
			if(++i < length){
				setTimeout(arguments.callee, 0);
			}
		}, 0);
	},
	appendTimeline: function(tline){
		var self = this;
		var length = tline.length;
		if(tline.error)this.timeline.innerHTML = '<li>' + tline.error + '</li>';
		if(!length){
			return false;
		}

		var screen_name = tline[0].user.screen_name;
		this.timelines[screen_name] = tline;
		setTimeout(function(){
			self.timelines[screen_name] = null;
		}, 3 * 60 * 1000);
		var user_status = tline[0].user;

		if(this.user == screen_name){
			var img = document.createElement('img');
			img.src = user_status.profile_image_url;
			img.width = '48';
			img.height = '48';
			img.alt = '';

			var a = document.createElement('a');
			a.target = '_blank';
			a.href = 'http://twitter.com/' + screen_name;
			a.title = 'Twitter / ' + screen_name;
			a.appendChild(img);
			document.getElementsByTagName('h2')[0].appendChild(a);
			setTimeout(function(){
				new Ajax.Request('/friends', {
					method: 'get',
					parameters: {
						user: screen_name,
						url: user_status.profile_image_url
					}
				});
			}, 1000 * 5);
		}

		user_status.description = (user_status.description || '').stripTags()
			.replace(/(http:\/\/[0-9a-z_\+\*\?\#\$\%\&\=\~\/\.\-]+)/ig, '<a href="$1" target="_blank">$1</a>')
			.replace(/@([a-z0-9_\-]+)/ig, '@<a href="/user/$1">$1</a>');
		this.profile.innerHTML = this.profile_tpl.evaluate(user_status);
		
		var timeline = this.timeline;
		timeline.innerHTML = '';
		timeline.scrollTop = 0;
		tline.each(function(t, i){
			var li = document.createElement('li');
			Element.addClassName(li, (i % 2) ? 'odd' : 'even');

			var p = document.createElement('p');
			Element.addClassName(p, 'text');
			p.innerHTML = t.text
				.replace(/(http:\/\/[0-9a-z_\+\*\?\#\$\%\&\=\~\/\.\-]+)/ig, '<a href="$1" target="_blank">$1</a>')
				.replace(/(@|＠)([a-z0-9_\-]+)/ig, '$1<a href="/user/$2">$2</a>');

			var attr = document.createElement('p');
			Element.addClassName(attr, 'attributes');

			var date = document.createElement('a');
			Element.addClassName(date, 'date');
			date.href = 'http://twitter.com/' + screen_name + '/statuses/' + t.id;
			date.title = 'Permalink';
			date.target = '_blank';
			date.innerHTML = self.toDate(self.toTimestamp(t.created_at));

			var from = document.createElement('span');
			from.innerHTML = '&nbsp;from ' + t.source;

			timeline.appendChild(li);
			li.appendChild(p);
			li.appendChild(attr);
			attr.appendChild(date);
			attr.appendChild(from);
			if(!(i % 4)){
				li.style.borderTop = '1px solid #acf';
				self.positions.push(li.offsetTop);
			}
		});
		var friends = this.friends;
		var len = friends.length;
		this.preload(friends[(friends.indexOf(screen_name) + 1 + len) % len]);
		this.preload(friends[(friends.indexOf(screen_name) + 2 + len) % len]);
		this.preload(friends[(friends.indexOf(screen_name) - 1 + len) % len]);
	},
	preload: function(user){
		if(user && !this.timelines[user]){
			this.appendScript('http://twitter.com/statuses/user_timeline/' + user + '.json?callback=tw._preload');
		}
	},
	_preload: function(tline){
		if(!tline.length)return false;
		var self = this;
		var screen_name = tline[0].user.screen_name;
		this.timelines[screen_name] = tline;
		setTimeout(function(){
			self.timelines[screen_name] = null;
		}, 3 * 60 * 1000);
	},
	getFriend: function(n){
		n = (n >= 0 && n < 100) ? n : 0;
		return this.friends[n];
	},
	scrollTid: false,
	scrollFlag: false,
	scrollDown: function(){
		if(this.scrollFlag)return;
		var self = this;
		this.scrollFlag = true;
		var content = this.content;
		var scroll = content.scrollTop;
		var positions = this.positions;
		var target = positions.length ? positions[positions.length - 1] : null;
		for(var i = 0, len = positions.length; i < len; i++){
			if(positions[i] > scroll + 30){
				target = positions[i];
				break;
			}
		}
		if(!target)return (this.scrollFlag = false);
		var i = parseInt((target - scroll) / 10);
		(function(){
			var tout = arguments.callee;
			self.scrollTid = setTimeout(function(){
				scroll += parseInt(i);
				if(i > 7)i /= 1.08;
				if(scroll >= target){
					scroll = target;
					self.scrollFlag = false;
				}else{
					tout();
				}
				content.scrollTop = scroll;
			}, 10);
		})();
	},
	scrollUp: function(){
		if(this.scrollFlag)return;
		var self = this;
		this.scrollFlag = true;
		var content = this.content;
		var scroll = content.scrollTop;
		var positions = this.positions;
		var target = 0;
		for(var i = positions.length - 1; i >= 0; i--){
			if(positions[i] < scroll - 30){
				target = positions[i];
				break;
			}
		}
		var i = parseInt((scroll - target) / 10);
		(function(){
			var tout = arguments.callee;
			self.scrollTid = setTimeout(function(){
				scroll -= parseInt(i);
				if(i > 7)i /= 1.08;
				if(scroll <= target){
					scroll = target;
					self.scrollFlag = false;
				}else{
					tout();
				}
				content.scrollTop = scroll;
			}, 10);
		})();
	},
	scrollFriends: function(){
		var friends = this.friends;
		var n = friends.indexOf(this.current) - 1;
		n = (n < 0) ? 0 : n;

		var direction = this.direction;
		var scroll = direction.scrollTop;
		var offset = this.users.childNodes[n].offsetTop - 10;
		offset = (offset < 0) ? 0 : offset;
		//direction.scrollTop = offset;
		var m = parseInt((offset - scroll) / 10);
		var i = 0;
		(function(){
			var tout = arguments.callee;
			setTimeout(function(){
				var t = direction.scrollTop + m;
				if(((m > 0) ? (t >= offset) : (t <= offset)) || ++i > 10)t = offset;
				else tout();
				direction.scrollTop = t;
			}, 0);
		})();
	},
	toTimestamp: function(time){
		var months = 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(',');
		var match = time.match(/^([a-z]+) ([a-z]+) ([0-9]+) ([0-9]+):([0-9]+):([0-9]+) ([^ ]+) ([0-9]+)$/i);
		if(!match)return 0;
		var year = +match[8];
		var month = 0;
		for(var i = 0, len =  months.length; i < len; i++){
			if(match[2].match(months[i])){
				month = i;
				break;
			}
		}
		var day = match[3];
		var hour = match[4];
		var minute = match[5];
		var second = match[6];	
		var d =  new Date(year, month, day, hour, minute, second);
		return d.getTime() - (d.getTimezoneOffset() * 60 * 1000);
	},
	toDate: function(timestamp){
		var d = new Date(timestamp);
		var year = d.getFullYear();
		var month = d.getMonth() + 1;
		var day = d.getDate();
		var hour = d.getHours();
		var minute = d.getMinutes();
		var second = d.getSeconds();
		var add_zero = function(v){
			return (v < 10) ? ('0' + v) : v;
		};
		return [year, month, day].map(add_zero).join('-') + ' ' + [hour, minute, second].map(add_zero).join(':');
	}
};
