/*
 * 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.Arrays;
import java.util.List;
import java.util.ArrayList;
// import java.util.Map;						// Collections.unmodifiableMap で使用
// import java.util.HashMap;					// Collections.unmodifiableMap で使用
import java.util.StringJoiner;
// import java.util.Collections;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;

import static org.opengion.fukurou.fileexec.CommandLine.GE70.* ;		// enum を簡素化して使用するための定義

/**
 * CommandLine は、コマンドリストを管理するクラスです。
 *
 *<pre>
 * コマンドリストは、GE70 テーブルからコマンドを取り出します。
 *
 * このクラスは、マルチスレッドに対応していません。
 *</pre>
 * @og.rev 7.0.0.0 (2017/07/07) 新規作成
 *
 * @version  7.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK1.8,
 */
public final class CommandLine {
	private static final XLogger LOGGER= XLogger.getLogger( CommandLine.class.getSimpleName() );		// ログ出力

	/** GE70 テーブルのカラム定義の enum */
	public enum GE70 {
//	public static enum GE70 {
		/** GE70 テーブルから検索するカラム名 */
		/** GE70 カラム */ SYSTEM_ID,
		/** GE70 カラム */ RSRV_NO,
		/** GE70 カラム */ NAME_JA,
		/** GE70 カラム */ EXECID,
		/** GE70 カラム */ FGYKAN,
		/** GE70 カラム */ DIR_BASE,
		/** GE70 カラム */ DIR_SUB,
		/** GE70 カラム */ DIR_WORK,
		/** GE70 カラム */ DIR_BKUP_OK,
		/** GE70 カラム */ DIR_BKUP_NG,
		/** GE70 カラム */ FILE_FILTER ;

		/** 取込予約ﾌﾗｸﾞ 1:実行 のみ処理。ORDER_BY も入れておきます。 */
		// 取込予約ﾌﾗｸﾞ 1:実行 2:停止
		private static final String FROM_WHERE = " from GE70 where FGJ='1' and FGYKAN='1' order by SYSTEM_ID,RSRV_NO" ;

//		/** order by で、SYSTEM_ID,RSRV_NO順に処理されるようにしておきます。 */
//		// 取込予約ﾌﾗｸﾞ 1:実行 2:停止
//		private static final String ORDER_BY = " order by SYSTEM_ID,RSRV_NO" ;

//		private static final String FGYKAN1 = "('1','3','4')" ;	// 起動直後
//		private static final String FGYKAN2 = "('1','4')" ;		// ループ処理

		/** 列挙子のCSV形式文字列 のキャッシュ  */
		public static final String SELECT  ;		// GE70検索
//		public static final String SELECT1 ;		// 起動直後
//		public static final String SELECT2 ;		// ループ処理
		static {
			final StringJoiner sj = new StringJoiner( "," , "select " , FROM_WHERE );
			Arrays.stream( values() ).forEachOrdered( v -> sj.add( v.name() ) );
			SELECT  = sj.toString() ;
//			SELECT1 = sj.toString() + FGYKAN1 + ORDER_BY ;
//			SELECT2 = sj.toString() + FGYKAN2 + ORDER_BY ;
		}

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

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

//	// 予約ﾌﾗｸﾞ は、値に応じて、セットする値が異なる。
//	/** Collections.unmodifiableMap を使用。 */
//	@SuppressWarnings( "serial" )
//	private static final Map<String,String> IN2OUT = Collections.unmodifiableMap(
//		new HashMap<String, String>() {{
//			put( "1" , "3" );		// 1:登録	→ 3:実行中
//			put( "4" , "2" );		// 4:停止	→ 2:済
//	}});

//	// 予約ﾌﾗｸﾞ は、値に応じて、セットする値が異なる。
//	// static イニシャライザで行う場合、ｴﾝｼﾞﾝのｿｰｽﾁｪｯｸで、警告5 が出るため、一時保留
//	private static final Map<String,String> IN2OUT;
//	static {
//		final Map<String,String> in2out = new HashMap<>();
//		in2out.put( "1" , "3" );		// 1:登録	→ 3:実行中
//		in2out.put( "4" , "2" );		// 4:停止	→ 2:済
//		IN2OUT = Collections.unmodifiableMap( in2out );
//	}

//	// GE70 で、IN2OUT に対応した予約ﾌﾗｸﾞ を更新します。
//	private static final String[] UPD_KEYS	= new String[] { "FGYKAN","DYUPD","PGUPD" };
//	private static final String   UPD_WHERE	= "SYSTEM_ID=? and RSRV_NO=? and FGJ='1'";
//
//	private static final String UPD_QUER = DBUtil.getUpdateSQL( "GE70",UPD_KEYS,null,null,UPD_WHERE );

//	// 7.2.5.3 (2020/06/16) 処理のスレッドを停止した時に、GF70.FGYKANを、3:実行中→1: 待機中  に更新する。
//	private static final String STOP_FGYKAN = "update GE70 set FGYKAN='1',DYUPD=?,PGUPD=? where FGYKAN='3'";

	private final String[]		cmndData	;
	private final String		cmndStr		;			// toString() 時に使用する、cmndList の文字列表現

	private final ConcurrentMap<String,String> kvMap = new ConcurrentHashMap<>();	// パラメータ(key1=val1 key2=val2 ･･･ のリスト)のMap

