/*
 * 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.Query;
import org.opengion.hayabusa.resource.GUIInfo;

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

/**
 * 【廃止】SQL文を直接指定して、データベースに追加/更新/削除を行います(queryType="JDBCPrepared")。
 *
 * 存在チェックを行う場合は、tableExist タグと併用してください。
 * 複雑な処理が必要な場合は、従来より使用しています、PLSQLをCALLする、
 * plsqlUpdateタグを使用してください。
 *
 * ※ このタグは、Transaction タグの対象です。
 *
 * @og.formSample
 * ●形式：&lt;og:update command="…" names="…" queryType="JDBCPrepared" &gt;
 *             {&#064;SQL}
 *         &lt;/og:update&gt;
 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
 *
 * ●Tag定義：
 *   &lt;og:update
 *       queryType          【廃止】Query を発行する為のクラスIDを指定します(初期値:JDBCPrepared)
 *       command            【TAG】コマンド(NEW,RENEW)をセットします(PlsqlUpdateTag,UpdateTag の場合は、ENTRY)
 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session)
 *       displayMsg         【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します (初期値:VIEW_DISPLAY_MSG[=])
 *       names              【TAG】PL/SQLを利用する場合の引数にセットすべき データの名称をCSV形式で複数指定します
 *       quotCheck          【TAG】リクエスト情報の クォーティション(') 存在チェックを実施するかどうか[true/false]を設定します(初期値:USE_SQL_INJECTION_CHECK)
 *       tableId            【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
 *       dbid               【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します
 *       xssCheck           【TAG】リクエスト情報の HTMLTag開始/終了文字(&gt;&lt;) 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_XSS_CHECK[=true])
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   &gt;   ... Body ...
 *   &lt;/og:update&gt;
 *
 * ●使用例
 *    ・引数/プロシジャーを他のJSPから渡す場合
 *    【copy.jsp】
 *        &lt;og:value scope=&quot;session&quot; key=&quot;names&quot; value=&quot;CLM,NAME_JA,LABEL_NAME,KBSAKU,SYSTEM_ID,LANG&quot; /&gt;
 *        &lt;og:value scope=&quot;session&quot; key=&quot;SQL&quot; &gt;
 *          INSERT INTO GE41
 *               (CLM,NAME_JA,LABEL_NAME,KBSAKU,SYSTEM_ID,LANG,
 *               FGJ,DYSET,DYUPD,USRSET,USRUPD,PGUPD)
 *          VALUES
 *               (?,?,?,?,?,?,
 *               &#39;1&#39;,&#39;{&#064;USER.YMDH}&#39;,&#39;{&#064;USER.YMDH}&#39;,&#39;{&#064;USER.ID}&#39;,&#39;{&#064;USER.ID}&#39;,&#39;{&#064;GUI.KEY}&#39;)
 *        &lt;/og:value&gt;
 *
 *    【entry.jsp】
 *        &lt;og:update
 *            command   = &quot;{&#064;command}&quot;
 *            queryType = &quot;JDBCPrepared&quot;
 *            names     = &quot;{&#064;names}&quot;  &gt;
 *        {&#064;SQL}
 *        &lt;/og:update&gt;
 *
 *        &lt;!-- 前画面で指定のSQL文を削除します。(scope=&quot;session&quot;なので削除が必要。) --&gt;
 *        &lt;og:value scope=&quot;session&quot; key=&quot;names&quot; command=&quot;REMOVE&quot; /&gt;
 *        &lt;og:value scope=&quot;session&quot; key=&quot;SQL&quot;   command=&quot;REMOVE&quot; /&gt;
 *
 *    ・引数/プロシジャーを直接書く場合
 *    【entry.jsp】
 *        &lt;og:update
 *            command   = &quot;{&#064;command}&quot;
 *            queryType = &quot;JDBCPrepared&quot;
 *            names     = &quot;CLM,NAME_JA,LABEL_NAME,KBSAKU,SYSTEM_ID,LANG&quot;
 *        &gt;
 *            INSERT INTO GE41
 *                (CLM,NAME_JA,LABEL_NAME,KBSAKU,SYSTEM_ID,LANG,
 *                 FGJ,DYSET,DYUPD,USRSET,USRUPD,PGUPD)
 *            VALUES
 *                (?,?,?,?,?,?,
 *                 &#39;1&#39;,&#39;{&#064;USER.YMDH}&#39;,&#39;{&#064;USER.YMDH}&#39;,&#39;{&#064;USER.ID}&#39;,&#39;{&#064;USER.ID}&#39;,&#39;{&#064;GUI.KEY}&#39;)
 *        &lt;/og:update&gt;
 *
 * @og.rev 4.0.0.0 (2005/01/31) 廃止
 * @og.group (廃止)ＤＢ登録
 *
 * @deprecated 4.0.0 (2005/01/31) 廃止。tableUpdate を利用するようにしてください。
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
@Deprecated public class UpdateTag extends QueryTag {
	//* このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "4.0.0.0 (2005/01/31)" ;

	private static final long serialVersionUID = 400020050131L ;

	/** command 引数に渡す事の出来る コマンド  登録{@value} */
	public static final String CMD_ENTRY  = "ENTRY" ;
	/** command 引数に渡す事の出来る コマンド リスト  */
	private static final String COMMAND_LIST = CMD_ENTRY;

	/**
	 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doStartTag() {
		dyStart = System.currentTimeMillis();

		table = (DBTableModel)getObject( tableId );
		if( table == null || table.getRowCount() == 0 ||
			! check( command, COMMAND_LIST ) ) { return(SKIP_BODY); }
		return( EVAL_BODY_BUFFERED );	// Body を評価する。( extends BodyTagSupport 時)
	}

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 *
	 * @og.rev 3.5.5.8 (2004/05/20) ErrorMessage オブジェクトを、正常終了時、クリア
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();		// 4.0.0 (2005/02/28)

		if( check( command, COMMAND_LIST ) ) {
			removeSessionAttribute( errMsgId );
		}

		executeCount = getParameterRows().length ;		// チェック行の数が登録件数と仮定

		// 4.0.0 (2005/01/31) 処理時間集計
		long dyTime = System.currentTimeMillis()-dyStart;

		// 4.0.0 (2005/01/31) セキュリティチェック(データアクセス件数登録)
		GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY );
		if( guiInfo != null ) { guiInfo.addWriteCount( executeCount,dyTime,sql ); }

		return(EVAL_PAGE);
	}

	/**
	 * Query を実行します。
	 *
	 * @og.rev 2.1.2.3 (2002/12/02) データベース更新時に、更新フラグをセットするように変更
	 * @og.rev 3.4.0.0 (2003/09/01) 登録エラー時のキーと値を表示するように変更。
	 * @og.rev 3.5.0.0 (2003/09/17) カラム名ではなく、カラム番号を先に求めておく方式に変更。
	 * @og.rev 3.5.6.0 (2004/06/18) DBRowHeader のパッケージプライベート化に伴なう変更
	 * @og.rev 4.0.0.0 (2005/01/31) getParameterRows() を使用するように変更
	 *
	 * @param   query オブジェクト
	 */
	@Override
	protected void execute( final Query query ) {
		// long st = System.currentTimeMillis();
		String[] values    = null;
		int row = 0;
		try {
			if( names == null ) {
				query.execute( null );
			}
			else {
				int[] rowNo = getParameterRows();		// 4.0.0 (2005/01/31)
				if( rowNo.length > 0 ) {
					int[] clmNo = getTableColumnNo( StringUtil.csv2Array( names ) );
					values    = null;
					// 逆順にDELETEしないと、行番号がずれてしまう。
					for( int j=rowNo.length-1; j>=0; j-- ) {
						row = rowNo[j];
						values = getTableModelData( clmNo,row );	// 3.5.0.0
						query.execute( values );
						if( DBTableModel.DELETE_TYPE.equals( table.getModifyType( row ) ) ) {
							table.removeValue( row );
						}
						else {
							table.resetModify( row );
						}
					}
				}
			}
//			if( query.getUpdateFlag() ) { query.commit(); }
			if( query.isUpdate() ) { query.commit(); }
		}
		catch( HybsSystemException ex ) {
			query.rollback();
	// 3.4.0.0 (2003/09/01) 登録エラー時のキーと値を表示するように変更。
			String errMsg = "DATABASE ERROR! "
				+ "rowNo=[" + ( row ) + "] " + HybsSystem.CR
				+ "nameArray=[" + names + "]" + HybsSystem.CR
				+ "values=[" + StringUtil.array2csv( values ) + "]" + HybsSystem.CR ;
			throw new HybsSystemException( errMsg,ex );		// 3.5.5.4 (2004/04/15) 引数の並び順変更
		}
		finally {
			if( query != null ) { query.close(); }
		}
		// System.out.println( ( System.currentTimeMillis() - st ) + " ms" );
	}

	/**
	 *  カラム名配列(String[])より、対応するカラムNo配列(int[])を作成します。
	 *
	 * @og.rev 3.5.0.0 (2003/09/17) 新規追加
	 *
	 * @param	nameArray カラム名配列
	 *
	 * @return	カラムNo配列
	 */
	private int[] getTableColumnNo( final String[] nameArray ) {
		int[] clmNo = new int[ nameArray.length ];
		for( int i=0; i<clmNo.length; i++ ) {
			clmNo[i] = table.getColumnNo( nameArray[i] );
		}
		return clmNo;
	}

	/**
	 *  指定の行番号の、カラムNo配列(int[])に対応した値の配列を返します。
	 *
	 * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を
	 * 処理の対象とします。
	 *
	 * @og.rev 3.5.0.0 (2003/09/17) カラム名ではなく、カラム番号を受け取るように修正。
	 *
	 * @param	clmNo	カラムNo配列
	 * @param	row		行番号
	 *
	 * @return	行番号とカラムNo配列に対応した、値の配列
	 */
	private String[] getTableModelData( final int[] clmNo,final int row ) {
		String[] values = new String[ clmNo.length ];
		for( int i=0; i<values.length; i++ ) {
			values[i] = table.getValue( row,clmNo[i] ) ;
		}
		return values;
	}

	/**
	 * 【廃止】Query を発行する為のクラスIDを指定します({@og.doc03Link queryType 初期値:JDBCPrepared})。
	 *
	 * @og.tag
	 * 登録を実行する手段は、Query インターフェースの実装クラスになります。
	 * このタグでは、Query.execute( String[] ) メソッドが複数回呼ばれます。
	 * これは、DBTableModelの選択された行に対して、繰り返し呼ばれます。
	 *
	 * 通常、このタグを使用する場合は、queryType="JDBCPrepared" を指定します。
	 *
	 * タグにより使用できる／出来ないがありますが、これは、org.opengion.hayabusa.db
	 * 以下の Query_**** クラスの **** を与えます。
	 * これらは、Query インターフェースを継承したサブクラスです。
	 * {@og.doc03Link queryType Query_**** クラス}
	 *
	 * @og.rev 3.5.4.2 (2003/12/15) JavaDocコメント用にメソッド追加。
	 *
	 * @param	id Query を発行する為の実クラス ID
	 * @see		org.opengion.hayabusa.db.Query  Queryのサブクラス
	 * @see		org.opengion.hayabusa.db.Query#execute( String[] )
	 * @deprecated クラスが廃止
	 */
	@Deprecated public void setQueryType( final String id ) {
		super.setQueryType( nval( id,"JDBCPrepared" ) );
	}
}
