/* ------------------------------------------------------------------------- */
/* "uni-twidget" blog-part script for twitter           Ver.1.10  2011/03/16 */
/*              (C)2011 digiuni, digi*unique production All rights reserved. */
/* ------------------------------------------------------------------------- */
/* author: digiuni(digi*unique production), tab-stop: 4, indent: 4           */
/* ------------------------------------------------------------------------- */
var program = "uni-twidget";			/* プログラム名						 */
var version = "1.10";					/* バージョン						 */
var release = "2011/03/16";				/* リリース日						 */
/* ------------------------------------------------------------------------- */
/* 更新履歴																	 */
/* ------------------------------------------------------------------------- */
/* 1.00	2011/03/13	最初のリリース											 */
/* 1.01	2011/03/14	取得レコードが無かった場合の処理を追加					 */
/* 1.10	2011/03/16	送り戻しのUIを追加										 */

/* ------------------------------------------------------------------------- */
/* 設定用変数																 */
/* ------------------------------------------------------------------------- */
var textColorCode  = "#404040";			/* 文字色							 */
var linkColorCode  = "#404040";			/* リンク文字色						 */
var timeColorCode  = "#808080";			/* 時刻文字色						 */
var backColorCode  = "#ffffff";			/* 背景色							 */
var textFontSize   = 12;				/* 文字サイズ						 */
var timeFontSize   = 10;				/* 時刻文字サイズ					 */
var widgetHtmlId   = "uni-twidget";		/* HTMLで定義した表示フレームのID	 */
var animationFrameMax            = 4;	/* 切替アニメーションコマ数 	4	 */
var animationInterval            = 80;	/* 切替アニメーション進行間隔	80	 */
var transitionIntervalBase       = 3000;/* 基本切替間隔					2000 */
var transitionIntervalAddPerChar = 100;	/* 追加切替間隔（1文字毎）		100	 */
var transitionDirFwd = false;			/* 切替進行方向（時系列方向=true）	 */

/* ------------------------------------------------------------------------- */
/* 制御用変数																 */
/* ------------------------------------------------------------------------- */
var tweet = new Array();				/* twitterから取得したレコードリスト */
var tweetIdx;							/* レコード情報配列のインデックス	 */
var transitionStage;					/* アニメーション状態変数			 */
var animationFrame;						/* アニメーションフレーム番号		 */
var textColor;							/* 文字色							 */
var linkColor;							/* リンク文字色						 */
var timeColor;							/* 時刻文字色						 */
var backColor;							/* 背景色							 */
var textColorOnAnim;					/* アニメーション中の文字色			 */
var linkColorOnAnim;					/* アニメーション中のリンク文字色	 */
var timeColorOnAnim;					/* アニメーション中の時刻文字色		 */
var contents;							/* 表示処理中の文字列				 */
var timerAnimation;						/* アニメーション用タイマハンドル	 */

/* ------------------------------------------------------------------------- */
/* 定数																		 */
/* ------------------------------------------------------------------------- */
/* 状態定義 */
var TRANSITION_STAGE_INIT      = 0;		/* 初期化							 */
var TRANSITION_STAGE_DISAPPEAR = 1;		/* 消滅アニメーション				 */
var TRANSITION_STAGE_APPEAR    = 2;		/* 出現アニメーション				 */
var TRANSITION_STAGE_STAY      = 3;		/* 表示維持							 */

/* ------------------------------------------------------------------------- */
/* 関数																		 */
/* ------------------------------------------------------------------------- */
/* 初期化 */
function Init()
{
	textColor       = new Color( textColorCode );
	timeColor       = new Color( timeColorCode );
	linkColor       = new Color( linkColorCode );
	backColor       = new Color( backColorCode );
	textColorOnAnim = new Color();
	timeColorOnAnim = new Color();
	linkColorOnAnim = new Color();
	transitionStage = TRANSITION_STAGE_INIT;

	if( tweet.length )
	{
		tweetIdx = new Index( 0, tweet.length, transitionDirFwd );
		timerAnimation = setTimeout( "AnimSequenceCb()", 0 );
	}
	else
	{
		SlideShowError();
	}
}

/* ------------------------------------------------------------------------- */
/* twitterAPIからのtweetリスト取得 */
function GetTweet( data )
{
	var i = 0;

	if( typeof( data.results ) == "undefined" )
	{
        return;
	}

    for( i = 0; i < data.results.length; i++ )
    {
        tweet.push( new TweetData( data.results[ i ], i ) );
    }
}

