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

import org.opengion.fukurou.system.OgRuntimeException ;		// 6.4.2.0 (2016/01/29)
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.opengion.fukurou.db.ConnectionFactory;
import org.opengion.fukurou.db.Transaction;
import org.opengion.fukurou.db.TransactionReal;
import org.opengion.fukurou.db.ApplicationInfo;
import org.opengion.fukurou.system.LogWriter;
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.system.ThrowUtil;							// 6.4.2.0 (2016/01/29)

/**
 * 伝送処理を実行するためのクラスです。
 *
 * 伝送デーモンでセットされた読取方法、実行方法の基づき伝送処理を実行します。
 * 伝送処理は以下のフローで実行されます。
 *
 * ①データの読み取り
 * 　読取方法に対応する各実装クラスの処理を呼び出しデータを読み取ります。
 * ②処理実行
 * 　実行方法に対応する各実装クラスの処理を呼び出し①で取得したデータに対して処理を実行します。
 * ③終了処理
 * 　①、②が正常終了した場合，読取方法のクラスで定義された終了処理を実行します。
 * 　①、②でエラーが発生した場合、読取方法のクラスで定義されたエラー処理を実行します。
 *
 * @og.group 伝送システム
 *
 * @version  5.0
 * @author   Hiroki.Nakamura
 * @since    JDK1.6
 */
public class TransferProcess {

	// 実行方法に対応する実装クラスの基準名
	private static final String READ_CLASS_BASE = "org.opengion.fukurou.transfer.TransferRead_" ;

	// 実行方法に対応する実装クラスの基準名
	private static final String EXEC_CLASS_BASE = "org.opengion.fukurou.transfer.TransferExec_" ;

	// 実行対象の伝送セットオブジェクトのセット
	private final Set<TransferConfig> configSet;

	// 最後に実行した伝送設定オブジェクト
	private TransferConfig config ;

	// 実行デーモン名
	private String dmnName ;

	// DB接続情報記録
	private ApplicationInfo appInfo;

	// デバッグ情報を出力するかどうか
	private boolean isDebug ;

	/**
	 * コンストラクタです。
	 *
	 * @param configSet 伝送設定オブジェクトのセット
	 */
	public TransferProcess( final Set<TransferConfig> configSet ) {
		this.configSet = configSet;
	}

	/**
	 * デーモン名をセットします。
	 *
	 * @param dmnName デーモン名
	 */
	public void setDmnName( final String dmnName ) {
		this.dmnName = dmnName;
	}

	/**
	 * DB接続情報をセットします。
	 *
	 * @param appInfo DB接続情報
	 */
	public void setAppInfo( final ApplicationInfo appInfo ) {
		this.appInfo = appInfo;
	}

	/**
	 * デバッグ情報を出力します。
	 */
	public void setDebug() {
		isDebug = true;
	}

	/**
	 * 最後に実行した伝送設定オブジェクトを返します。
	 *
	 * @return 伝送設定オブジェクト
	 */
	public TransferConfig getLastConfig() {
		return config;
	}

	/**
	 * 伝送処理を実行します。
	 *
	 * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
	 *
	 */
	public void process() {
//		Transaction tran = new TransactionReal( appInfo );
		TransferRead read = null;
		TransferExec exec = null;
//		try {
		try( final Transaction tran = new TransactionReal( appInfo ) ) {
			for( final TransferConfig c : configSet ) {
				config = c;

				// デバッグ情報を出力します。
				if( isDebug ) {
					System.out.println();
					System.out.print( " START = " + new Date() );
					System.out.println( "[" + dmnName + "]:[" + config.toString() + "]" );
				}

				// 読取方法のオブジェクトを生成し、伝送プロセスにセットします。
				read = (TransferRead)StringUtil.newInstance( READ_CLASS_BASE + config.getKbRead() );

				// 実行方法のオブジェクトを生成し、伝送プロセスにセットします。
				exec = (TransferExec)StringUtil.newInstance( EXEC_CLASS_BASE + config.getKbExec() );

				final String[] vals = read.read( config, tran );
				exec.execute( vals, config, tran );
				read.complete( config, tran );

				// デバッグ情報を出力します。
				if( isDebug ) {
					System.out.println();
					System.out.print( " END   = " + new Date() );
					System.out.println( "[" + dmnName + "]:[" + config.toString() + "]" );
				}
			}
			tran.commit();						// 6.3.6.1 (2015/08/28)
		}
		catch( final Throwable ex ) {		// catch は、close() されてから呼ばれます。
			// 6.3.6.1 (2015/08/28) tran.commit() されない場合は、rollback() される。
//			if( tran != null ) {
//				tran.rollback();
//				tran.close();
//				tran = null; // エラー発生時は、接続を終了します。(次の状況更新でデッドロックになるため)
//			}

			if( read != null ) {
				read.error( config, appInfo );
			}

			throw new OgRuntimeException( ex );
		}
//		finally {
//			if( tran != null ) { tran.close(); }
//		}
	}

