/*--------------------------------------------------------------------------*
 *  
 *  EventManager jQuery Plugin beta1
 *  
 *  tested with jQuery 1.3.2
 *  
 *  MIT-style license. 
 *  
 *  December 8th , 2009 Written by Koji Kimura @ STARRYWORKS inc. http://www.starryworks.co.jp/
 *  
 *--------------------------------------------------------------------------*/


/*

簡易Document

--------------------------------------------------

registerEventSet( i_name, i_object )

引数で指定された名前とオブジェクトを元にイベントの状態を保存する。

【戻り値】
jQueryオブジェクト

【引数】
i_types:String	ユニークなキーとなる名前
i_object:Object	イベントハンドラの配列をイベントのタイプをキーにして格納したオブジェクト

--------------------------------------------------

saveEventSet( i_name )

引数で指定された名前で現在登録されているイベントの状態を保存する。

【戻り値】
jQueryオブジェクト

【引数】
i_types:String	ユニークなキーとなる名前

--------------------------------------------------

loadEventSet( i_name )

引数で指定された名前で保存されたイベントの状態をロードする。

【戻り値】
jQueryオブジェクト

【引数】
i_types:String	ユニークなキーとなる名前

--------------------------------------------------

clearEventSet( [ i_names ] )

引数で指定された名前で保存されたイベントの状態のデータを削除

【戻り値】
jQueryオブジェクト

【引数】
i_names:String	削除するデータのキー。省略すると全てのデータを削除。

--------------------------------------------------

saveEvents( [ i_types ], [ i_returnIfEmpty ] )

引数で渡されたタイプのイベントをすべて保存する。

【戻り値】
jQueryオブジェクト

【引数】
i_types:String	イベントのタイプ（スペースで区切って複数指定可能）。省略すると全てのタイプのイベントが保存される。

--------------------------------------------------

stopEvents( [ i_types ] )

引数で渡されたタイプのイベントをすべて保存して一時停止する。

【戻り値】
jQueryオブジェクト

【引数】
i_types:String	イベントのタイプ（スペースで区切って複数指定可能）。省略すると全てのタイプのイベントを一時停止する。

--------------------------------------------------

resumeEvents( [ i_types ] )

保存されている引数で渡されたタイプのイベントをすべて再バインドする。

【戻り値】
jQueryオブジェクト

【引数】
i_types:String	イベントのタイプ（スペースで区切って複数指定可能）省略すると全てのタイプのイベントを再バインドする。

--------------------------------------------------

getEvents( [ i_types ] )

引数で渡されたタイプのイベントをすべてオブジェクトとして返す。

【戻り値】
Object			イベントハンドラの配列をイベントのタイプをキーにして格納したオブジェクト

【引数】
i_types:String	イベントのタイプ（スペースで区切って複数指定可能）。省略すると全てのタイプのイベントを取得する。

--------------------------------------------------

bindEvents( [ i_object ] )

getEventsで取得した形式のオブジェクトを元にイベントをバインドする。

【戻り値】
jQueryオブジェクト

【引数】
i_object:Object	イベントハンドラの配列をイベントのタイプをキーにして格納したオブジェクト

--------------------------------------------------

clearSavedEvents( [ i_types ] ) {

保存されたイベントを削除する。

【戻り値】
jQueryオブジェクト

【引数】
i_types:String	イベントのタイプ（スペースで区切って複数指定可能）。省略すると全てのタイプの保存されたイベントを削除する。

--------------------------------------------------

*/