/* ------------------------------------------------------------------------- */
/* アニメーション処理（コールバック） */
function AnimSequenceCb()
{
	switch( transitionStage )
	{
	/* ----------------------------------------- */
	/* 初期化状態処理							 */
	/* ----------------------------------------- */
	case TRANSITION_STAGE_INIT:
		/* 表示記事情報の初期化 */
		contents        = tweet[ tweetIdx.getIdx() ];
		animationFrame  = 0;
		tweetIdx.next();

		/* 状態遷移：初期化→出現 */
		transitionStage = TRANSITION_STAGE_APPEAR;
		timerAnimation  = setTimeout( "AnimSequenceCb()", 0 );
		break;

	/* ----------------------------------------- */
	/* 出現アニメーション状態処理				 */
	/* ----------------------------------------- */
	case TRANSITION_STAGE_APPEAR:
		SlideShowTransition( true, animationFrame, animationFrameMax );
		if( animationFrame < animationFrameMax )
		{
			/* 次のフレームを設定 */
			animationFrame ++;
			timerAnimation = setTimeout( "AnimSequenceCb()", animationInterval );
		}
		else
		{
			/* フレームをクリア */
			animationFrame  = 0;

			/* 状態遷移：初期化→出現 */
			transitionStage = TRANSITION_STAGE_STAY;
			timerAnimation  = setTimeout( "AnimSequenceCb()", 0 );
		}
		break;

	/* ----------------------------------------- */
	/* 表示維持状態処理							 */
	/* ----------------------------------------- */
	case TRANSITION_STAGE_STAY:
		/* 状態遷移：出現→表示維持 */
		transitionStage = TRANSITION_STAGE_DISAPPEAR;
	    timerAnimation  = setTimeout( "AnimSequenceCb()",
	                                  transitionIntervalBase +
	                                  contents.getLength() * transitionIntervalAddPerChar +
	                                  animationInterval * animationFrameMax * 2 );
		break;

	/* ----------------------------------------- */
	/* 消滅アニメーション状態処理				 */
	/* ----------------------------------------- */
	case TRANSITION_STAGE_DISAPPEAR:
		SlideShowTransition( false, animationFrame, animationFrameMax );
		if( animationFrame < animationFrameMax )
		{
			/* 次のフレームを設定 */
			animationFrame ++;
			timerAnimation = setTimeout( "AnimSequenceCb()", animationInterval );
		}
		else
		{
			/* フレームをクリア */
			animationFrame  = 0;

			/* 状態遷移：消滅→初期化 */
			transitionStage = TRANSITION_STAGE_INIT;
			timerAnimation  = setTimeout( "AnimSequenceCb()", 0 );
		}
		break;

	default:
		;
		break;
	}
}

/* ------------------------------------------------------------------------- */
/* スライドショー処理 */
function SlideShowTransition( appear, frameCurr, frameMax )
{
	var i     = 0;
	var fg    = 0;
	var bg    = 0;
	var tr    = 0;
	var html  = "";
	var idx   = contents.getIdx();
	var text  = contents.getText();
	var time  = contents.getTime();
	var ratio = appear ?
	            ( ( frameMax - frameCurr ) / frameMax ) :
	            ( ( frameCurr ) / frameMax );

	for( i = 0; i < 3; i ++ )
	{
		bg = backColor.getDec( i );

		/* アニメーション中のテキスト色 生成 */
		fg = textColor.getDec( i );
		tr = Math.floor( fg + ( bg - fg ) * ratio );
		textColorOnAnim.setDec( tr, i );

		/* アニメーション中のテキスト色 生成 */
		fg = timeColor.getDec( i );
		tr = Math.floor( fg + ( bg - fg ) * ratio );
		timeColorOnAnim.setDec( tr, i );

		/* アニメーション中のリンク色 生成 */
		fg = linkColor.getDec( i );
		tr = Math.floor( fg + ( bg - fg ) * ratio );
		linkColorOnAnim.setDec( tr, i );
	}
	
	text = text.replace( /<a (.*?)>/gi, '<a $1 ' + 'style="color:' + linkColorOnAnim.getCode() + ';">' );

	html += '<span style="font-size:' + textFontSize + 'px; line-height:130%; color:' + textColorOnAnim.getCode() + ';">' + text + '</span>' + '<br />' +
	        '<span style="font-size:' + timeFontSize + 'px; line-height:130%; color:' + timeColorOnAnim.getCode() + ';">' + time + '&nbsp;&nbsp;';
	html += '<span style="cursor:pointer; text-decoration:underline;" OnClick="Prev();">' + '&lt;&lt;' + '</span> | ';
	html += ( idx == 0 ) ? ( "最新" ) : ( idx + "件前" );
	html += ' | <span style="cursor:pointer; text-decoration:underline;" OnClick="Next();">' + '&gt;&gt;' + '</span>';

	document.getElementById( widgetHtmlId ).innerHTML = html;
}