	/**
	 * 実行用のメインメソッド。
	 *
	 * Usage: java org.opengion.hayabusa.transfer.TransferProcess
	 *  -kbRead=読取方法 -readObj=読取対象 [-readPrm=読取パラメーター]
	 *  -kbExec=実行方法 -execObj=実行対象 [-execPrm=実行パラメーター]
	 *  -DBConfig=DBConfig.xml [-execDbid=実行接続先DBID] [-hfrom=送り元ホストコード]
	 *  [-debug=true/false]
	 *
	 * @og.rev 5.8.3.2 (2015/01/30) debug追加
	 * @og.rev 5.8.4.2 (2015/02/28) 修正
	 * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。
	 * @og.rev 6.5.0.1 (2016/10/21) debug時のex.toString()は不要なので、削除しておきます。
	 *
	 * @param	args	コマンド引数配列
	 */
	public static void main( final String[] args ) {
		boolean debug	= false; // 5.8.3.2 (2015/01/30) 
		try {
			if( args.length < 5 ) {
				LogWriter.log( "Usage: java org.opengion.hayabusa.transfer.TransferProcess" );
				LogWriter.log( "   -kbRead=読取方法 -readObj=読取対象 [-readPrm=読取パラメーター]" );
				LogWriter.log( "   -kbExec=実行方法 -execObj=実行対象 [-execPrm=実行パラメーター]" );
				LogWriter.log( "   -DBConfig=DBConfig.xml [-execDbid=実行接続先DBID] [-hfrom=送り元ホストコード]" );
				return;
			}

			String kbRead	= null;
			String readObj	= null;
			String readPrm	= null;
			String kbExec	= null;
			String execObj	= null;
			String execPrm	= null;
			String dbConfig	= null;
			String execDbid	= null;
			String hfrom	= null;

			for( int i=0; i<args.length; i++ ) {
				final String arg = args[i];
				if( arg.startsWith( "-kbRead=" ) ) {
					kbRead = arg.substring( 8 );
				}
				else if( arg.startsWith( "-readObj=" ) ) {
					readObj = arg.substring( 9 );
				}
				else if( arg.startsWith( "-readPrm=" ) ) {
					readPrm = arg.substring( 9 );
				}
				else if( arg.startsWith( "-kbExec=" ) ) {
					kbExec = arg.substring( 8 );
				}
				else if( arg.startsWith( "-execObj=" ) ) {
					execObj = arg.substring( 9 );
				}
				else if( arg.startsWith( "-execPrm=" ) ) {
					execPrm = arg.substring( 9 );
				}
				else if( arg.startsWith( "-DBConfig=" ) ) {
					dbConfig = arg.substring( 10 );
				}
				else if( arg.startsWith( "-execDbid=" ) ) {
					execDbid = arg.substring( 10 );
				}
				else if( arg.startsWith( "-hfrom=" ) ) {
					hfrom = arg.substring( 7 );
				}
				else if( arg.startsWith( "-debug=" ) ) {		// 5.8.3.2 (2015/01/30) 
					if( "true".equalsIgnoreCase( arg.substring( 7 ) ) ){ debug = true; }  // 5.8.4.2 (2015/02/28)
				}
			}

			if( kbRead == null || kbRead.isEmpty()
				||	readObj	== null || readObj.isEmpty()
				||	kbExec	== null || kbExec.isEmpty()
				||	execObj == null || execObj.isEmpty()
				||	dbConfig== null || dbConfig.isEmpty() ) {
						LogWriter.log( "以下のパラメーターは必須です。" );
						LogWriter.log( "-kbRead=読取方法 -readObj=読取対象" );
						LogWriter.log( "-kbExec=実行方法 -execObj=実行対象" );
						LogWriter.log( "-DBConfig=DBConfig.xml" );
			}

			// DBID接続情報の取得先の設定
			ConnectionFactory.init( null,dbConfig );

			// 伝送設定オブジェクト
			final TransferConfig config = new TransferConfig(
										kbRead, readObj, readPrm
										, kbExec, execDbid, execObj, execPrm
										, null, hfrom, null, -1 );
			final Set<TransferConfig> configSet = new HashSet<>();
			configSet.add( config );

			// 伝送処理を実行します。
			final TransferProcess proc = new TransferProcess( configSet );
			if( debug ){ // 5.8.3.2 (2015/01/30)
				proc.setDebug();
			}

			System.out.println( "EXEC START Config=[" + config.toString() + "]" );
			proc.process();
			System.out.println( "EXEC END   Config=[" + config.toString() + "]" );
		}
		catch( final Throwable ex ) {
//			ex.printStackTrace();
			System.err.println( ThrowUtil.ogStackTrace( ex ) );				// 6.4.2.0 (2016/01/29)
//			// 5.8.3.2 (2015/01/30)
//			if( debug ){
//				System.out.println( ex.toString() );						// 6.5.0.1 (2016/10/21) 不要なので削除
//			}
			// 異常終了の場合
			System.exit( 1 );
		}

		// 正常終了の場合
		System.exit( 0 );
	}
}