	/**
	 * データを引数にとるコンストラクタ
	 *
	 * SYSTEM_ID,RSRV_NO,NAME_JA,EXECID,FGYKAN,DIR_BASE,DIR_SUB,DIR_WORK,DIR_BKUP_OK,DIR_BKUP_NG,FILE_FILTER
	 * ｼｽﾃﾑID,予約番号,名称,処理ID,取込予約ﾌﾗｸﾞ,取込ﾍﾞｰｽﾌｫﾙﾀﾞ,取込ｻﾌﾞﾌｫﾙﾀﾞ,処理ﾌｫﾙﾀﾞ(WORK),処理済ﾌｫﾙﾀﾞ(正常),処理済ﾌｫﾙﾀﾞ(異常),検索条件 を
	 * 文字列として順番に持っています。
	 *
	 * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
	 *
	 * @param	values	データ
	 * @throws	RuntimeException 引数に不整合があった場合。
	 */
	private CommandLine( final String[] values ) {
		cmndData = Arrays.copyOf( values, values.length );

		cmndStr = Arrays.toString( cmndData );
		LOGGER.debug( () -> "① values=" + cmndStr );

		if( cmndData[RSRV_NO.NO] == null || cmndData[EXECID.NO] == null ) {
			// MSG3001 = コマンドリストに、予約番号,取込ID,処理IDは必須です。[{0}]
			throw MsgUtil.throwException( "MSG3001" , cmndStr );
		}

		// key=val のパラメータ文字列を、Map化します。
		final String filter = cmndData[FILE_FILTER.NO];						// 検索条件となるフィルター情報
		if( filter != null && !filter.trim().isEmpty() && filter.indexOf( '=' ) >= 0 ) {
			// 6番目のparamsは、key=valの羅列
			for( final String kvStr : filter.split( " " ) ) {				// スペースで分割
				final int ad = kvStr.indexOf( '=' );						// key=val を見つける。
				if( ad > 0 ) {
					final String key = kvStr.substring( 0,ad ).trim();
					final String val = kvStr.substring( ad+1 ).trim();
					if( !key.isEmpty() ) { kvMap.put( key , val ); }		// keyが空文字の場合は、無視
				}
			}
		}
	}

	/**
	 * 設定値を返します。
	 *
	 * @param	clm GE70ﾃｰﾌﾞﾙを定義したenum
	 * @return	設定値
	 */
	public String getValue( final GE70 clm ) { return cmndData[ clm.NO ]; }

	/**
	 * パラメータ(key1=val1 key2=val2 ･･･ のリスト)のMapを返します。
	 *
	 * @return	パラメータ(key1=val1 key2=val2 ･･･ のリスト)のMap
	 * @og.rtnNotNull
	 */
	public ConcurrentMap<String,String> getKeyValMap() { return kvMap ; }

	/**
	 * 指定のGE70テーブルを読み込んで、CommandLineオブジェクトのListを作成します。
	 *
//	 * @param	isFirst 起動直後の初期処理かどうかの判定ﾌﾗｸﾞ(起動直後は、true)
	 * @return	CommandLineオブジェクトのList
	 */
//	public static List<CommandLine> dbCommand( final boolean isFirst) {
	public static List<CommandLine> dbCommand() {
		final List<CommandLine> cmndList = new ArrayList<>();

//		// 更新用の値
//		final List<String[]> upddbData = new ArrayList<>();
//		final String NOW  = StringUtil.getTimeFormat();
//		final String PGID = "CMNDLine";

//		final List<String[]> cmdRow = DBUtil.dbQuery( isFirst ? SELECT1 : SELECT2 );	// GE70.SELECT
		final List<String[]> cmdRow = DBUtil.dbQuery( SELECT );							// GE70.SELECT
		for( final String[] cmdClms : cmdRow ) {
			cmndList.add( new CommandLine( cmdClms ) );

//			final String fgKan = IN2OUT.get( cmdClms[FGYKAN.NO] );			// 予約ﾌﾗｸﾞ
//			if( fgKan != null ) {				// 予約ﾌﾗｸﾞ が、対象の場合。
//				// 予約ﾌﾗｸﾞを、IN2OUT で変換した値に更新します。
//				// M_FileExec テーブルの更新カラム
//				final String[] updVals = new String[] {
//					  fgKan						// 予約ﾌﾗｸﾞ			FGYKAN
//					, NOW						// 更新日時			DYUPD
//					, PGID						// 更新PG			PGUPD
//					, cmdClms[SYSTEM_ID.NO]		// ｼｽﾃﾑID			SYSTEM_ID
//					, cmdClms[RSRV_NO.NO]		// 予約番号			RSRV_NO
//				} ;
//				upddbData.add( updVals );
//			}
		}

//		if( ! upddbData.isEmpty() ) {
//			DBUtil.execute( UPD_QUER , upddbData );
//		}

		return cmndList ;
	}

// 	/**
// 	 * 終了時に、クリアするために GE70テーブルを更新する。
// 	 *
// 	 * 予約ﾌﾗｸﾞ(FGYKAN)を、3:実行中 から 1: 待機中 に変更する。
// 	 *
// 	 * @og.rev 7.2.5.3 (2020/06/16) 処理のスレッドを停止した時に、GF70.FGYKANを、3:実行中→1: 待機中 に更新する。
// 	 */
// 	public static void stopFgykan() {
// 		// 更新用の値
// 		final String NOW  = StringUtil.getTimeFormat();
// 		final String PGID = "CMNDLine";
//
// 		DBUtil.execute( STOP_FGYKAN,NOW,PGID );	// 3:実行中→1: 待機中 に更新
// 	}

	/**
	 *コマンドリストクラスの文字列表現を返します。
	 *
	 * @return	コマンドリストクラスの文字列表現
	 */
	@Override
	public String toString() { return cmndStr ; }
}