/* ------------------------------------------------------------------------- */
/* エラー表示 */
function SlideShowError()
{
	var html  = "";
	var text  = "データを取得できません。";

	html = '<span style="font-size:' + textFontSize + 'px; line-height:130%; color:' + textColor.getCode() + ';">' + text + '</span>' + '<br />';

	document.getElementById( widgetHtmlId ).innerHTML = html;
}

/* ------------------------------------------------------------------------- */
/* 次の記事を表示 */
function Next()
{
	/* 進行中のタイマをキャンセルして次に送る */
	/* アニメーション中でもそのまま折り返すため
	   animationFrame変数のクリアは行わない。 */

	clearTimeout( timerAnimation );

	/* 遷移後1レコード進むので、時間を送るだけ。 */

	transitionStage = TRANSITION_STAGE_DISAPPEAR;
    timerAnimation  = setTimeout( "AnimSequenceCb()", 0 );
}

/* ------------------------------------------------------------------------- */
/* 前の記事を表示 */
function Prev()
{
	/* 進行中のタイマをキャンセルして前に戻す */
	/* アニメーション中でもそのまま折り返すため
	   animationFrame変数のクリアは行わない。 */

	clearTimeout( timerAnimation );

	/* 遷移後1レコード進むので、2レコード戻す。 */
	tweetIdx.prev();
	tweetIdx.prev();

	transitionStage = TRANSITION_STAGE_DISAPPEAR;
    timerAnimation  = setTimeout( "AnimSequenceCb()", 0 );
}

