/*
 * 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.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.hayabusa.db.DBColumn;
import org.opengion.hayabusa.db.Query;
import org.opengion.hayabusa.db.QueryFactory;
import org.opengion.fukurou.util.XHTMLTag;
import org.opengion.fukurou.util.Attributes;
import org.opengion.fukurou.util.ToString;						// 6.1.1.0 (2015/01/17)
import org.opengion.fukurou.db.Transaction;
// import org.opengion.fukurou.db.TransactionReal;

import static org.opengion.fukurou.util.StringUtil.nval ;

// import java.io.ObjectOutputStream;
// import java.io.ObjectInputStream;
// import java.io.IOException;

/**
 * プルダウンメニューの選択項目をSELECT文の結果から作成するタグです。
 *
 * 基本的には、ｑueryタグと同じ使い方をします。
 * このオブジェクトに、 queryId を与えることにより、queryId に対応した Queryオブジェクト
 * (のサブクラスのオブジェクト)が作成されます。
 * ここで指定するSELECT文は、『SELECT KEY、LABEL1、LABEL2、･･･ FROM TABLE ･･･』形式 を
 * している必要があります。特別なケースとして、『SELECT KEY FROM TABLE ･･･』形式の場合は、
 * LABEL に KEY が 使用されます。
 * SystemData の USE_SQL_INJECTION_CHECK が true か、quotCheck 属性が true の場合は、
 * ＳＱＬインジェクション対策用のシングルクォートチェックを行います。リクエスト引数に
 * シングルクォート(')が含まれると、エラーになります。
 * 同様にUSE_XSS_CHECKがtrueか、xssCheck属性がtrueの場合は、
 * クロスサイトススクリプティング(XSS)対策のためless/greater than signのチェックを行います。
 *
 * ※ このタグは、Transaction タグの対象です。
 *
 * @og.formSample
 * ●形式：
 *     &lt;og:queryOption &gt;
 *          SELECT文 
 *     &lt;/og:queryOption &gt;
 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
 *
 * ●Tag定義：
 *   &lt;og:queryOption
 *       value              【TAG】Optionの初期値で選ばれる値を指定します
 *       separator          【TAG】複数のラベルを合成するときに使用する項目区切り文字をセットします(初期値:スペース)
 *       defaultVal         【TAG】value値がNULLの場合に使用される初期値を設定します
 *       language           【TAG】タグ内部で使用する言語コード[ja/en/zh/…]を指定します
 *       quotCheck          【TAG】リクエスト情報の シングルクォート(') 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_SQL_INJECTION_CHECK[=true])
 *       dbid               【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します(初期値:null)
 *       addKey             【TAG】項目が一つだけの場合のﾗﾍﾞﾙﾘｿｰｽに、キー情報を追加するかどうかを指定します(初期値:false)
 *       classUseNo         【TAG】オプションに追加する class 属性の カラム番号を指定します
 *       styleUseNo         【TAG】オプションに追加する style 属性の カラム番号を指定します
 *       disabledUseNo      【TAG】オプションに追加する disabled 属性の カラム番号を指定します
 *       groupUseNo         【TAG】オプションのグループ化を行うカラム番号を指定します
 *       titleUseNo         【TAG】オプションに追加する title 属性の カラム番号を指定します
 *       xssCheck           【TAG】リクエスト情報の HTMLTag開始/終了文字(&gt;&lt;) 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_XSS_CHECK[=true])
 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   &gt;   ... Body ...
 *   &lt;/og:queryOption&gt;
 *
 * ●使用例
 *     &lt;og:select name="CDC" &gt;
 *         &lt;og:queryOption&gt;
 *                 select NOSYN,NOSYN,NMSYN from DB01 ORDER BY 1
 *         &lt;/og:queryOption&gt;
 *     &lt;/og:select&gt;
 *
 *     &lt;og:select name="CDC" &gt;                選択項目の一番上に空白をセットしたいときoptionタグを組合せることも可能です。
 *         &lt;og:option lbl="" /&gt;               初期値を設定したいときはvalue属性を使います。
 *         &lt;og:queryOption value="61200" separator=":" &gt;
 *                 select CDBK,CDBK,NMBK from DB02 ORDER BY 1
 *         &lt;/og:queryOption&gt;
 *     &lt;/og:select&gt;
 *
 * @og.group 選択データ制御
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class QueryOptionTag extends CommonTagSupport {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "6.4.8.1 (2016/07/02)" ;
	private static final long serialVersionUID = 648120160702L ;

	private static final String ERR_ARG_NO = "通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定して下さい。";		// 6.4.2.1 (2016/02/05) PMD refactoring.

	private transient DBTableModel	table	;
	private String	selValue		;
	private String	defaultVal		;
	// 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
	private String	dbid		;
	private String	sql			;
	private String	separator	= " ";		// 項目区切り文字
	private boolean	quotCheck	= HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );	// 4.0.0 (2005/08/31)
	private int		classUseNo	= -1;		// 3.8.5.2 (2006/06/09) オプションに追加するクラス属性
	private int		styleUseNo	= -1;		// 6.2.0.0 (2015/02/27) コードリソースのパラメータの指定方法を変更します。
	private int		disabledUseNo= -1;		// 6.2.0.0 (2015/02/27) コードリソースのパラメータの指定方法を変更します。
	private int		groupUseNo	= -1;		// 3.8.5.2 (2006/06/09) キーブレイク時に追加するグループ文字
	private boolean	addKey		;			// 4.0.0 (2006/11/15) 項目一つのときにﾗﾍﾞﾙﾘｿｰｽ表示時にキーも付加する。
	private int		titleUseNo	= -1;		// 4.3.8.0 (2009/08/01) オプションのtitle属性
	private boolean	xssCheck	= HybsSystem.sysBool( "USE_XSS_CHECK" );	// 5.0.0.2 (2009/09/15)
	private String	rawSql		;			// 5.1.7.0 (2010/06/01) 動的プルダウン実装見直し

	/**
	 * デフォルトコンストラクター
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
	 */
	public QueryOptionTag() { super(); }		// これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。

	/**
	 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
	 *
	 * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
	 * @og.rev 6.4.8.1 (2016/07/02) xssCheckを、doStartTag に移動
	 *
	 * @return	後続処理の指示( EVAL_BODY_BUFFERED )
	 */
	@Override
	public int doStartTag() {
		useXssCheck( xssCheck );			// 6.4.8.1 (2016/07/02)

		// 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
		return useTag()
					? EVAL_BODY_BUFFERED	// Body を評価する。( extends BodyTagSupport 時)
					: SKIP_BODY ;			// Body を評価しない

//		// 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
//		if( useTag() ) {
//			return EVAL_BODY_BUFFERED ;	// Body を評価する。( extends BodyTagSupport 時)
//		}
//		return SKIP_BODY ;				// Body を評価しない
	}

	/**
	 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) ボディの内容を取得する処理を、CommonTagSupport で行う。
	 * @og.rev 3.6.0.8 (2004/11/19) エラー発生時に確実にリリースされるように try finally 追加
	 * @og.rev 3.7.1.0 (2005/04/26) DBTableModel がすでにセットされている場合は、SQL処理不要。
	 * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
	 * @og.rev 4.0.0.0 (2005/08/31) useQuotCheck() によるＳＱＬインジェクション対策
	 * @og.rev 3.8.6.3 (2006/11/30) SQL 文の前後のスペースを取り除きます。
	 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
	 * @og.rev 4.3.6.0 (2009/04/01) EventColumn対応
	 * @og.rev 5.0.0.5 (2009/08/28) XSS対策
	 * @og.rev 5.1.7.0 (2010/06/01) 動的プルダウン実装見直し
	 * @og.rev 5.1.9.0 (2010/08/01) TransactionTag 対応。上位に TransactionTag があれば、そこからConnection をもらう。
	 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
	 * @og.rev 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
	 * @og.rev 6.3.1.1 (2015/07/10) BodyString,BodyRawStringは、CommonTagSupport で、trim() します。
	 * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
	 * @og.rev 6.3.6.1 (2015/08/28) QueryFactory.close( Query ) 廃止。Queryはキャッシュしません。
	 * @og.rev 6.4.8.1 (2016/07/02) xssCheckを、doStartTag に移動
	 *
	 * @return	後続処理の指示(SKIP_BODY)
	 */
	@Override
	public int doAfterBody() {
		// 3.7.1.0 (2005/04/26) DBTableModel がすでにセットされている場合は、SQL処理不要。
		if( table != null ) { return SKIP_BODY ; }

		// 4.0.0 (2005/08/31) useQuotCheck() によるＳＱＬインジェクション対策
		useQuotCheck( quotCheck );
		// 5.0.0.2 (2009/09/15) XSS対策
//		useXssCheck( xssCheck );			// 6.4.8.1 (2016/07/02)

//		sql    = getBodyString().trim();
//		rawSql = getBodyRawString().trim();
		sql    = getBodyString();			// 6.3.1.1 (2015/07/10)
		rawSql = getBodyRawString();		// 6.3.1.1 (2015/07/10)

//		// 4.3.6.0 (2009/04/01) セッションへのSQL文登録
//		// 5.1.7.0 (2010/06/01) 動的プルダウン実装見直し
//		final Query query = QueryFactory.newInstance();		// 4.0.0 (2005/01/31)
//		Transaction tran = null;
//		try {
//			// 5.1.9.0 (2010/08/01) TransactionTag 対応
//			final TransactionTag tranTag = (TransactionTag)findAncestorWithClass( this,TransactionTag.class );
//			if( tranTag == null ) {
//				tran = new TransactionReal( getApplicationInfo() );		// 5.3.7.0 (2011/07/01) 引数変更
//			}
//			else {
//				tran = tranTag.getTransaction();
//			}
		// 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
		try( final Transaction tran = getTransaction() ) {
			final Query query = QueryFactory.newInstance();		// 4.0.0 (2005/01/31)
//			query.setTransaction( dbid,tran );	// 5.1.9.0 (2010/08/01) TransactionTag 対応
			query.setConnection( tran.getConnection( dbid ) );			// 6.3.6.1 (2015/08/28)
			query.setResourceManager( getResource() );	// 4.0.0 (2005/01/31)
			query.setStatement( sql );
			query.execute();

			table = query.getDBTableModel();

//			query.commit();				// 6.3.6.1 (2015/08/28)
			tran.commit();				// 6.3.6.1 (2015/08/28)
		}
//		finally {
//			QueryFactory.close( query );
//			if( tran != null ) { tran.close(); }		// 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
//		}
		return SKIP_BODY ;
	}

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 *
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.3.2.0 (2003/07/07) defaultVal 属性の追加。
	 * @og.rev 3.5.4.0 (2003/11/25) selVal 属性を追加。
	 * @og.rev 5.0.2.0 (2009/11/01) 複数パラメーターの選択に対応
	 * @og.rev 5.1.7.0 (2010/06/01) 動的プルダウン実装見直し
	 * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
	 * @og.rev 5.7.1.0 (2013/12/06) SelectTag ⇒ OptionAncestorIF に変更して、DatalistTag にも対応。
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();		// 4.0.0 (2005/02/28)
		// 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
		if( useTag() ) {
			final OptionAncestorIF select = (OptionAncestorIF)findAncestorWithClass( this,OptionAncestorIF.class );
			if( select == null ) {
				final String errMsg = "<b>" + getTagName() + "タグは、SelectTag または、DatalistTag のBODY に記述する必要があります。</b>";
				throw new HybsSystemException( errMsg );
			}
			final String selVal = nval( select.getValue(),defaultVal );	// 3.5.4.0 (2003/11/25)
	//		selValue = nval( selValue,selVal );						// 3.5.4.0 (2003/11/25)
			selValue = "|" + nval( selValue,selVal ) + "|";			// 5.0.2.0 (2009/11/01)
			makeLabel( select );

			// 5.1.7.0 (2010/06/01) 動的プルダウン実装見直し
			select.setRawParam( rawSql );
		}
		return EVAL_PAGE ;
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 *
	 * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
	 * @og.rev 3.0.1.0 (2003/03/03) セパレーターを指定できる様に変更。
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.3.2.0 (2003/07/07) defaultVal 属性の追加。
	 * @og.rev 3.8.5.2 (2006/06/09) classUseNo , groupUseNo 属性の追加。
	 * @og.rev 4.0.0.0 (2005/08/31) quotCheck , addKey 属性の追加
	 * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
	 * @og.rev 5.1.7.0 (2010/06/01) 動的プルダウン実装見直し
	 * @og.rev 6.2.0.0 (2015/02/27) コードリソースのパラメータの指定方法を変更します。styleUseNo,disabledUseNo 属性追加
	 *
	 */
	@Override
	protected void release2() {
		super.release2();
		table		= null;
		selValue	= null;
		defaultVal	= null;
		dbid		= null;
		sql			= null;
		separator	= " ";
		classUseNo	= -1;		// 3.8.5.2 (2006/06/09) オプションに追加するクラス属性
		styleUseNo	= -1;		// 6.2.0.0 (2015/02/27) コードリソースのパラメータの指定方法を変更します。
		disabledUseNo	= -1;	// 6.2.0.0 (2015/02/27) コードリソースのパラメータの指定方法を変更します。
		groupUseNo	= -1;		// 3.8.5.2 (2006/06/09) キーブレイク時に追加するグループ文字
		quotCheck	= HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );	// 4.0.0 (2005/08/31)
		addKey		= false;		// 4.0.0 (2006/11/15) 項目一つのときにﾗﾍﾞﾙﾘｿｰｽ表示時にキーも付加する。
		titleUseNo		= -1;
		xssCheck	= HybsSystem.sysBool( "USE_XSS_CHECK" );	// 5.0.0.2 (2009/09/15)
		rawSql		= null; // 5.1.7.0 (2010/06/01) 動的プルダウン実装見直し
	}

	/**
	 * DBTableModelをセットします。
	 *
	 * サブクラスより、DBTableModelをセットするのに使います。
	 *
	 * @og.rev 3.7.1.0 (2005/04/26) 新規追加
	 *
	 * @param	table	DBTableModelオブジェクト
	 */
	protected void setTableModel( final DBTableModel table ) {
		this.table = table ;
	}

	/**
	 * オプションを作成します。
	 *
	 * DBTableModel の１番目の値を "value" に、それ以降を文字列を連結させて
	 * BODY属性 に登録するOptionを作成します。
	 *
	 * @og.rev 3.0.1.0 (2003/03/03) 『SELECT KEY FROM TABLE ･･･』形式の場合は、LABEL に KEY を使用。
	 * @og.rev 3.8.0.9 (2005/10/17) 複数選択可能時に全選択を設定する。
	 * @og.rev 3.8.5.2 (2006/06/09) classUseNo 属性と groupUseNo 属性を追加
	 * @og.rev 3.8.9.2 (2007/07/28) グループと、クラスの設定方法のバグ修正
	 * @og.rev 4.3.8.0 (2009/08/01) titleUseNo属性追加
	 * @og.rev 5.0.2.0 (2009/11/01) 複数パラメーターの選択に対応
	 * @og.rev 5.7.1.0 (2013/12/06) SelectTag ⇒ OptionAncestorIF に変更して、DatalistTag にも対応。
	 * @og.rev 6.0.4.0 (2014/11/28) キー:ラベル形式で表示するかどうかの、addKeyLabel 属性対応
	 * @og.rev 6.2.0.0 (2015/02/27) コードリソースのパラメータの指定方法を変更します。
	 *
	 * @param   select SelectTagオブジェクト
	 */
	private void makeLabel( final OptionAncestorIF select ) {
		final boolean multipleAll = select.isMultipleAll();	// 3.8.0.9 (2005/10/17)
		final int rowCnt = table.getRowCount();		// 3.5.5.7 (2004/05/10)

		// 6.0.4.0 (2014/11/28) キー:ラベル形式で表示するかどうか[true:キー:ラベル形式/false:ラベルのみ/null:指定通り]
		final String addKeyLabel = select.getAddKeyLabel();

		// 6.2.0.0 (2015/02/27) ２番目以降の groupUseNo,classUseNo,styleUseNo,disabledUseNo,titleUseNo 以外のカラムは連結対象
		// 0:キー、1:ラベル、以降、特殊カラム以外は連結します。先に連結するカラム番号をピックアップしておきます。
		final int clmSize = table.getColumnCount();
		int[] tmpClms = new int[clmSize];			// 実際には、clmSize-2 が最大だが、カラム数=1 もあり得る。
		int cnt = 0;								// 実際
		for( int clm=2; clm<clmSize; clm++ ) {		// カラムの２番目以降
			if( clm != groupUseNo && clm != classUseNo && 
				clm != styleUseNo && clm != disabledUseNo && clm != titleUseNo ) {
					tmpClms[cnt++] = clm;
			}
		}

		String bkGroupKey = "";
		String grpLabel ;
		final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );	// 6.1.0.0 (2014/12/26) refactoring
		for( int row=0; row<rowCnt; row++ ) {
			// 3.8.5.2 (2006/06/09) groupUseNo 属性
			if( groupUseNo >= 0 ) {
				final String groupKey = table.getValue( row,groupUseNo );
				grpLabel = getRendererValue( row,groupUseNo );
				if( !bkGroupKey.equals( groupKey ) ) {		// キーブレイク
					// 3.8.9.2 (2007/07/28) グループと、クラスの設定方法のバグ修正
					if( ! "".equals( bkGroupKey ) ) {
						select.addOption( "</optgroup>" );
					}
					if( ! "".equals( groupKey ) ) {
						select.addOption( "<optgroup label=\"" + grpLabel + "\">" );
					}
					bkGroupKey = groupKey;
				}
			}

			final Attributes attri = new Attributes();
			final String value = table.getValue( row,0 );
			attri.set( "value", value );

			// 5.0.2.0 (2009/11/01)
			// selValue は、makeLabel( OptionAncestorIF ) が呼ばれる前に、必ずセットされている。
			if( multipleAll || selValue.indexOf( "|" + value + "|" ) >= 0 ) {
				attri.set( "selected", "selected" );
			}

			// 3.8.5.2 (2006/06/09) classUseNo 属性
			if( classUseNo >= 0 ) {
				attri.add( "class", table.getValue( row,classUseNo ) );
			}

			// 6.2.0.0 (2015/02/27) コードリソースのパラメータの指定方法を変更します。
			if( styleUseNo >= 0 ) {
				attri.add( "style", table.getValue( row,styleUseNo ) );
			}

			if( disabledUseNo >= 0 ) {
				final String val = table.getValue( row,disabledUseNo );
				if( "true".equalsIgnoreCase( val ) || "disabled".equalsIgnoreCase( val ) ) {
					attri.add( "disabled","disabled" );
				}
			}

			buf.setLength(0);			// 6.1.0.0 (2014/12/26) refactoring
			boolean titleFlg = false;	// 4.3.8.0 (2009/08/01) title属性を付けるかどうか
			if( clmSize == 1 ) {		// 6.2.0.0 (2015/02/27) 変数化
				// 項目が一つの queryOption では、ラベルリソースが使用されます。
				if( addKey ) { buf.append( value ).append( ':' ); }		// 6.0.2.5 (2014/10/31) char を append する。
				final String label = getResource().getLabel( value );	// 6.2.0.0 (2015/02/27) 変数使用
				buf.append( label );

				// 4.3.8.0 (2009/08/01) titleUseNo 属性 セットされている場合かつラベルと異なる場合はtitle属性に追加
				if( titleUseNo >= 0 && !label.equals( table.getValue( row,titleUseNo ) )) {
					titleFlg = true;
				}
			}
			else {
	//			if( groupUseNo >= 0 ) {
	//				buf.append( grpLabel );
	//				buf.append( separator );
	//			}
				final String label = getRendererValue( row,1 );
				buf.append( label );
	//			attri.set( "label", label );
				// 6.2.0.0 (2015/02/27) ２番目以降の連結対象
				for( int i=0; i<cnt; i++ ) {	// 注意：tmpClms.length ではなく、実際の設定済み数 cnt を使う。
					buf.append( separator ).append( getRendererValue( row,tmpClms[i] ) );
				}

				// 4.3.8.0 (2009/08/01) titleUseNo 属性 セットされている場合かつラベルと異なる場合はtitle属性に追加
				if( titleUseNo >= 0 && !label.equals( table.getValue( row,titleUseNo ) )) {
					titleFlg = true;
				}
			}

			// 4.3.7.2 (2009/06/22) タイトル属性セット
			if( titleFlg ){
				attri.add( "title", table.getValue( row,titleUseNo ) );
			}

			attri.set( "body", buf.toString() );
			select.addOption( XHTMLTag.option( attri , addKeyLabel ) );
		}
		if( groupUseNo >= 0 && ! "".equals( bkGroupKey ) ) {	// 3.8.9.2 (2007/07/28)
			select.addOption( "</optgroup>" );
		}
	}

	/**
	 * 【TAG】Optionの初期値で選ばれる値を指定します。
	 *
	 * @og.tag Optionの初期値で選ばれる値を指定します。
	 *
	 * @param   val Optionの初期値で選ばれる値
	 */
	public void setValue( final String val ) {
		selValue = getRequestParameter( val );
	}

	/**
	 * 【TAG】value属性に値がセットされていないとき使用する、初期値を指定します。
	 *
	 * @og.tag
	 * value属性に値がセットされていないときに、この初期値を使用します。
	 *
	 * @og.rev 3.3.2.0 (2003/07/07) defaultVal 属性の追加。(新規作成)
	 *
	 * @param	val 初期値
	 */
	public void setDefaultVal( final String val ) {
		defaultVal = getRequestParameter( val );
	}

	/**
	 * 【TAG】複数のラベルを合成するときに使用する項目区切り文字をセットします(初期値:スペース)。
	 *
	 * @og.tag
	 * 初期値は、スペースです。
	 *
	 * @og.rev 3.0.1.0 (2003/03/03) セパレーターを指定できる様に変更。
	 *
	 * @param   sep 項目区切り文字
	 */
	public void setSeparator( final String sep ) {
		separator = nval( getRequestParameter( sep ),separator );
	}

	/**
	 * 【TAG】オプションに追加する class 属性の カラム番号を指定します(初期値:使用しない(-1))。
	 *
	 * @og.tag
	 * オプションは、データベースを検索して作成されますが、そのSQL文のカラム情報を
	 * 使用して オプションに class 属性を追加します。
	 * 各オプションに色をつける場合は、この class 属性に対応する CSS ファイルを用意します。
	 * ここでは、class 属性に使用する SQL文の カラム番号( 先頭が 0 ) を指定します。
	 * 通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定します。
	 * 初期値は、使用しない(-1)です。
	 *
	 * @og.rev 3.8.5.2 (2006/06/09) 新規追加
	 *
	 * @param   no オプションに追加するクラス属性
	 */
	public void setClassUseNo( final String no ) {
		classUseNo = nval( getRequestParameter( no ),classUseNo );
		if( classUseNo == 0 || classUseNo == 1 ) {
//			final String errMsg = "通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定して下さい。";
//			throw new HybsSystemException( errMsg );
			throw new HybsSystemException( ERR_ARG_NO );	// 6.4.2.1 (2016/02/05) PMD refactoring.
		}
	}

	/**
	 * 【TAG】オプションに追加する style 属性の カラム番号を指定します(初期値:使用しない(-1))。
	 *
	 * @og.tag
	 * オプションは、データベースを検索して作成されますが、そのSQL文のカラム情報を
	 * 使用して オプションタグにstyle 属性を追加します。
	 * 通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定します。
	 * 初期値は、使用しない(-1)です。
	 *
	 * @og.rev 6.2.0.0 (2015/02/27) コードリソースのパラメータの指定方法を変更します。
	 *
	 * @param   no オプションに追加するstyle 属性
	 */
	public void setStyleUseNo( final String no ) {
		styleUseNo = nval( getRequestParameter( no ),styleUseNo );
		if( styleUseNo == 0 || styleUseNo == 1 ) {
//			final String errMsg = "通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定して下さい。";
//			throw new HybsSystemException( errMsg );
			throw new HybsSystemException( ERR_ARG_NO );	// 6.4.2.1 (2016/02/05) PMD refactoring.
		}
	}

	/**
	 * 【TAG】オプションに追加する disabled 属性の カラム番号を指定します(初期値:使用しない(-1))。
	 *
	 * @og.tag
	 * オプションは、データベースを検索して作成されますが、そのSQL文のカラム情報を
	 * 使用して オプションタグにdisabled 属性を追加します。
	 *
	 * 設定する値は、"true" か、"disabled" の場合のみ、disabled になります。
	 *
	 * 通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定します。
	 * 初期値は、使用しない(-1)です。
	 *
	 * @og.rev 6.2.0.0 (2015/02/27) コードリソースのパラメータの指定方法を変更します。
	 *
	 * @param   no オプションに追加するdisabled 属性
	 */
	public void setDisabledUseNo( final String no ) {
		disabledUseNo = nval( getRequestParameter( no ),disabledUseNo );
		if( disabledUseNo == 0 || disabledUseNo == 1 ) {
//			final String errMsg = "通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定して下さい。";
//			throw new HybsSystemException( errMsg );
			throw new HybsSystemException( ERR_ARG_NO );	// 6.4.2.1 (2016/02/05) PMD refactoring.
		}
	}

	/**
	 * 【TAG】オプションのグループ化を行うカラム番号を指定します(初期値:使用しない(-1))。
	 *
	 * @og.tag
	 * オプションは、データベースを検索して作成されますが、そのSQL文のカラム情報を
	 * 使用して オプションをグループ化します。グループ化は optgroup要素をブレイク時に
	 * 出力する事で対応します。
	 * ここでは、グループ化に使用する SQL文の カラム番号( 先頭が 0 ) を指定します。
	 * 通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定します。
	 * 初期値は、使用しない(-1)です。
	 *
	 * @og.rev 3.8.5.2 (2006/06/09) 新規追加
	 *
	 * @param   no キーブレイク時に追加するグループ文字
	 */
	public void setGroupUseNo( final String no ) {
		groupUseNo = nval( getRequestParameter( no ),groupUseNo );
		if( groupUseNo == 0 || groupUseNo == 1 ) {
//			final String errMsg = "通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定して下さい。";
//			throw new HybsSystemException( errMsg );
			throw new HybsSystemException( ERR_ARG_NO );	// 6.4.2.1 (2016/02/05) PMD refactoring.
		}
	}

	/**
	 * 【TAG】リクエスト情報の シングルクォート(') 存在チェックを実施するかどうか[true/false]を設定します
	 *		(初期値:USE_SQL_INJECTION_CHECK[={@og.value SystemData#USE_SQL_INJECTION_CHECK}])。
	 *
	 * @og.tag
	 * ＳＱＬインジェクション対策の一つとして、暫定的ではありますが、SQLのパラメータに
	 * 渡す文字列にシングルクォート(') を許さない設定にすれば、ある程度は防止できます。
	 * 数字タイプの引数には、 or 5=5 などのシングルクォートを使用しないコードを埋めても、
	 * 数字チェックで検出可能です。文字タイプの場合は、必ず (')をはずして、
	 * ' or 'A' like 'A のような形式になる為、(')チェックだけでも有効です。
	 * (') が含まれていたエラーにする(true)／かノーチェックか(false)を指定します。
	 * (初期値:システム定数のUSE_SQL_INJECTION_CHECK[={@og.value SystemData#USE_SQL_INJECTION_CHECK}])。
	 *
	 * @og.rev 4.0.0.0 (2005/08/31) 新規追加
	 *
	 * @param   flag クォートチェック [true:する/それ以外:しない]
	 * @see		org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK
	 */
	public void setQuotCheck( final String flag ) {
		quotCheck = nval( getRequestParameter( flag ),quotCheck );
	}

	/**
	 * 【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します(初期値:null)。
	 *
	 * @og.tag
	 * Queryオブジェクトを作成する時のDB接続IDを指定します。
	 * これは、システムリソースで、DEFAULT_DB_URL 等で指定している データベース接続先
	 * 情報に、XX_DB_URL を定義することで、 dbid="XX" とすると、この 接続先を使用して
	 * データベースにアクセスできます。
	 *
	 * @param	id データベース接続ID
	 */
	public void setDbid( final String id ) {
		dbid = nval( getRequestParameter( id ),dbid );
	}

	/**
	 * 【TAG】項目が一つだけの場合のﾗﾍﾞﾙﾘｿｰｽに、キー情報を追加するかどうかを指定します(初期値:false)。
	 *
	 * @og.tag
	 * Queryオブジェクトの項目が一つの場合、ﾗﾍﾞﾙ部には、ﾗﾍﾞﾙﾘｿｰｽを使用します。
	 * この時、ﾗﾍﾞﾙ無しの場合は、キーが表示されますが、ﾗﾍﾞﾙありの場合は、キーは表示されず
	 * ﾗﾍﾞﾙのみ表示されます。
	 * 都合によっては、キーも表示したい場合がありますので、その様なケースでは、
	 * addKey = "true を設定する事で、キー:ﾗﾍﾞﾙ のセットをﾗﾍﾞﾙとして扱います。
	 * 初期値はfalse(キーは付加しない)です。
	 *
	 * @param	id データベース接続ID
	 */
	public void setAddKey( final String id ) {
		addKey = nval( getRequestParameter( id ),addKey );
	}

	/**
	 * 【TAG】リクエスト情報の HTMLTag開始/終了文字(&gt;&lt;) 存在チェックを実施するかどうか[true/false]を設定します
	 *		(初期値:USE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
	 *
	 * @og.tag
	 * クロスサイトスクリプティング(XSS)対策の一環としてless/greater than signについてのチェックを行います。
	 * (&gt;&lt;) が含まれていたエラーにする(true)／かノーチェックか(false)を指定します。
	 * (初期値:システム定数のUSE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
	 *
	 * @og.rev 5.0.0.2 (2009/09/15) 新規追加
	 *
	 * @param	flag	XSSチェック [true:する/false:しない]
	 * @see		org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK
	 */
	public void setXssCheck( final String flag ) {
		xssCheck = nval( getRequestParameter( flag ),xssCheck );
	}

	/**
	 * row行，colum列 のデータの値を返します。
	 *
	 * これは、データの値そのものではなく、その値のラベル文字を返します。
	 *
	 * @param   row		行番号
	 * @param   column	カラム番号
	 *
	 * @return  row行，colum列 のデータの値
	 */
	private String getRendererValue( final int row,final int column ) {
		final String val = table.getValue( row,column );
		final DBColumn clm = table.getDBColumn( column );
		return clm.getRendererValue( val );
	}

	/**
	 * 【TAG】オプションに追加する title 属性の カラム番号を指定します。
	 *
	 * @og.tag
	 * オプションは、データベースを検索して作成されますが、そのSQL文のカラム情報を
	 * 使用して オプションに title 属性を追加します。
	 * title属性はマウスオーバー時にツールチップとして表示されるため、
	 * プルダウンの横幅を短くしたい場合に有効です。
	 * 通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定します。
	 * 初期値は、使用しない(-1)です。
	 *
	 * @og.rev 4.3.8.0 (2009/08/01) 新規追加
	 *
	 * @param   no オプションに追加するtitle属性
	 */
	public void setTitleUseNo( final String no ) {
		titleUseNo = nval( getRequestParameter( no ),titleUseNo );
		if( titleUseNo == 0 || titleUseNo == 1 ) {
//			final String errMsg = "通常、カラム番号=0 は キー情報、=1 はラベル情報 です。2 か 3 を指定して下さい。";
//			throw new HybsSystemException( errMsg );
			throw new HybsSystemException( ERR_ARG_NO );	// 6.4.2.1 (2016/02/05) PMD refactoring.
		}
	}

