/*
 * 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.remote;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.opengion.fukurou.db.Transaction;
import org.opengion.fukurou.db.TransactionReal;
import org.opengion.fukurou.transfer.TransferConfig;
import org.opengion.fukurou.transfer.TransferRead;
import org.opengion.fukurou.util.ApplicationInfo;
import org.opengion.fukurou.util.StringUtil;
import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import static org.opengion.fukurou.util.HybsConst.BUFFER_MIDDLE;	// 6.1.0.0 (2014/12/26) refactoring

/**
 * RemoteControllableインタフェイスを実装した
 * サーブレット経由で遠隔伝送読取処理を行うためのクラスです。
 *
 * このクラスは、伝送読取処理のラッパークラスです。
 * 引数のKBREADのパラメーターに基づき、伝送読取オブジェクトを生成し、伝送処理を実行します。
 * 詳細については、{@link org.opengion.fukurou.transfer.TransferRead_HTTP}を参照して下さい。
 *
 * @og.rev 5.4.2.0 (2011/12/01) 新規作成
 *
 * @version  4.1
 * @author   Hiroki Nakamura
 * @since    JDK6.0,
 *
 */
public class TransferReadWrapper implements RemoteControllable {

	// 伝送読取クラスのベースクラス名
	private static final String READ_CLASS_BASE = "org.opengion.fukurou.transfer.TransferRead_" ;

	// コネクションにアプリケーション情報を追記するかどうか指定
	private static final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;

	private static final ApplicationInfo appInfo;

	static {
		if( USE_DB_APPLICATION_INFO ) {
			appInfo = new ApplicationInfo();
			// ユーザーID,IPアドレス,ホスト名
			appInfo.setClientInfo( "TransferReadWrapper",HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME );
			// 画面ID,操作,プログラムID
			appInfo.setModuleInfo( "TransferReadWrapper","TransferReadWrapper","TransferReadWrapper" );
		}
		else {
			appInfo = null;
		}
	}
	/**
	 * RemoteControllableインタフェイスの実装メソッドです。
	 *
	 * @og.rev 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
	 *
	 * @param	valMap	 サーブレットが受け取ったキーと値のマップ
	 *
	 * @return	XML形式の実行結果
	 */
	@Override
	public String remoteControl( final Map<String,String> valMap ) {
		// パラメーターより伝送設定オブジェクトを生成します。
		final TransferConfig conf = new TransferConfig(
				valMap.get( "KBREAD" )
				, valMap.get( "READOBJ" )
				, valMap.get( "READPRM" )
				, valMap.get( "KBEXEC" )
				, valMap.get( "EXECDBID" )
				, valMap.get( "EXECOBJ" )
				, valMap.get( "EXECPRM" )
				, valMap.get( "ERROR_SENDTO" )
				, valMap.get( "HFROM" )
				, null, -1 );
		Transaction tran = null;
		String rtn = null;
		try {
			tran = new TransactionReal( appInfo );
			final TransferRead read = (TransferRead)StringUtil.newInstance( READ_CLASS_BASE + valMap.get( "KBREAD" ) );

			// データ読取
			final String type = valMap.get( "type" );
			if( "read".equals( type ) ) {
				final String[] data = read.read( conf, tran );
				// 完了/エラー処理のために更新キーを取得しXMLに埋め込む
				final String[] keys = read.getKeys();
				rtn = makeXml( data, keys );
			}
			// 完了処理
			else if( "complete".equals( type ) ) {
				// パラメーターから更新キーを読み取る
				final String[] keys = getKeys( valMap );
				read.setKeys( keys );
				read.complete( conf, tran );
			}
			// エラー処理
			else if( "error".equals( type ) ) {
				// パラメーターから更新キーを読み取る
				final String[] keys = getKeys( valMap );
				read.setKeys( keys );
				read.error( conf, appInfo );
			}
			else {
				final String errMsg = "処理タイプが不正です。[指定可能タイプ=read,complete,error][指定されたタイプ=" + type + "]";
				throw new HybsSystemException( errMsg );
			}
		}
		catch ( Throwable ex ) {
			final String errMsg = "伝送読取処理(HTTP経由)でエラーが発生しました。";
			throw new HybsSystemException( errMsg, ex );	// 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
		}
		finally {
			if( tran != null ) { tran.close(); }
		}

		return rtn;
	}

	/**
	 * 伝送読取処理の結果からデータ一覧及びキー一覧からXMLデータを生成します。
	 *
	 * @og.rev 5.4.4.5 (2012/02/20) 特定文字をエスケープする
	 * @param data データ一覧(配列)
	 * @param key 更新時に使用するキー一覧(配列)
	 *
	 * @return XMLデータ
	 */
	private String makeXml( final String[] data, final String[] key ) {
		final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
			.append( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><root><dataList>" );
		if( data != null ) {
			for( final String d : data ) {
				buf.append( " <data>" ).append( StringUtil.htmlFilter(d) ).append( "</data>" );
			}
		}
		buf.append( " </dataList><keyList>" );
		if( key != null ) {
			for( final String k : key ) {
				buf.append( " <key>" ).append( StringUtil.htmlFilter(k) ).append( "</key>" );
			}
		}
		buf.append( " </keyList></root>" );
		return buf.toString();
	}

	/**
	 * パラメーターより伝送読取オブジェクトに渡すキー一覧(配列)を生成します。
	 * 対象パラメーターは①n(データ件数) と ②k1～kn(データ) です。
	 *
	 * @param valMap パラメーターMap
	 *
	 * @return 値一覧(配列)
	 */
	private String[] getKeys( final Map<String,String> valMap ) {
		int rows = 0;
		final String rno = valMap.get( "n" );
		if( rno != null && rno.length() > 0 ) {
			rows = Integer.parseInt( rno );			// 6.0.2.4 (2014/10/17) メソッド間違い
		}
		final List<String> list = new ArrayList<>();
		for( int i=0; i<rows; i++ ) {
			final String key = valMap.get( "k" + i );
			list.add( key );
		}
		return list.toArray( new String[list.size()] );
	}
}