(function(){
	
	//stopEventsが２回連続実行されると空になってしまうのを防ぐためのフラグ
	var stopped = false;
	
	/*--------------------------------------------------
	* 関数
	--------------------------------------------------*/
	
	//配列内に値が存在するかチェック
	function containsInArray( i_array, i_value ) {
		for(var i in i_array){
			if( i_array.hasOwnProperty(i) && i_array[i] === i_value ) return true;
	    }
	    return false
	}
	
	//配列やスペース区切りの文字列などで渡される引数を配列に変換
	function splitArgument( i_arg ) {
		if ( typeof(i_arg) == "array" ) return i_arg;
		return ( typeof(i_arg) == "string" ) ? (i_arg+"").split(/ ,/) : [];
	}
	
	//オブジェクトのインデックスを配列に
	function getKeysInObject( i_object ) {
		var returnArray = [];
		for ( var i in i_object ) returnArray.push(i);
		return returnArray;
	}
	
	//リンクを無効に
	function disableLink() { return false; }
	
	/*--------------------------------------------------
	* 引数で指定された名前とオブジェクトを元にイベントの状態を登録する
	--------------------------------------------------*/
	$.fn.registerEventSet = function( i_name, i_object ){
		
		//保存されているデータを取得
		var stat = $(this).data("eventSets");
		if ( typeof(stat) == "undefined" ) stat = {};
		
		//バインドされているイベントを取得
		stat[i_name] = i_object;
		
		//保存
		$(this).data("eventSets", stat );
		
		return $(this);
	}
	
	
	/*--------------------------------------------------
	* 引数で指定された名前で現在登録されているイベントの状態を保存する
	--------------------------------------------------*/
	$.fn.saveEventSet = function( i_name ){
		return $(this).registerEventSet( i_name, $(this).getEvents() );
	}
	
	/*--------------------------------------------------
	* 引数で指定された名前で保存されたイベントの状態をロードする
	--------------------------------------------------*/
	$.fn.loadEventSet = function( i_name ){
		
		//保存されているデータを取得
		var stat = $(this).data("eventSets");
		if ( typeof(stat) == "undefined" || typeof(stat[i_name]) == "undefined" ) return;
		
		//バインドされているイベントを全てアンバインド
		$(this).unbind();
		
		//イベントを再度バインドする
		$(this).bindEvents( stat[i_name] );
		
		return $(this);
	}
	
	
	/*--------------------------------------------------
	* 引数で指定された名前で保存されたイベントの状態のデータを削除
	--------------------------------------------------*/
	$.fn.clearEventSet = function( i_names ){
		
		//i_namesが省略された場合全て削除
		if ( !i_names ) {
			$(this).data("eventSets",{});
			return;
		}
		
		//保存されているデータを取得
		var stat = $(this).data("eventSets");
		if ( typeof(stat) == "undefined" ) return;
		
		//削除
		var names = splitArgument( i_names );
		for ( var n in names ) {
			if ( typeof(stat[n]) != "undefined" ) stat[n] = {};
		}
		
		return $(this);
	}
	
	
	/*--------------------------------------------------
	* 引数で渡されたタイプのイベントをすべて保存する
	--------------------------------------------------*/
	$.fn.saveEvents = function( i_types, i_returnIfEmpty ){
		
		//バインドされているイベントを取得
		var events = $(this).getEvents( i_types );
		
		//i_returnIfEmptyがtrueの場合はバインドされているイベントがなければ保存しない
		if ( !i_types && i_returnIfEmpty ) {
			//ハンドラがバインドされているイベントの数をカウント
			var cnt = 0;
			var type, inner_cnt, i;
			for ( type in events ) {
				inner_cnt = 0;
				for ( i in events[type] ) {
					inner_cnt++;
					break;
				}
				if ( inner_cnt ) cnt++;
			}
			if ( !cnt ) return;
		}
		
		//保存されたイベントを取得
		var savedEvents = {};
		if ( i_types ) savedEvents = $(this).data("savedEvents");
		
		//保存
		$(this).data("savedEvents", $.extend(events, savedEvents) );
		
		return $(this);
	}
	
	
	/*--------------------------------------------------
	* 引数で渡されたタイプのイベントをすべて一時停止する
	--------------------------------------------------*/
	$.fn.stopEvents = function( i_types, i_enableLink ){
		if ( i_types || !stopped ) $(this).saveEvents( i_types );
		if ( !i_types ) {
			if ( !stopped ) $(this).unbind();
			stopped = true;
			//タイプ指定がない場合、<A>が動作しないようにする
			if ( !i_enableLink ) $(this).bind("click",disableLink );
		} else {
			$(this).unbind( i_types );
		}
		return $(this);
	}
	
	/*--------------------------------------------------
	* 引数で渡されたタイプのイベントをすべて再バインドする
	--------------------------------------------------*/
	$.fn.resumeEvents = function( i_types ){
		if ( !i_types && !stopped ) {
			return $(this);
		}
		
		stopped = false;
		
		$(this).unbind("click",disableLink );
		
		var savedEvents = $(this).data("savedEvents");
		
		
		//イベントのタイプの引数チェック
		var typesArray = splitArgument( i_types );
		
		//タイプが指定された場合はtypesArrayの中にあるものだけを
		if ( typesArray.length ) {
			var _savedEvents = savedEvents;
			savedEvents = {};
			var type, i;
			for ( i in typesArray ) {
				type = typesArray[i];
				if ( typeof(_savedEvents[type]) == "undefined" ) continue;
				savedEvents[type] = _savedEvents[type];
			}
		}
		
		//イベントを再度バインドする
		$(this).bindEvents( savedEvents );
		
		return $(this);
	}
	
	/*--------------------------------------------------
	* 引数で渡されたタイプのイベントをすべてオブジェクトとして返す
	--------------------------------------------------*/
	$.fn.getEvents = function( i_types ){
		
		//バインドされているイベント
		var events = $(this).data("events");
		
		//イベントのタイプの引数チェック
		var typesArray = splitArgument( i_types );
		
		//イベントがひとつもbindされておらず、i_typesの指定がない場合
		if ( !events && !typesArray.length ) return {};
		
		//保存されたイベントを取得
		var returnObject = {};
		
		//タイプが省略された場合はeventsの中にあるもの全部
		if ( !typesArray.length ) typesArray = getKeysInObject( events );
		
		//イベントを走査
		var type, key, i;
		for ( var i in typesArray ) {
			type = typesArray[i];
			if ( typeof(events[type]) == "undefined" ) continue;
			if ( typeof(returnObject[type]) == "undefined" ) returnObject[type] = [];
			for ( key in events[type] ) {
				if ( !containsInArray(returnObject[type], events[type][key]) ) {
					returnObject[type].push( events[type][key] );
				}
			}
		}
		
		return returnObject;
	}
	
	/*--------------------------------------------------
	* オブジェクトを元にイベントをバインド
	--------------------------------------------------*/
	$.fn.bindEvents = function( i_object ) {
		var i, type;
		for ( var type in i_object ) {
			if ( typeof(i_object[type]) == "function" ) {
				$(this).bind( type, i_object[type] );
				continue;
			}
			for ( i in i_object[type] ) {
				$(this).bind( type, i_object[type][i] );
			}
		}
		return $(this);
	};
	
	/*--------------------------------------------------
	* 保存されたイベントを削除
	--------------------------------------------------*/
	$.fn.clearSavedEvents = function( i_types ) {
		
		//イベントのタイプの引数チェック
		var typesArray = splitArgument( i_types );
		
		//すべてのイベントを削除する場合
		if ( !typesArray.length ) {
			$(this).data("savedEvents", {});
			return;
		}
		
		//保存されたイベントを取得
		var savedEvents = $(this).data("savedEvents");
		if ( typeof(savedEvents) == "undefined") return;
		
		//イベントを走査
		var type, key, i;
		for ( var i in typesArray ) {
			type = typesArray[i];
			if ( typeof(savedEvents[type]) != "undefined" ) savedEvents[type] = {};
		}
		
		return $(this);
	}

})();
