/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.hayabusa.taglib;

import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.html.TabData;
import static org.opengion.fukurou.util.StringUtil.nval ;

/**
 * タブペインで、項目を分割して表示するタグのタブそのものを作成します。
 *
 * ※ データの大きさによってtabLink、tabList と使い分けてください。
 *
 * 一つの大きなHTMLを、タブを使用することで複数の塊に分割表示できます。
 * 分割された各タブは、一つのHTMLのため、タブ間の移動による情報の消失はありません。
 * また、一つのHTMLのため、タブにまたがって入力した値は、すべて 一括送信することも
 * 可能です。(Formタグで、全てのタブをまとめて記述していれば)
 * 個々のタブの指定は、この tab タグを使用します。
 * それらを、タブテーブル の BODY 部に記述します。タブは、記述された順番に、
 * 設定されます。
 * タブテーブル の BODY 部に記述するタブは、必ず一つ以上必要です。
 *
 * @og.formSample
 * ●形式：&lt;og:tabTable  ...  &gt;
 *             &lt;og:tab name="paGE1" lbl="page 1" &gt;
 *                    &lt;jsp:directive.include file="paGE1.jsp" /&gt;
 *             &lt;/og:tab&gt;
 *             &lt;og:tab name="page2" lbl="page 2" &gt;
 *                    &lt;jsp:directive.include file="page2.jsp" /&gt;
 *             &lt;/og:tab&gt;
 *         &lt;/og:tabTable &gt;
 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
 *
 * ●Tag定義：
 *   &lt;og:tab
 *       lbl                【TAG】ラベルリソースのラベルIDを指定します
 *       name                要素に対して固有の名前(id)をつける場合に設定します
 *       term               【廃止】処理する条件を指定します(初期値:null)
 *       termList           【廃止】処理する条件を含むような文字列を指定します
 *       delTerm            【廃止】処理しないタブを選択する条件を指定します(初期値:null)
 *       delTermList        【廃止】処理しない条件を含むような文字列を指定します
 *       style              【TAG】タブに与える 初期 style 属性を指定します
 *       keys               【廃止】タブが選択状態(OPEN選択タブ時)に使用するキーをCSV形式で複数指定します
 *       vals               【廃止】タブが選択状態(OPEN選択タブ時)に使用する値をCSV形式で複数指定します
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   &gt;   ... Body ...
 *   &lt;/og:tab&gt;
 *
 * ●使用例
 *  &lt;og:tabTable&gt;
 *    &lt;og:tab lbl="page 1"&gt;
 *      &lt;table summary="layout" &gt;
 *        &lt;tr&gt;
 *          &lt;og:column name="SYSTEM_ID" must="true" /&gt;
 *          &lt;og:column name="COLUMN_NAME" /&gt;
 *          &lt;og:column name="RENDERER"    /&gt;
 *        &lt;/tr&gt;
 *      &lt;/table&gt;
 *    &lt;/og:tab&gt;
 *    &lt;og:tab lbl="page 2"&gt;
 *      &lt;table summary="layout" &gt;
 *        &lt;tr&gt;
 *          &lt;og:column name="DBTYPE"      /&gt;
 *          &lt;og:column name="NAME_JA"     /&gt;
 *          &lt;og:column name="EDITOR"      /&gt;
 *        &lt;/tr&gt;
 *      &lt;/table&gt;
 *    &lt;/og:tab&gt;
 *  &lt;/og:tabTable&gt;
 *
 * @og.rev 3.5.6.5 (2004/08/09) 新規作成
 * @og.rev 5.9.1.3 (2015/10/30) jQuery方式に変更して復活(このタグはコメントの修正のみ)
 * @og.group 画面部品
 *
 * @version  4.0
 * @author	 Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class TabTag extends CommonTagSupport {
	//* このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "4.0.0.0 (2005/08/31)" ;

	private static final long serialVersionUID = 400020050831L ;

	private String text = null;
	private String name = null;
	private String body = null;
	private String style = null;	// 3.8.6.1 (2006/10/24)

	private String[] keys		= null;		// 3.8.6.2 (2006/11/01)
	private String[] vals		= null;		// 3.8.6.2 (2006/11/01)
	private Object[] backVals	= null;		// 3.8.6.2 (2006/11/01)

	// 3.8.6.1 (2006/10/20)
	private String	term		= null;
	private String	termList	= null;
	private String	delTerm		= null;
	private String	delTermList	= null;
	private boolean	isOpen		= false;		// term    が termList    に含まれている場合 true
	private boolean	isDelete	= false;		// delTerm が delTermList に含まれている場合 true
	private TabTableTag tabTable = null;

	/**
	 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
	 *
	 * @og.rev 3.8.6.2 (2006/11/01) keys,vals属性の処理を追加
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doStartTag() {
		tabTable = (TabTableTag)findAncestorWithClass( this,TabTableTag.class );
		// isSelected の判断は、OPEN/DELETE 関係なく、タブの数だけ実行する必要がある。
		if( tabTable != null ) {
			isOpen = tabTable.isSelected();
		}
		else {
			String errMsg = "tabTable タグの BODY部で使用してください。";
			throw new HybsSystemException( errMsg );
		}

		// del条件リストに存在する場合は、DELETE選択タブとして認識される。
		isDelete = ( delTermList != null && delTerm != null && delTermList.indexOf( delTerm ) >= 0 ) ;
		if( isDelete ) { return(SKIP_BODY); }			// Body を評価しない

		// isSelected の判断 が優先される。
		if( !isOpen ) {
			// 条件リストに存在する場合は、OPEN選択タブとして認識される。
			isOpen = ( termList != null && term != null && termList.indexOf( term ) >= 0 ) ;
		}

		// keys変数の元の値の退避とvals 値の設定。
		if( isOpen && keys != null && keys.length > 0 ) {
			int size = keys.length;
			backVals = new Object[size];
			for( int i=0; i<size; i++ ) {
				String key = keys[i];
				if( key != null && key.length() > 0 ) {
					backVals[i] = getRequestAttribute( key );
					setRequestAttribute( key,vals[i] );
				}
			}
		}

		return( EVAL_BODY_BUFFERED );	// Body を評価する。( extends BodyTagSupport 時)
	}

	/**
	 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
	 *
	 * @return	後続処理の指示(SKIP_BODY)
	 */
	@Override
	public int doAfterBody() {
		body = getBodyString();
		return(SKIP_BODY);
	}

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 *
	 * @og.rev 3.8.6.1 (2006/10/20) term、termList、action属性を追加
	 * @og.rev 3.8.6.2 (2006/11/01) keys,vals属性の処理を追加
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();		// 4.0.0 (2005/02/28)
		if( !isDelete ) {
			// keys変数の元の値の戻し。
			if( isOpen && keys != null && keys.length > 0 ) {
				int size = keys.length;
				for( int i=0; i<size; i++ ) {
					String key = keys[i];
					if( key != null && key.length() > 0 ) {
						if( backVals[i] != null ) {
							setRequestAttribute( key,backVals[i] );
						}
						else {
							removeRequestAttribute( key );
						}
					}
				}
			}

			text = getMsglbl();

			TabData tab = new TabData( text,name,body,isOpen,style );
			tabTable.addTabData( tab );
		}
		return(EVAL_PAGE);
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 *
	 * @og.rev 3.8.6.1 (2006/10/20) term、termList、action属性を追加
	 * @og.rev 3.8.6.2 (2006/11/01) keys, vals, isOpen, delTerm, delTermList 属性を追加
	 */
	@Override
	protected void release2() {
		super.release2();
		text		= null;
		name		= null;
		body		= null;
		term		= null;
		termList	= null;
		delTerm		= null;
		delTermList	= null;
		style		= null;
		keys		= null;		// 3.8.6.2 (2006/11/01)
		vals		= null;		// 3.8.6.2 (2006/11/01)
		isOpen		= false;	// 3.8.6.2 (2006/11/01)
		isDelete	= false;	// 3.8.6.2 (2006/11/01)
		tabTable	= null;
	}

	/**
	 * 【廃止】要素に対して固有の名前(id)をつける場合に設定します。
	 *
	 * @og.tag 名前セット
	 * 
	 * @og.rev 5.9.1.3 (2015/10/30) 復活
	 *
	 * @param   name 名前
	 */
	public void setName( final String name ) {
		this.name = getRequestParameter( name );
	}

	/**
	 * 【廃止】処理する条件を指定します(初期値:null)。
	 *
	 * @og.tag
	 * termListで与えられた文字列に、term文字列(大文字/小文字の区別あり)が
	 * 含まれていれば、OPEN選択タブとして処理します。
	 * OPEN選択タブでないタブは、初期値OPENにならないだけで、タブそのものは表示されます。
	 * OPEN選択とDELETE選択が競合した場合は、DELETE選択が優先されます。
	 * 初期値は、 null です。
	 *
	 * @og.rev 3.8.6.1 (2006/10/20) 新規追加
	 *
	 * @param	flag 処理する条件
	 * @deprecated クラスが廃止されました。
	 */
	@Deprecated public void setTerm( final String flag ) {
		term = nval( getRequestParameter( flag ),term );
	}

	/**
	 * 【廃止】処理する条件を含むような文字列を指定します。
	 *
	 * @og.tag
	 * termListで与えられた文字列に、term文字列(大文字/小文字の区別あり)が
	 * 含まれていれば、OPEN選択タブとして処理します。
	 * 例えば、"A","B","C" という文字列が、term で指定された
	 * 場合に処理するようにしたい場合は、"A|B|C" をセットします。
	 * 初期値は、 null です。
	 * 判定は、文字列を含むかどうかなので、１文字のみの場合は、"|"区切りにする
	 * 必要はありません。
	 * OPEN選択とDELETE選択が競合した場合は、DELETE選択が優先されます。
	 *
	 * @og.rev 3.8.6.1 (2006/10/20) 新規追加
	 *
	 * @param	list 処理する条件(indexOf による含む/含まない判定)
	 * @deprecated クラスが廃止されました。
	 */
	@Deprecated public void setTermList( final String list ) {
		termList = nval( getRequestParameter( list ),termList );
	}

	/**
	 * 【廃止】処理しないタブを選択する条件を指定します(初期値:null)。
	 *
	 * @og.tag
	 * delTermListで与えられた文字列に、delTerm文字列(大文字/小文字の区別あり)が
	 * 含まれていれば、DELETE選択タブとして処理します。
	 * DELETE選択タブは、タブそのものが表示されません。
	 * ただし、タブのselectIndex は、DELETEされたタブも含めて、カウントされますので、
	 * JSPでの設定時の順番がインデックス番号になります。
	 * OPEN選択とDELETE選択が競合した場合は、DELETE選択が優先されます。
	 * 初期値は、 null です。
	 *
	 * @og.rev 3.8.6.2 (2006/11/01) 新規追加
	 *
	 * @param	flag DELETE選択タブ条件
	 * @deprecated クラスが廃止されました。
	 */
	@Deprecated public void setDelTerm( final String flag ) {
		delTerm = nval( getRequestParameter( flag ),delTerm );
	}

	/**
	 * 【廃止】処理しない条件を含むような文字列を指定します。
	 *
	 * @og.tag
	 * delTermListで与えられた文字列に、delTerm文字列(大文字/小文字の区別あり)が
	 * 含まれていれば、DELETE選択タブとして処理します。
	 * 例えば、"A","B","C" という文字列が、delTerm で指定された
	 * 場合に処理しないようにしたい場合は、"A|B|C" をセットします。
	 * 初期値は、 null です。
	 * 判定は、文字列を含むかどうかなので、１文字のみの場合は、"|"区切りにする
	 * 必要はありません。
	 * OPEN選択とDELETE選択が競合した場合は、DELETE選択が優先されます。
	 *
	 * @og.rev 3.8.6.2 (2006/11/01) 新規追加
	 *
	 * @param	list DELETE選択タブ条件文字列(indexOf による含む/含まない判定)
	 */
	@Deprecated public void setDelTermList( final String list ) {
		delTermList = nval( getRequestParameter( list ),delTermList );
	}

	/**
	 * 【廃止】タブに与える 初期 style 属性を指定します。
	 *
	 * @og.tag
	 * ts:tab 本体では、初期選択時のスタイルシートを、defaultStyle と
	 * selectedStyle で与える必要があります。これは、id 属性を設定して、
	 * 外部でスタイルシートを定義する形式で指定できません。
	 * ここで指定した style 属性 は、tabTableTag で与える style 属性 より優先度は
	 * 高くなります。
	 * ここでの style は、タブの OPEN選択には関係ありません。
	 *
	 * @og.rev 3.8.6.1 (2006/10/24) 新規追加
	 *
	 * @param	st タブに与える 初期 style 属性
	 * @deprecated クラスが廃止されました。
	 */
	@Deprecated public void setStyle( final String st ) {
		style = nval( getRequestParameter( st ),style );
	}

	/**
	 * 【廃止】タブが選択状態(OPEN選択タブ時)に使用するキーをCSV形式で複数指定します。
	 *
	 * @og.tag
	 * タブのBODY内部でのみ有効なscope="request"変数を定義できます。
	 * 条件は、term、termList によるOPEN選択タブ時にのみ指定のタブの
	 * BODY部内のみに有効になります。
	 * タブの前に設定されている scope="request"変数 は退避され、BODY部が
	 * 終了した時点で、元の変数に値が戻されます。
	 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
	 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
	 *
	 * @og.rev 3.8.6.2 (2006/11/01) 新規追加
	 *
	 * @param	key キー(CSV形式)
	 * @deprecated クラスが廃止されました。
	 */
	@Deprecated public void setKeys( final String key ) {
		keys = getCSVParameter( key );
	}

	/**
	 * 【廃止】タブが選択状態(OPEN選択タブ時)に使用する値をCSV形式で複数指定します。
	 *
	 * @og.tag
	 * タブのBODY内部でのみ有効なscope="request"変数を定義できます。
	 * 条件は、term、termList によるOPEN選択タブ時にのみ指定のタブの
	 * BODY部内のみに有効になります。
	 * タブの前に設定されている scope="request"変数 は退避され、BODY部が
	 * 終了した時点で、元の変数に値が戻されます。
	 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
	 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
	 *
	 * @param	val 値(CSV形式)
	 * @deprecated クラスが廃止されました。
	 */
	@Deprecated public void setVals( final String val ) {
		vals = getCSVParameter( val );
	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 *
	 * @return このクラスの文字列表現
	 */
	@Override
	public String toString() {
		return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
				.println( "VERSION"		,VERSION	)
				.println( "text"		,text		)
				.println( "name"		,name		)
				.println( "body"		,body		)
				.println( "term"		,term		)
				.println( "termList"	,termList	)
				.println( "Other..."	,getAttributes().getAttribute() )
				.fixForm().toString() ;
	}
}
