/**
 * wrapperのクラス入れ替えJS
 * jquery.swapwrapperclass.js
 * ver 1.3
 *
 * triger（操作もと）の操作（click、mouseover、mouseoutなど）に応じて、
 * wrapper（枠組み）に対して、特定のクラスの入れ替え、追加、削除を実行する
 *
 * デフォルトの挙動
 *   a.swap_wrapper_classのクリック時に、href属性にて指定されるidを持つエレメントのclassを
 *   rel属性で指定されているclass名に入れ替える
 *
 * オプションパラメータ
 *   wrapper:
 *     wrapperの取得
 *     this=トリガ
 *     デフォルト=href属性のid指定、または、親
 *   wrapperClass:
 *     wrapperに追加されるクラスの取得
 *     this=トリガ
 *     デフォルト=rel属性値
 *   swapEvent:
 *     classを入れ替えるイベント
 *     デフォルト="click"
 *   addEvent:
 *     classを追加するイベント
 *     デフォルト=undefined
 *   removeEvent:
 *     classを除去するイベント
 *     デフォルト=undefined
 *   beforeSwap:
 *     class入れ替え前の処理
 *     return falseで停止
 *     デフォルト=undefined
 *   afterSwap:
 *     class入れ替え後の処理
 *     デフォルト=undefined
 *   beforeAdd:
 *     class追加前の処理
 *     return falseで停止
 *     デフォルト=undefined
 *   afterAdd:
 *     class追加後の処理
 *     デフォルト=undefined
 *   beforeRemove:
 *     class除去前の処理
 *     return falseで停止
 *     デフォルト=undefined
 *   afterRemove:
 *     class除去後の処理
 *     デフォルト=undefined
 *
 * その他備考
 *   クラスの入れ替え、追加、削除の前後に処理を実行（引数[$self, $wrapper, wrapperClasses, index]）
 *   クラスの入れ替え、追加、削除の前処理にて、falseを返すと処理停止
 *   クラスの入れ替え、追加、削除の前後の処理は、それぞれ独立して指定
 *
 * 例）
 *   クリックで入れ替え
 *     swapEvent: "click", removeEvent: undefined
 *   マウスオーバーで入れ替え（マウスアウトでも削除する）
 *     swapEvent: "mouseover", removeEvent: "mouseout"
 *   マウスオーバーで入れ替え（マウスアウトでは削除しない）
 *     swapEvent: "mouseover", removeEvent: undefined
 * 
 */
(function($){
	//wrapperクラス入れ替え
	$.fn.swapWrapperClass = function(options){
		//存在しない場合は終了
		if(!this) return this;

		//トリガ
		var $self = this;

		//イベント指定時、データ格納時のnamespace
		var nameSpace = "swapWrapperClass";

		//オプション拡張
		options = $.extend({}, $.fn.swapWrapperClass.defaults, options, true);
		//wrapperに追加するクラスの配列
		var wrapperClasses = [];
		
		$self.each(
			function(index){
				//wrapperに追加するクラス取得
				var wrapperClass;
				if($.isFunction(options.wrapperClass)){
					wrapperClass = options.wrapperClass.apply(this);
				}
				else{
					wrapperClass = options.wrapperClass;
				}
				//wrapperに追加するクラスを配列にセット
				wrapperClasses[index]=wrapperClass;
			}
		);

		//トリガを走査
		return $self.each(
			function(index){
				var $trigger = $(this);
				//wrapper取得
				var $wrapper;
				if($.isFunction(options.wrapper)){
					$wrapper = options.wrapper.apply(this);
				}
				else{
					$wrapper = $(options.wrapper);
				}
				var callbackArg = [$self, $wrapper, wrapperClasses, index];
				
				//トリガのイベント設定
				//classを追加するイベント
				if(options.addEvent)
				{
					$trigger.bind(
						options.addEvent + "." + nameSpace,
						function(evnt){
							if(options.beforeAdd == undefined || $.isFunction(options.beforeAdd) && options.beforeAdd.apply(this, callbackArg)){
								//wrapperにクラスを追加
								$wrapper.addClass(wrapperClasses[index]);
								if($.isFunction(options.afterAdd)){
									options.afterAdd.apply(this, callbackArg);
								}
							}
							evnt.preventDefault();
							return false;
						}
					);
				}
				//classを除去するイベント
				if(options.removeEvent)
				{
					$trigger.bind(
						options.removeEvent + "." + nameSpace,
						function(evnt){
							if(options.beforeRemove == undefined || $.isFunction(options.beforeRemove) && options.beforeRemove.apply(this, callbackArg)){
								//wrapperから追加されるクラスを一度全て削除
								$wrapper.removeClass(wrapperClasses.join(" "));
								if($.isFunction(options.afterRemove)){
									options.afterRemove.apply(this, callbackArg);
								}
							}
							evnt.preventDefault();
							return false;
						}
					);
				}
				//classを入れ替えるイベント
				if(options.swapEvent)
				{
					$trigger.bind(
						options.swapEvent + "." + nameSpace,
						function(evnt){
							if(options.beforeSwap == undefined || $.isFunction(options.beforeSwap) && options.beforeSwap.apply(this, callbackArg)){
								//追加する前にwrapperから追加されるクラスを一度全て削除
								$wrapper.removeClass(wrapperClasses.join(" "));
								//対象のクラスを追加
								$wrapper.addClass(wrapperClasses[index]);
								if($.isFunction(options.afterSwap)){
									options.afterSwap.apply(this, callbackArg);
								}
							}
							evnt.preventDefault();
							return false;
						}
					);
				}
			}
		);
	};

	//wrapperクラス入れ替えのデフォルト設定
	$.fn.swapWrapperClass.defaults = {
		//wrapperの取得（this=トリガ）
		wrapper: function(){
			//hrefのid指定
			var href, wrapper, $this = $(this);
			return ( href = $this.attr("href")) && (wrapper = $(href)) ?
				wrapper:
				undefined;
		},
		//wrapperに追加されるクラスの取得（this=トリガ）
		wrapperClass: function(){
			//relの値
			var rel, $this = $(this);
			return ( rel = $this.attr("rel")) ?
				rel:
				undefined;
		},
		//classを入れ替えるイベント
		swapEvent: "click",
		//classを追加するイベント
		addEvent: undefined,
		//classを除去するイベント
		removeEvent: undefined,
		//class入れ替え前の処理（falseで停止）
		beforeSwap: undefined,
		//class入れ替え後の処理
		afterSwap: undefined,
		//class追加前の処理（falseで停止）
		beforeAdd: undefined,
		//class追加後の処理
		afterAdd: undefined,
		//class除去前の処理（falseで停止）
		beforeRemove: undefined,
		//class除去後の処理
		afterRemove: undefined
	};

	//初期動作
	$(function(){
		$("a.swap_wrapper_class").swapWrapperClass();
	});
})(jQuery);
