/*
 * Copyright (c) 2017 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.fileexec;

import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
// import java.util.logging.Logger;
import java.util.StringJoiner;
import java.util.Arrays;
import java.util.List;
import java.nio.file.Path;

/**
 * AppliExec は、アプリケーション応答ファイル(DATファイル)を監視し、ファイル更新があれば、適切に処理するクラスです。
 *
 *<pre>
 *
 * ここでは、個々のDATファイルを解析して、ファイルなりデータベースに登録します。
 *
 *</pre>
 *
 * @og.rev 7.0.0.0 (2017/07/07) 新規作成
 *
 * @version  7.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK1.8,
 */
public final class AppliExec {
	private static final XLogger LOGGER= XLogger.getLogger( AppliExec.class.getName() );		// ログ出力

	/** GE74 テーブルのカラム定義の enum */
	public static enum GE74 {
		/** GE74 テーブルから検索するカラム名 */
		RUNTYPE,RUNPG,PARAMS,TORIID,DBID,TABLE_NAME,SHT_NOS,READER_CLS,FILE_ENC,SKIP_CNT,NEXTID ;

		/** order by で、開始日時(ST_TIME)順に処理されるようにしておきます。 */
		private static final String FROM_WHERE = " from GE74 where SYSTEM_ID=? and EXECID=? and FGJ='1'" ;		// １件のみのはず

		/** 列挙子のカンマ区切り文字列 のキャッシュ  */
		public static final String SELECT ;
		static {
			final StringJoiner sj = new StringJoiner( "," , "select " , FROM_WHERE );
			Arrays.stream( values() ).forEachOrdered( v -> sj.add( v.name() ) );
			SELECT = sj.toString();
		}

		/** 列挙子の序数(カラムの並び順) */
		public final int NO ;

		/** private コンストラクター */
		private GE74() { NO = ordinal(); }
	};

	private static final ConcurrentMap<String,AppliExec> APP_EXEC_MAP = new ConcurrentHashMap<>();

	private final String[] ge74Data ;

	/**
	 * private コンストラクタ
	 *
	 * @param	systemId	システムID
	 * @param	execId	処理ID
	 */
	private AppliExec( final String systemId , final String execId ) {
		LOGGER.debug( () -> "[AppliExec] systemId=" + systemId + " , execId=" + execId );

		final List<String[]> cmdRow = DBUtil.dbQuery( GE74.SELECT , systemId , execId );

		if( cmdRow.isEmpty() ) {
			// MSG2001 = コマンドリストに、予約番号,取込ID,処理IDは必須です。[{0}]
			throw MsgUtil.throwException( "MSG2001" , "SYSTEM_ID=" + systemId + " , EXECID=" + execId );
		}

		ge74Data = cmdRow.get(0);		// １件のみのはず
	}

	/**
	 * システムIDと処理IDから、対応するAppliExecオブジェクトを返します。
	 *
	 * AppliExecオブジェクトを、動的に作成します。
	 * このメソッドは、ClassNotFoundException を拾うために、用意した簡易メソッドです。
	 *
	 * 何らかの Exception が、throw された場合は、null を返します。
	 *
	 * @param	systemId	システムID
	 * @param	execId	処理ID
	 * @return	AppliDataオブジェクト（作成できなければ、null）
	 */
	public static AppliExec newInstance( final String systemId , final String execId ) {
		final String mapKey = systemId + "_" + execId ;

		return APP_EXEC_MAP.computeIfAbsent( mapKey , key -> new AppliExec( systemId,execId ) );
	}

	/**
	 * GE74.RUNTYPE に基づいて、各種処理を実行します。
	 * 
	 * @param	path 処理するファイルパス
	 * @return	処理結果(true:正常/false:異常)
	 */
	public boolean exec( final Path path ) {
		LOGGER.debug( () -> "exec() : Path=" + path + " , runType=" + ge74Data[GE74.RUNTYPE.NO] );

		boolean rtn = false;
		try {
			switch( ge74Data[GE74.RUNTYPE.NO] ) {
				case "0" : rtn = true;					break;			// なにもしない
				case "1" : rtn = execDBin( path );		break;			// DB入力
				case "2" : rtn = execPLSQL( path );		break;			// PL/SQLコール
				case "3" : rtn = execBAT( path );		break;			// BATファイルコール
				case "4" : rtn = execJSP( path );		break;			// JSPファイルコール（URLコネクション）
				default  : rtn = false;					break;			// なにもしない(runTypeなしエラー)
			}
		}
		catch( final Throwable th ) {
			// MSG0021 = 予期せぬエラーが発生しました。\n\tﾒｯｾｰｼﾞ=[{0}]
			MsgUtil.errPrintln( th , "MSG0021" , path );
		}

		return rtn ;
	}

	/**
	 * データベースに追加処理を呼び出します。
	 * 
	 * @param	path 処理するファイルパス
	 * @return	処理結果(true:正常/false:異常)
	 */
	private boolean execDBin( final Path path ) {
		LOGGER.debug( () -> "execDBin() : Path=" + path );

		return true;
	}

	/**
	 * PL/SQLを呼び出します。
	 * 
	 * @param	path 処理するファイルパス
	 * @return	処理結果(true:正常/false:異常)
	 */
	private boolean execPLSQL( final Path path ) {
		LOGGER.debug( () -> "execPLSQL() : Path=" + path );

		return false;
	}

	/**
	 * バッチファイルを呼び出します。
	 * 
	 * @param	path 処理するファイルパス
	 * @return	処理結果(true:正常/false:異常)
	 */
	private boolean execBAT( final Path path ) {
		LOGGER.debug( () -> "execBAT() : Path=" + path );

		return false;
	}

	/**
	 * JSP を呼び出します。
	 * 
	 * @param	path 処理するファイルパス
	 * @return	処理結果(true:正常/false:異常)
	 */
	private boolean execJSP( final Path path ) {
		LOGGER.debug( () -> "execJSP() : Path=" + path );

		return false;
	}
}