/* ------------------------------------------------------------------------- */
/* オブジェクト																 */
/* ------------------------------------------------------------------------- */
/* 色オブジェクト */
function Color( data )
{
	/* ----------------------------------------- */
	/* 入力オブジェクトのプロパティ				 */
	/* ----------------------------------------- */
	/* HTMLカラーコード文字列					 */
	/* #RRGGBB形式のコードのみ対応				 */
	/* ----------------------------------------- */
	
	/* ----------------------------------------- */
	/* 公開API：コード設定						 */
	/* ----------------------------------------- */
	function SetCode( code )
	{
		var i = 0;

		if( null == code.match( /#[0-9a-fA-F]{6}/ ) )
		{
			this.code = "#000000";
		}
		else
		{
			this.code = code;
		}

		for( i = 0; i < this.idxMax; i ++ )
		{
			this.hex[ i ] = code.slice( 1 + 2 * i, 3 + 2 * i );
			this.dec[ i ] = parseInt( this.hex[ i ], 16 );
		}
	}

	/* ----------------------------------------- */
	/* 公開API：10進設定						 */
	/* ----------------------------------------- */
	function SetDec( dec, idx )
	{
		var i = 0;

		if( (idx < 0 ) ||
		    ( idx >= this.idxMax ) )
		{
			return;
		}
		
		if( dec > 255 )
		{
			dec = 255;
		}
		else
		if( dec < 0 )
		{
			dec = 0;
		}

		this.dec[ idx ] = dec;
		this.code = "#";

		for( i = 0; i < this.idxMax; i ++ )
		{
			this.hex[ i ] = this.dec[ i ].toString( 16 );
			if( 1 == this.hex[ i ].length )
			{
				this.hex[ i ] = "0" + this.hex[ i ];
			}
			this.code += this.hex[ i ];
		}
	}

	/* ----------------------------------------- */
	/* 公開API：16進設定						 */
	/* ----------------------------------------- */
	function SetHex( hex, idx )
	{
		var i = 0;

		if( (idx < 0 ) ||
		    ( idx >= this.idxMax ) )
		{
			return;
		}

		if( null == hex.match( /#[0-9a-fA-F]{2}/ ) )
		{
			hex = "00";
		}

		this.hex[ idx ] = hex;
		this.code = "#";

		for( i = 0; i < this.idxMax; i ++ )
		{
			this.dec[ i ] = parseInt( this.hex[ i ], 16 );
			this.code += this.hex[ i ];
		}
	}

	/* ----------------------------------------- */
	/* 公開API：コード取得						 */
	/* ----------------------------------------- */
	function GetCode()
	{
		return ( this.code );
	}

	/* ----------------------------------------- */
	/* 公開API：10進数取得						 */
	/* ----------------------------------------- */
	function GetDec( idx )
	{
		var ret = 0;

		if( (idx < 0 ) ||
		    ( idx >= this.idxMax ) )
		{
			ret = 0;
		}
		else
		{
			ret = this.dec[ idx ];
		}
		
		return ret;
	}

	/* ----------------------------------------- */
	/* 公開API：16進数取得						 */
	/* ----------------------------------------- */
	function GetHex()
	{
		var ret = 0;

		if( (idx < 0 ) ||
		    ( idx >= this.idxMax ) )
		{
			ret = 0;
		}
		else
		{
			ret = this.hex[ idx ];
		}
		
		return ret;
	}

    Color.prototype.setCode = SetCode;
    Color.prototype.setDec  = SetDec;
    Color.prototype.setHex  = SetHex;
    Color.prototype.getCode = GetCode;
    Color.prototype.getDec  = GetDec;
    Color.prototype.getHex  = GetHex;

	this.code = "#000000";
	this.hex  = new Array( 0, 0, 0 );
	this.dec  = new Array( 0, 0, 0 );
	this.idxMax = 3;
	
	if( typeof( data ) == "undefined" )
	{
		data = "#000000";
	}

    this.setCode( data );
}

/* ------------------------------------------------------------------------- */
/* twitter記事オブジェクト */
function TweetData( data, idx )
{
	/* ----------------------------------------- */
	/* 入力オブジェクトdateのプロパティ			 */
	/* ----------------------------------------- */
	/* profile_image_url:	 					 */
	/* created_at:								 */
	/* from_user:								 */
	/* to_user_id:								 */
	/* text:	 								 */
	/* id:	 									 */
	/* from_user_id:							 */
	/* geo:										 */
	/* source:									 */
	/* ----------------------------------------- */

	function TextVisualLength( text )
	{
		text = text.replace( /(https?:\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi, "" );
		text = text.replace( /@([a-zA-Z0-9_]+)/gi, "" );
		text = text.replace( /#([a-zA-Z0-9_]+)/gi, "" );
		
		return text.length;
	}
	
	function FormatText( text )
	{
		text = text.replace( /(https?:\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi, "<a href=\"$1\">$1</a>" );
		text = text.replace( /@([a-zA-Z0-9_]+)/gi, "<a href=\"http://twitter.com/$1\">@$1</a>" );
		text = text.replace( /#([a-zA-Z0-9_]+)/gi, "<a href=\"http://twitter.com/search?q=%23$1\">#$1</a>" );
		
		return text;
	}

	function FormatTime( text )
	{
		var dt  = new Date();
		var now = new Date();
		var ret = "";

		dt.setTime( Date.parse( text ) );
		
		if( ( dt.getFullYear() == now.getFullYear() ) &&
		    ( dt.getMonth()    == now.getMonth()    ) &&
		    ( dt.getDate()     == now.getDate()     ) )
		{
			ret = "今日 " +
			      ZeroFill( dt.getHours(),     2 ) + ":"   +
			      ZeroFill( dt.getMinutes(),   2 );
		}
		else
		{
			ret = /* dt.getFullYear()                 + "年"  + */
			      ZeroFill( dt.getMonth() + 1, 2 ) + "月"  +
			      ZeroFill( dt.getDate(),      2 ) + "日 " +
			      ZeroFill( dt.getHours(),     2 ) + ":"   +
			      ZeroFill( dt.getMinutes(),   2 );
		}

		return ret;
	}
	
	function ZeroFill( num, digit )
	{
		var i = 0;
		var ret = num;
		
		if( num.toString().length < digit )
		{
			for( i = 0; i < ( digit - num.toString().length ); i ++ )
			{
				ret = "0" + ret;
			}
		}
		
		return ret;
	}

	/* ----------------------------------------- */
	/* 公開API：インデックス取得				 */
	/* ----------------------------------------- */
	function GetIdx()
	{
		return this.idx;
	}

	/* ----------------------------------------- */
	/* 公開API：整形済みテキスト取得			 */
	/* ----------------------------------------- */
	function GetText()
	{
		return this.text;
	}

	/* ----------------------------------------- */
	/* 公開API：整形済み日時取得				 */
	/* ----------------------------------------- */
	function GetTime()
	{
		return this.time;
	}

	/* ----------------------------------------- */
	/* 公開API：見た目のテキスト長取得			 */
	/* ----------------------------------------- */
	function GetLength()
	{
		return this.len;
	}

    TweetData.prototype.getIdx    = GetIdx;
    TweetData.prototype.getText   = GetText;
    TweetData.prototype.getTime   = GetTime;
    TweetData.prototype.getLength = GetLength;

	if( ( typeof( data ) == "undefined" ) ||
	    ( typeof( idx )  == "undefined" ) )
	{
		this.idx  = 0;
		this.text = "データがありません。";
		this.len  = TextVisualLength( this.text );
		this.time = "";
	}
	else
	{
		this.idx  = idx;
		this.text = FormatText( data.text );
		this.len  = TextVisualLength( data.text );
		this.time = FormatTime( data.created_at );
	}
}

/* ------------------------------------------------------------------------- */
/* twitter記事オブジェクト */
function Index( idx, len, dir )
{
	/* ----------------------------------------- */
	/* 公開API：長さ設定						 */
	/* ----------------------------------------- */
	function SetLen( len )
	{
		this.len = ( len > 0 ) ? len : 1;
		this.setIdx( this.idx );
	}

	/* ----------------------------------------- */
	/* 公開API：長さ取得						 */
	/* ----------------------------------------- */
	function GetLen()
	{
		return this.len;
	}

	/* ----------------------------------------- */
	/* 公開API：インデックス設定				 */
	/* ----------------------------------------- */
	function SetIdx( idx )
	{
		if( this.len <= idx )
		{
			idx = this.len - 1;
		}
		else
		if( 0 > idx )
		{
			idx = 0;
		}
		
		this.idx = idx;
	}

	/* ----------------------------------------- */
	/* 公開API：インデックス取得				 */
	/* ----------------------------------------- */
	function GetIdx()
	{
		return this.idx;
	}

	/* ----------------------------------------- */
	/* 公開API：方向設定						 */
	/* ----------------------------------------- */
	function SetDir( dir )
	{
		this.dir = ( true == dir ) ? true : false;
	}

	/* ----------------------------------------- */
	/* 公開API：方向取得						 */
	/* ----------------------------------------- */
	function GetDir()
	{
		return this.dir;
	}

	/* ----------------------------------------- */
	/* 公開API：方向取得						 */
	/* ----------------------------------------- */
	function Next()
	{
//		alert( "next" );
		this.idx = ( this.dir ) ? ( this.idx - 1 ) : ( this.idx + 1 );

		if( this.len <= this.idx )
		{
			this.idx = 0;
		}
		else
		if( 0 > this.idx )
		{
			this.idx = this.len - 1;
		}
	}

	/* ----------------------------------------- */
	/* 公開API：方向取得						 */
	/* ----------------------------------------- */
	function Prev()
	{
//		alert( "prev" );
		this.idx = ( this.dir ) ? ( this.idx + 1 ) : ( this.idx - 1 );

		if( this.len <= this.idx )
		{
			this.idx = 0;
		}
		else
		if( 0 > this.idx )
		{
			this.idx = this.len - 1;
		}
	}

    Index.prototype.setLen = SetLen;
    Index.prototype.getLen = GetLen;
    Index.prototype.setIdx = SetIdx;
    Index.prototype.getIdx = GetIdx;
    Index.prototype.setDir = SetDir;
    Index.prototype.getDir = GetDir;
    Index.prototype.next   = Next;
    Index.prototype.prev   = Prev;

	if( ( typeof( idx ) == "undefined" ) ||
	    ( typeof( len ) == "undefined" ) ||
	    ( typeof( dir ) == "undefined" ) )
	{
		this.setLen( 1 );
		this.setIdx( 0 );
		this.setDir( false );
	}
	else
	{
		this.setLen( len );
		this.setIdx( idx );
		this.setDir( dir );
	}
	
}

/* ------------------------------------------------------------------------- */