//	/**
//	 * シリアライズ用のカスタムシリアライズ書き込みメソッド。
//	 *
//	 * @og.rev 4.0.0.0 (2006/09/31) 新規追加
//	 * @serialData 一部のオブジェクトは、シリアライズされません。
//	 *
//	 * @param	strm	ObjectOutputStreamオブジェクト
//	 * @throws IOException	入出力エラーが発生した場合
//	 */
//	private void writeObject( final ObjectOutputStream strm ) throws IOException {
//		strm.defaultWriteObject();
//	}

//	/**
//	 * シリアライズ用のカスタムシリアライズ読み込みメソッド
//	 *
//	 * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
//	 *
//	 * @og.rev 4.0.0.0 (2006/09/31) 新規追加
//	 * @serialData 一部のオブジェクトは、シリアライズされません。
//	 *
//	 * @param	strm	ObjectInputStreamオブジェクト
//	 * @see #release2()
//	 * @throws IOException	シリアライズに関する入出力エラーが発生した場合
//	 * @throws ClassNotFoundException	クラスを見つけることができなかった場合
//	 */
//	private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
//		strm.defaultReadObject();
//	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 *
	 * @return このクラスの文字列表現
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		return ToString.title( this.getClass().getName() )
				.println( "VERSION"		,VERSION	)
				.println( "selValue"	,selValue	)
				.println( "defaultVal"	,defaultVal	)
				.println( "dbid"		,dbid		)
				.println( "sql"			,sql		)
				.println( "separator"	,separator	)
				.println( "quotCheck"	,quotCheck	)
				.println( "Other..."	,getAttributes().getAttribute() )
				.fixForm().toString() ;
	}
}
