/*
 * 
 * twttrFloatTip
 * 
 * jQuery required (tested on version 1.4.2)
 * encoding UTF-8
 * 
 * Copyright (c) 2010 nori (norimania@gmail.com)
 * 5509 - http://moto-mono.net
 * Licensed under the MIT
 * 
 * Special Thanks - rew (http://rewish.org)
 *
 * $Update: 2010-03-29 21:30
 * $Date: 2010-03-17 08:07
 * 
 */
 
(function($){

	// TwttrFloatTip
	$.fn.twttrFloatTip = function(options) {

		var UP = new twttrFloatTip(),
			c = $.extend(UP, {
				user_name: 'text', // text, href, attr(not href)
				attr: null, // user_nameがattrの場合など
				// ex) user_name: 'attr', attr: 'title'
				href: 'http://twitter.com/'
				// 対象をhrefにした場合は、カットしたいhrefを入れる
			}, options);
			
		$(this).each(function(i) {
			var screen_name,
				$this = $(this);
			
			if( c.user_name == 'href' ) {
				screen_name = $this.attr('href').replace(c.href, '');
			} else {
				screen_name = $this[c.user_name](c.attr);
				if( screen_name.match(/^@/) ) {
					screen_name = screen_name.replace(/^@/, '');
				}
			}
			
			$this.hover(
				function() {
					var pos = $this.offset();
					
					UP.mouseEnterFlg = true;
					UP.jsonpReadQueue[screen_name] = true;
					UP.setPos(pos, $this);
					UP.addData(screen_name, function(){
						// コールバックで位置の調整
						UP.setPos(pos, $this);
					});
				},
				function() {
					// カーソルが外れたらフラグを立てる
					UP.jsonpReadQueue[screen_name] = false;
					UP.mouseEnterFlg = false;
					
					// カーソルが外れてhideDurationミリ秒後にmouseEnterFlgがfalseなら非表示にする
					setTimeout(function() {
						if( !UP.mouseEnterFlg ) {
							UP.content.css({
								left: '-1000em'
							});
						}
					}, UP.hideDuration);
				}
			);
		});
		
		// メソッドチェーンできるよ！
		return this;
	}
	
	// UserPreview
	// ここに一時データなどを保存する
	var twttrFloatTip = function() {
		
		var self = this;
		
		this.apiURL = 'http://twitter.com/users/show.json';
		this.userObject = {};
		this.loadingText = 'loading...';
		this.jsonpReadQueue = {};
		this.mouseEnterFlg = null;
		this.hideDuration = 500;
		this.spaceFix = 5;
		this.moreBtn = true;
		/*
		this.userObject: {
			'screen_name': {
				'profile_image_url': hoge,
				'name': hoge,
				'screen_name': hoge,
				'location': hoge,
				'url': hoge,
				'description': hoge,
				'latest_tweet': hoge,
				'statuses_count': hoge,
				'friends_count': hoge,
				'followers_count': hoge,
				'favourites_count': hoge
			}
		}
		this.jsonpReadQueue =  = {
			'screen_name': true / false
		}
		*/
		
		this.temp = function(data) {
			return [
				'<div class="userPreviewInner">',
					'<div class="userData">',
						'<div class="userImage">',
							'<img src="'+data['profile_image_url']+'" alt="'+data['name']+'" width="48" height="48" class="userImage" />',
						'</div>',
						'<div class="userTexts">',
							'<div class="userName">'+data['name']+'</div>',
							'<div class="userScreenName"><a class="userScreenName" href="http://twitter.com/'+data['screen_name']+'">@'+data['screen_name']+'</a></div>',
							data['location']
							? '<div class="userLocation">'+data['location']+'</div>'
							: '',
						'</div>',
					'</div>',
					'<div class="userDetail">',
						'<div class="userSubData">',
							data['url'] 
							? '<div class="userWebSite">Web ： <span class="userWebSite"><a href="'+data['url']+'">'+data['url']+'</a></span></div>'
							: '',
							data['description'] 
							? '<div class="userBio">Bio ： <span class="userBio">'+data['description']+'</span></div>'
							: '',
							'<div class="latest">Latest Tweet ： <span class="userLatest">'+data['latest_tweet']+'</span></div>',
						'</div>',
						'<ul class="userStatus">',
							'<li class="userTweets"><span class="userTweets">'+data['statuses_count']+'</span>tweets</li>',
							'<li class="userFollowing"><span class="userFollowing">'+data['friends_count']+'</span>following</li>',
							'<li class="userFollowers"><span class="userFollowers">'+data['followers_count']+'</span>followers</li>',
							'<li class="userFavourites"><span class="userFavourites">'+data['favourites_count']+'</span>favourites</li>',
						'</ul>',
					'</div>',
				'</div>'
			].join('');
		}
		this.loading = function() {
			return [
				'<div class="loadingInner">',
					'<div class="text">'+this.loadingText+'</div>',
				'</div>'
			].join('');
		}
		
		this.content = $('<div class="userPreview"/>');
		this.content
			.hover(
				function() {
					self.mouseEnterFlg = true;
				},
				function() {
					self.mouseEnterFlg = false;
					setTimeout(function() {
						if( !self.mouseEnterFlg ) {
							self.content.css({
								left: '-1000em'
							});
						}
					}, self.hideDuration);
				}
			)
			.append(this.loading())
			.addClass('loading');

		
		$('body').append(this.content.css({
			position: 'absolute',
			left: '-1000em',
			display: 'none'
		}));
	}
	
	// 情報を更新する
	twttrFloatTip.prototype.upDate = function(temp, data) {
		this.content.empty().removeClass('loading').append(temp(data));
	}
	
	// JSONPで情報を取得して保存する
	twttrFloatTip.prototype.addData = function(screen_name, set_pos) {

		// screen_nameが空の場合はなにもしない･･･なにも･･･できない･･･
		if( !screen_name ) return false;

		var self = this;
		
		// 既に取得済みの場合はリクエストせずに一時データを使う
		if( self.userObject[screen_name] ) {
			self.upDate(self.temp, self.userObject[screen_name]);
			
			// ある意味コールバック
			set_pos();
			
		// 取得中なら何もせずに松
		} else if( $('script[src*="screen_name='+screen_name+'"]').length>0 ) {
			// console.log('wait a minute');
		
		// 未取得ならリクエストを行う
		} else {
			self.content.empty().addClass('loading').append(self.loading());
			// ある意味コールバック
			set_pos();
			
			// 通信前にフラグを立てておく
			self.jsonpReadQueue[screen_name] = true;
			$.ajax({
				url: self.apiURL,
				type: 'GET',
				dataType: 'jsonp',
				data: {
					'screen_name': screen_name
				},
				success: function(JSON) {
					// エラーが返されたら
					if( JSON.error ) {
						if( self.jsonpReadQueue[screen_name] ) {
							self.content.empty().removeClass('loading').append('<div class="error">Rate Limit Exceed</a>');
							
							// ある意味コールバック
							set_pos();
						}
					// データを取得できたら
					} else {
						// データを一時保存(ページリロードで消えるで)
						self.userObject[screen_name] = {
							'profile_image_url': JSON['profile_image_url'],
							'name': JSON['name'],
							'screen_name': JSON['screen_name'],
							'location': JSON['location'],
							'url': JSON['url'],
							'description': JSON['description'],
							'latest_tweet': twttrUserAnchorStyle(JSON['status']['text']),
							'statuses_count': toDeliminated(JSON['statuses_count']),
							'friends_count': toDeliminated(JSON['friends_count']),
							'followers_count': toDeliminated(JSON['followers_count']),
							'favourites_count': toDeliminated(JSON['favourites_count'])
						}
						// カーソルが残っていれば表示する
						if( self.jsonpReadQueue[screen_name] ) {
							self.upDate(self.temp, self.userObject[screen_name]);
							
							// ある意味コールバック
							set_pos();
						}
					}
				}
			});
		}
	}
	
	// 位置を調整する
	twttrFloatTip.prototype.setPos = function(pos, elm) {
		var d = document,
			self = this,
			clientHeight = d.documentElement.clientHeight,
			clientWidth = d.documentElement.clientWidth,
			scrollTop = d.body.scrollTop || d.documentElement.scrollTop,
			posFlg = ( ( pos.top - scrollTop ) > clientHeight / 2 ) ? true : false,
			posFlgSide = ( pos.left > clientWidth /2 ) ? true : false,
			// true: above, false: below
			posClass = posFlg ? 'floatTipAbove' : 'floatTipBelow',
			// true: right, false: left
			posClassSide = posFlgSide ? 'Right' : 'Left',
			posClass = posClass + posClassSide;
				
		this.content
			.removeClass('floatTipAboveRight')
			.removeClass('floatTipAboveLeft')
			.removeClass('floatTipBelowRight')
			.removeClass('floatTipBelowLeft')
			.addClass(posClass)
			.css({
				left: '-1000em'
			});
			
		if( posFlg ) {
			this.content.css({
				top: pos.top - self.content.attr('offsetHeight') - self.spaceFix
				//left: pos.left
			});
		} else {
			this.content.css({
				top: pos.top + $(elm).height() + self.spaceFix
				//left: pos.left
			});
		}
		
		if( posFlgSide ) {
			console.log(self.content.attr('offsetWidth'))
			this.content.css({
				left: pos.left + elm.attr('offsetWidth') - self.content.attr('offsetWidth')
			});
		} else {
			this.content.css({
				left: pos.left
			});
		}
	}
	
	// ユーザーとリンクっぽい箇所にアンカーを付けて返す
	function twttrUserAnchorStyle(tweet) {
		return tweet
			.replace(/(https?\:\/\/[^ 　]+)/g, '<a href="$1">$1</a>')
			.replace(/@(\w{1,15})/g, '<a href="http://twitter.com/$1">@$1</a>');
	}
	
	// Thanks for nanto_vi
	// http://nanto.asablo.jp/blog/2007/12/07/2479257
	function toDeliminated(num) {
		var string = "" + + num;
		var pointIndex = string.indexOf(".");
		return (pointIndex == -1)
			? string.replace(/(\d{1,3})(?=(?:\d\d\d)+$)/g, "$1,")
			: string.substring(0, pointIndex)
				.replace(/(\d{1,3})(?=(?:\d\d\d)+$)/g, "$1,") +
			  string.substring(pointIndex)
				.replace(/(\d\d\d)(?=\d)/g, "$1,");
	}
	
})(jQuery);


