var Expander = Class.create();
Expander.prototype = {
	targetElem: null,
	contentElem: null,
	openBtn: null,
	closeBtn: null,
	params: null,
	status: null,
	openHandlerCache: null,
	closeHandlerCache: null,
	
	initialize: function($wrapper, $param){
		//コンテンツ、heightを変更するターゲット、ボタン類を包むwrapperを取得
		if($wrapper == null) return;
		$wrapper = jQuery($wrapper)

		//パラメータの設定
		this.params = jQuery.extend(
			{
				openSpeed:1000,　					//開くスピード (openSpeed+"ms" かけて広がる)
				closeSpeed:1000,　					//開くスピード (closeSpeed+"ms"かけて広がる)
				openBtnClassName: "expanderOpen",	//取得するopenボタンのクラス名
				closeBtnClassName: "expanderClose",	//取得するcloseボタンのクラス名
				targetClassName: "expanderTarget",	//開閉ターゲットのクラス名
				contentClassName: "expanderContent", //表示するコンテンツのクラス名
				maxSize: -1,　//どこまで広がるか。デフォルトはコンテンツの高さ (-1はダミー。-1のままなら後にデフォルト値に変更)
				minSize: -1, //どこまで閉じるか。デフォルトはCSSで定義したターゲットの高さ。　(-1はダミー。-1のままなら後にデフォルト値に変更)
				switchBtn: true,					//閉じるボタンと開くボタンの表示を切り替えるかどうか
				initialStatus: "close",				//初期状態
				custom:{ 
						open:{queue: false, handler: null}, //開く時にほかの関数を実行するかどうか。qeue: trueでexpandが終わったら実行。falseで同時に実行
						close:{uqeue: true, handler: null} 　//閉じる時にほかの関数を実行するかどうか。qeue: trueでexpandが終わったら実行。falseで同時に実行
						}
			}, ( $param || {} )
		);
		
		//コンテンツとターゲットの取得
		( $wrapper.hasClass(this.params.targetClassName) ) 	
			? this.targetElem = $wrapper
			: this.targetElem = $wrapper.find("."+this.params.targetClassName+":first");
		
		this.contentElem = $wrapper.find("."+this.params.contentClassName+":first");
		if(this.targetElem.size() == 0 || this.contentElem.size() == 0) return;
		
		this.targetElem.css({overflow: "hidden", zIndex: 9999});

		//maxSizeとminSizeのデフォルト値の設定
		if(this.params.maxSize == -1)
			this.params.maxSize = this.contentElem.outerHeight({margin:true});
		if(this.params.minSize == -1)
			this.params.minSize = this.targetElem.height();
		
		//ボタン類の取得
		($wrapper.hasClass(this.params.openBtnClassName) == true)
			? this.openBtn = $wrapper
			: this.openBtn =  $wrapper.find("."+this.params.openBtnClassName+":first");
		
		($wrapper.hasClass(this.params.closeBtnClassName) == true)
			? this.closeBtn = $wrapper
			: this.closeBtn =  $wrapper.find("."+this.params.closeBtnClassName+":first");
		
		if(this.openBtn.size() == 0 || this.closeBtn.size() == 0) return;
		
		//ボタン押下時のイベントハンドラをキャッシュ登録
		this.openHandlerCache = jQuery.proxy(this.openHandler, this);
		this.closeHandlerCache = jQuery.proxy(this.closeHandler, this);
		
		//初期状態の設定
		this.status = this.params.initialStatus;
		
		//初期状態に応じてボタンの表示、及びイベント登録
		if (this.status == "open") {
			this.showCloseBtn();
			this.closeBtn.bind("click", this.closeHandlerCache);
		}else if (this.status == "close") {
			this.showOpenBtn();
			this.openBtn.bind("click", this.openHandlerCache);
		}
	}, //constructor
	
	openHandler: function(event){
		event.stopPropagation();
		this.open( this.params.maxSize );
		this.showCloseBtn()	
		this.openBtn.unbind("click", this.openHandlerCache );
		this.closeBtn.bind("click", this.closeHandlerCache );
		this.status = "open";
	},

	open: function($targetSize){
		var $opts = {duration: this.params.openSpeed, complete: null}
		if( this.params.custom.open.handler == null || this.params.custom.open.queue == true ){
			$opts.complete = this.params.custom.open.handler;
			this.targetElem.animate( {height: $targetSize + "px"}, $opts);
		}else{
			this.targetElem.animate( {height: $targetSize + "px"}, $opts);
			this.params.custom.open.handler();
		}
		return false;
	},

	closeHandler: function(event){
		event.stopPropagation();
		this.close( this.params.minSize );
		this.showOpenBtn();
		this.closeBtn.unbind( "click", this.closeHandlerCache );
		this.openBtn.bind( "click", this.openHandlerCache );
		this.status = "close";
	},
	
	close: function($targetSize){
		var $opts = {duration: this.params.closeSpeed, complete: null}
		if( this.params.custom.close.handler == null || this.params.custom.close.queue == true ){
			$opts.complete = this.params.custom.close.handler;
			this.targetElem.animate( {height: $targetSize + "px"}, $opts);
		}else{
			this.targetElem.animate( {height: $targetSize + "px"}, $opts);
			this.params.custom.close.handler();
		}
		return false;
	},
		
	showOpenBtn: function(){
		if(this.params.switchBtn == true){
			this.closeBtn.hide();
			this.openBtn.show();
		}
	},
	
	showCloseBtn: function(){
		if (this.params.switchBtn == true){
			this.openBtn.hide();
			this.closeBtn.show();
		}
	},
	
	//要素の配列を受け取って、引数のパラメータでインスタンス化するa
	initAll : function($elem, $params, $array){
		if($array == null || typeof $array == undefined)
			var $array = new Array();
			
		for(var $i=0; $i < $elem.length; $i++){
			$array.push( new Expander($elem[$i], $params) )
		}
		return $array;
	}
}//Expander
