$(function() {
	// 共通変数
	var w = $(window);
	var d = $(document);
	var b = $(document.body);
	var clip = $('#clip');
	var usersUl = $('#users');
	var article = $('article');
	var pager = $('#pager');
	var duplex = $('#duplex').find('select');
	var aside = $('aside');
	var footer = $('footer');
	var helps = footer.find('p');

	// 共通 function
	function err(msg) {
		alert(msg);
	}
	function h(str) {
		str = str.replace('"', '&quot;').replace('<', '&lt;').replace('>', '&gt;');
		str = str.replace(new RegExp("(https?://[-/._&%=?0-9a-z]+)", "ig"), '<a href="$1" target="_blank">$1</a>');
		str = str.replace(new RegExp("@([0-9a-z_]+)", "ig"), '<a href="http://twitter.com/$1" target="_blank">@$1</a>');
		str = str.replace(new RegExp("#([^ \\t\\r\\n]+)", "ig"), '<a href="http://twitter.com/search/%23' + encodeURI('$1') + '" target="_blank">#$1</a>');
		return str;
	}
	function ok(obj) {
		if (!obj) return false;
		if (typeof obj == 'string') {
			return obj.length > 0;
		}
		return true;
	}
	function num(n) {
		n = n + '';
		var arr = n.split('').reverse();
		var res = [];
		for (var i=0; i<arr.length; i++) {
			if (i!=0 && i%3==0) {
				res.push(',');
			}
			res.push(arr[i]);
		}
		return res.reverse().join('');
	}
	function date(str) {
		var d = new Date(str);
		return d.getFullYear() + '-' +
			fill(d.getMonth() + 1) + '-' +
			fill(d.getDate()) + ' ' +
			fill(d.getHours()) + ':' +
			fill(d.getMinutes()) + ':' +
			fill(d.getSeconds())
		;
	}
	function fill(value, len, c) {
		var str = value + '';
		c = !!c ? c : '0';
		while (str.length < len) {str = c + str;}
		return str;
	}
	function diff(str) {
		var date = new Date(str);
		var html = '';
		var diffStr = false;
		var clazz = false;
		while (true) {
			var diff = (new Date()).getTime() - date.getTime();
			diff = diff / 1000;
			if (diff <= 60) {
				diffStr = '1分以内';
				break;
			}
			diff = diff / 60;
			if (diff < 60) {
				diffStr = '約' + Math.floor(diff) + '分前';
				break;
			}
			diff = diff / 60;
			if (diff < 24) {
				diffStr = '約' + Math.floor(diff) + '時間前';
				break;
			}
			diff = diff / 24;
			if (diff < 30) {
				diffStr = '約' + Math.floor(diff) + '日前';
				clazz = 'diff_day';
			} else if (diff < 60) {
				diffStr = '1ヶ月以上前';
				clazz = 'diff_1mon';
			} else if (diff < 90) {
				diffStr = '2ヶ月以上前';
				clazz = 'diff_2mon';
			} else {
				diffStr = '3ヶ月以上前';
				clazz = 'diff_3mon';
			}
			break;
		}
		if (clazz) {
			html += '<span class="' + clazz + '">';
		}
		html += '(' + diffStr + ')';
		if (clazz) { html += '</span>'; }
		return html;
	}
	function loading(wait) {
		if (wait) {
			article.removeClass('hideloading').addClass('loading');
		} else {
			article.addClass('hideloading');
			setTimeout(function() {
				article.removeClass('loading').removeClass('hideloading');
				$('#duplex').show();
			}, 200);
		}
	}

	// クラス
	function Pager(itemLength) {
		this.current = 0;
		this.itemCount = 20;
		this.lastIndex = parseInt((itemLength-1) / this.itemCount);
		this.maxButtons = 5;
		this.toHtml = function() {
			var start = this.current - parseInt(this.maxButtons / 2);
			if (start < 0) start = 0;
			var end = Math.max(this.current + parseInt(this.maxButtons / 2), start + this.maxButtons - 1);
			if (end > this.lastIndex) end = this.lastIndex;
			var html = '';
			if (start > 0) {
				html += '<li class="button enable" data-index="0">≪</li>';
				html += '<li class="period">...</li>';
			}
			for (var i=start; i<=end; i++) {
				if (i == this.current) {
					html += '<li class="button current">' + (i+1) + '</li>';
				} else {
					html += '<li class="button enable" data-index="' + i + '">' + (i+1) + '</li>';
				}
			}
			if (end < this.lastIndex) {
				html += '<li class="period">...</li>';
				html += '<li class="button enable" data-index="' + this.lastIndex + '">≫</li>';
			}
			return html;
		}
		this.set = function(index) {
			this.current = index;
		}
		this.start = function(offset) {
			offset = !!offset ? offset : 0;
			return (this.current + offset) * this.itemCount;
		}
		this.end = function(offset) {
			offset = !!offset ? offset : 0;
			return (this.current + offset + 1) * this.itemCount;
		}
	}

	// サイズ
	w.resize(function() {
		var baseHeight = w.height() - b.height() + clip.height();
		clip.height(baseHeight - 30);
		aside.height(baseHeight + 37);
	}).resize();

	// ヘルプの表示
	$('.help').live('mouseover', function() {
		var help = $(this).data('help');
		helps.stop(false, false).animate({'opacity': 0});
		footer.find('.' + help).stop(false, false).animate({'opacity': 1});
	}).live('mouseout', function() {
		helps.stop(false, false).animate({'opacity': 0}, 'fast');
		footer.find('.default').stop(false, false).animate({'opacity': 1}, 'fast');
	});

	// フォロー解除
	$('.controls .followed').live('mouseover', function() {
		$(this).addClass('remove').text('フォロー解除');
	}).live('mouseout', function() {
		$(this).removeClass('remove').text('フォロー中');
	});
	
	// TwitAPI.js
	var api = new TwitAPI('http://taj-proxy.appspot.com', 'twitmgr');
	
	// アクション
	var user;
	var followingIds;
	var followingPager;
	var followersIds;
	var followersPager;
	var currentAction;
	var currentPager;
	var users = {};
	function act(func) {
		// 初期化
		if (!user) {
			var error = false;
			var finished = false;
			// ユーザ情報
			api.call('get', '1/statuses/user_timeline', function(res) {
				if (!res || res.length != 1) {
					error = true;
					err('ユーザ情報が取得出来ません。');
					return;
				}
				user = res[0].user;
				// following 情報
				api.call('get', '1/friends/ids', function(res) {
					if (!res) {
						error = true;
						err('フレンズ情報が取得出来ません。');
						return;
					}
					followingIds = res.ids;
					// followers 情報
					api.call('get', '1/followers/ids', function(res) {
						if (!res) {
							error = true;
							err('フォロワー情報が取得出来ません。');
							return;
						}
						followersIds = res.ids;

						for (var i=0; i<followingIds.length; i++) {
							users[followingIds[i]] = {
								'id': followingIds[i],
								'following': true,
								'follower': false
							};
						}
						for (var i=0; i<followersIds.length; i++) {
							if (users[followersIds[i]]) {
								users[followersIds[i]].follower = true;
							} else {
								users[followersIds[i]] = {
									'id': followingIds[i],
									'following': false,
									'follower': true
								};
							}
						}

						followingPager = new Pager(followingIds.length, 'following');
						followersPager = new Pager(followersIds.length, 'followers');
						finished = true;
					}, {'user_id': user.id_str});
				}, {'user_id': user.id_str});
			}, {'count': 1});
			(function() {
				if (error) {
					return;
				} else if (finished) {
					func();
					return;
				}
				setTimeout(arguments.callee, 100);
			})();
		} else {
			func();
		}
	}
	function loadUsers(userIds, func) {
		var joinedIds = '';
		for (var i=0; i<userIds.length; i++) {
			var userId = userIds[i];
			if (users[userId].loaded) continue;
			if (joinedIds.length > 0) joinedIds += '%2C';
			joinedIds += userId;
		}
		if (joinedIds.length > 0) {
			api.call('get', '1/users/lookup', function(res) {
				for (var i=0; i<res.length; i++) {
					var user = res[i];
					var userId = user.id_str;
					$.extend(users[userId], user, {'loaded': true});
				}
				if (!!func) func();
			}, 'user_id=' + joinedIds);
		} else {
			if (!!func) func();
		}
	}
	function viewUsers(userIds, pagerObj) {
		usersUl.empty();
		clip.scrollTop(0);
		pager.empty();
		loadUsers(userIds, function() {
			var dup = duplex.val();
			var appended = false;
			for (var i=0; i<userIds.length; i++) {
				var userId = userIds[i];
				var user = users[userId];
				if (!user.domReady) {
					user.dom = $('<li data-id="' + userId + '">').html(
						'<img class="waiting" src="img/loading_user.gif" />' +
						'<div class="info">' +
							'<div class="controls ' + (user.following ? '' : 'un') + 'following">' +
								'<div class="pane1">' +
									'<a class="followed">フォロー中</a><a class="follow">フォローする</a>' +
								'</div>' +
								'<div class="pane2">' +
									'<a class="block">ブロックする</a>' +
									'<a class="spam">スパム報告</a>' +
								'</div>' +
							'</div>' +
							'<a href="http://twitter.com/'+ user.screen_name + '" target="_blank"><img class="icon" src="' + user.profile_image_url + '"></a>' +
							'<div class="simple">' +
								'<span class="full-name">' + h(user.name) + '</span> ' +
								'<a href="http://twitter.com/'+ user.screen_name + '" class="screen-name" target="_blank">@' + user.screen_name + '</a> ' +
								(ok(user.url) ? '<a class="url" href="' + user.url + '" target="_blank">WEB</a> ' : '') +
								'<span class="following help" data-help="info-following">' + user.friends_count + '</span> ' +
								'<span class="followers help" data-help="info-followers">' + user.followers_count + '</span> ' +
							'</div>' +
							(ok(user.description) ? '<div class="bio">' + h(user.description) + '</div>' : '') +
						'</div>' +
						'<div class="tweets">' +
							(ok(user.status) ? '<a class="show">最新のツイートを見る</a> <a class="hide">最新のツイートを隠す</a> ' : '') +
							'<span class="count help" data-help="tweets-count">' + num(user.statuses_count) + '</span> ' +
							'<span class="timestamp help" data-help="tweets-timestamp">' + (ok(user.status) ? date(user.status.created_at) : '-') + '</span> ' +
							(ok(user.status) ? '<span class="timestamp-view">' + diff(user.status.created_at)  + '</span> ' : '') +
							'<ul></ul>' +
						'</div>'
					);
					user.domReady = true;
				}
				if (dup == 'show') {
					if (user.following && user.follower) {
						usersUl.append(user.dom.show());
						appended = true;
					}
				} else if (dup == 'hide') {
					if (!(user.following && user.follower)) {
						usersUl.append(user.dom.show());
						appended = true;
					}
				} else {
					usersUl.append(user.dom.show());
					appended = true;
				}
			}
			if (appended) {
				pager.html(currentPager.toHtml());
			} else {
				usersUl.html('<li>該当するユーザがいませんでした。</li>');
			}
			loading(false);
		});
	}
	var actions = {
		'following': function() {
			loading(true);
			currentPager = followingPager;
			viewUsers(followingIds.slice(followingPager.start(), followingPager.end()));
			loadUsers(followingIds.slice(followingPager.start(1), followingPager.end(1)));
			loadUsers(followersIds.slice(followersPager.start(), followersPager.end()));
			loadUsers(followingIds.slice(followingPager.start(-1), followingPager.end(-1)));
		},
		'followers': function() {
			loading(true);
			currentPager = followersPager;
			viewUsers(followersIds.slice(followersPager.start(), followersPager.end()));
			loadUsers(followersIds.slice(followersPager.start(1), followersPager.end(1)));
			loadUsers(followingIds.slice(followingPager.start(), followingPager.end()));
			loadUsers(followersIds.slice(followersPager.start(-1), followersPager.end(-1)));
		}
	}

	// タブのクリック
	$('.tab').click(function() {
		var tab = $(this);
		currentAction = tab.data('tab');
		act(actions[currentAction]);
		$('.tab').removeClass('selected');
		tab.addClass('selected');
	});
	
	// 相互フォロー
	duplex.change(function() {
		act(actions[currentAction]);
	});
	
	// ページャ
	$('#pager .enable').live('click', function() {
		var index = $(this).data('index');
		currentPager.set(index);
		act(actions[currentAction]);
	});
	
	// フォロー・リムーブ・ブロック
	$('.controls .follow').live('click', function() {
		var a = $(this);
		var li = a.parents('li');
		var userId = li.data('id');
		var user = users[userId];
		li.addClass('waiting');
		api.call('post', '1/friendships/create', function(){
			user.following = true;
			followingIds.unshift(userId);
			li.find('.controls').removeClass('unfollowing').addClass('following');
			li.removeClass('waiting');
		}, {'user_id': userId});
	}).end().find('.remove').live('click', function() {
		var a = $(this);
		var li = a.parents('li');
		var userId = li.data('id');
		var user = users[userId];
		li.addClass('waiting');
		api.call('post', '1/friendships/destroy', function(){
			user.following = false;
			for (var i=0; i<followingIds.length; i++) {
				if (followingIds[i] == userId) {
					followingIds.splice(i, 1);
					break;
				}
			}
			li.find('.controls').removeClass('following').addClass('unfollowing');
			li.removeClass('waiting');
			if (currentAction == 'following') {
				li.slideUp('fast');
			}
		}, {'user_id': userId});
	}).end().find('.block , .spam').live('click', function() {
		var a = $(this);
		var li = a.parents('li');
		var userId = li.data('id');
		var user = users[userId];
		li.addClass('waiting');
		var path = a.hasClass('spam') ? '1/report_spam' : '1/blocks/create';
		api.call('post', path, function(){
			for (var i=0; i<followingIds.length; i++) {
				if (followingIds[i] == userId) {
					followingIds.splice(i, 1);
					break;
				}
			}
			for (var i=0; i<followersIds.length; i++) {
				if (followersIds[i] == userId) {
					followersIds.splice(i, 1);
					break;
				}
			}
			li.removeClass('waiting');
			li.slideUp();
		}, {'user_id': userId});
	}).end()

	// ツイートの表示・非表示
	$('.show').live('click', function() {
		var a = $(this);
		var li = a.parents('li');
		var userId = li.data('id');
		var user = users[userId];
		if (!user.tweetsReady) {
			li.addClass('waiting');
			api.call('get', '1/statuses/user_timeline', function(res) {
				var html = '';
				for (var i=0; i<res.length; i++) {
					var t = res[i];
					html += '<li class="' + (ok(t.retweeted_status) ? ' retweet' : '') + '">' + h(t.text) + ' (' + date(t.created_at) + ')</li>';
				}
				user.dom.find('.tweets ul').html(html);
				user.tweetsReady = true;
				li.removeClass('waiting');
				a.hide().parent().find('.hide').show().end().find('ul').slideDown('fast');
			}, {'user_id': userId, 'include_rts': 't', 'trim_user': 't'});
		} else {
			a.hide().parent().find('.hide').show().end().find('ul').slideDown('fast');
		}
	});
	$('.hide').live('click', function() {
		$(this).hide().parent()
			.find('.show').show().end()
			.find('ul').slideUp('fast')
		;
	});
});

