/*
 * 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.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;

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

/**
 * MainProcess は、単独で使用する ファイル取込システムのメインクラスです。
 *
 *<pre>
 * このクラスのmainメソッドから起動します。
 * コマンドラインを処理することで、各種処理を実行します。
 *
 *</pre>
 *
 * @og.rev 7.0.0.0 (2017/07/07) 新規作成
 *
 * @version  7.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK1.8,
 */
public final class MainProcess {
	private static final XLogger LOGGER= XLogger.getLogger( MainProcess.class.getName() );	// ログ出力

//	private final ConcurrentMap<Integer,FileExec> execMap = new ConcurrentHashMap<>();
	private final ConcurrentMap<String,FileExec> execMap = new ConcurrentHashMap<>();		// ｷｰは、systemId + rsrv_no

	/**
	 * デフォルトコンストラクター
	 */
	public MainProcess() { super(); }			// 必要ないが、とりあえず。

	/**
	 * 時間起動のタスクオブジェクトを起動します。
	 *
	 * コマンドリストは、予約番号,種別,号機指定,雛形ファイル,開始日時,実行間隔,終了日時,経過終了間隔,パラメータMAP を
	 * 文字列として順番に持っています。
	 * リストの数が、少ない場合は、それぞれ、初期値が使用されます。
	 * 最低、コマンド種別は、必要です。
	 *
	 * @param	cmndLine	CommandLineオブジェクト
	 */
	public void startTask( final CommandLine cmndLine ) {
//		// 同一予約番号の過去の依頼は停止しておきます。
//		final int yoyakuNo = Integer.parseInt( cmndLine.getValue( GE70.RSRV_NO ) );
//		stopTask( yoyakuNo );										// 一旦、予約を解除します。

		// タスクオブジェクトの起動前に、一旦過去の依頼は停止しておきます。
		final String systemId	= cmndLine.getValue( GE70.SYSTEM_ID );		// ｼｽﾃﾑID
		final String rsrvNo		= cmndLine.getValue( GE70.RSRV_NO );		// 予約番号
		final String mapKey		= systemId + "_" + rsrvNo ;
		stopTask( mapKey );													// 一旦、予約を解除します。

		// ※ 取込予約ﾌﾗｸﾞ(FGYKAN)は、DB検索時に、1:登録 4:停止 しか、来ません。
		final String fgkan = cmndLine.getValue( GE70.FGYKAN );		// 取込予約ﾌﾗｸﾞ 1:登録 2:済 3:実行中 4:停止
		if( "1".equals( fgkan ) || "3".equals( fgkan ) ) {			// 取込予約ﾌﾗｸﾞ(FGYKAN)が、1:登録 3:実行中 以外は、過去の依頼を停止した時点で、終了します。
			final FileExec fExec = new FileExec( cmndLine );

			LOGGER.info( () -> "startTask: yoyakuNo=[" + mapKey + "]" );

			fExec.watchStart();
//			execMap.put( yoyakuNo,fExec );
			execMap.put( mapKey,fExec );
		}
		else {
			LOGGER.warning( () -> "【WARNING】startTask: yoyakuNo=[" + mapKey + "] , fgkan=[" + fgkan + "]" );		// 6.8.1.5 (2017/09/08)
		}
	}

	/**
	 * 時間起動のタスクオブジェクトをキャンセルします。
	 *
//	 * @param	yoyakuNo	ｺﾏﾝﾄﾞ予約番号
	 * @param	mapKey		ｺﾏﾝﾄﾞ予約番号時のｷｰﾜｰﾄﾞ
	 */
//	private void stopTask( final int yoyakuNo ) {
	private void stopTask( final String mapKey ) {
//		final FileExec	fExec = execMap.remove( yoyakuNo );		// 取り消しなので、Mapから削除します。
		final FileExec	fExec = execMap.remove( mapKey );		// 取り消しなので、Mapから削除します。
		if( fExec != null ) {									// 完了(正常終了、例外、取り消し)以外は、キャンセルします。
			fExec.watchStop();
		}

		LOGGER.info( () -> "stopTask: yoyakuNo=[" + mapKey + "]" );
	}

	/**
	 * すべての成形機のセッションフォルダの監視を終了します。
	 *
	 */
	public void watchStop() {
		execMap.forEach( (no,fExec) -> fExec.watchStop() );
	}

	/** main メソッドから呼ばれる ヘルプメッセージです。 {@value} */
	public static final String USAGE = "Usage: java org.opengion.fukurou.fileexec.MainProcess [-LOOP n(秒)] [-help]" ;

	/**
	 * Euromapのミドルウエア(成形条件管理システム)のメインクラスを起動します。
	 *
	 * ベースフォルダを、指定しない場合は、アプリケーションの起動フォルダになります。(./)
	 *
	 * {@value #USAGE}
	 *
	 * @param	args 引数配列
	 */
	public static void main( final String[] args ) {
		// ********** 【整合性チェック】 **********

		// ********** 【引数定義】 **********
		int     loopTime	= 10;							// スキャンするインターバル(秒)

		// ********** 【引数処理】 **********
		for( int i=0; i<args.length; i++ ) {
			final String arg = args[i];

			if( "-help" .equalsIgnoreCase( arg ) ) { System.out.println( USAGE ); return ; }
			else if( "-LOOP" .equalsIgnoreCase( arg ) ) {
				loopTime = Integer.parseInt( args[++i] );		// ひとつ進める
			}
			else {
				// MSG2011 = コマンドリストの操作に失敗ました。形式をご確認ください。[{0}]
				throw MsgUtil.throwException( "MSG2011" , Arrays.toString( args ) );
			}
		}

		// ********** 【本体処理】 **********
		final MainProcess mainPrcs = new MainProcess();

		// ほぼ、暫定対応。無限ループで、DBを監視します。
		boolean isFirst = true;		// 最初だけ、FGYKAN=3:実行中 を検索する必要がある。
		int cnt = 0;
		while( true ) {
			try {
				final List<CommandLine> cmndList = CommandLine.dbCommand( isFirst );
				cmndList.forEach( cmndLine -> mainPrcs.startTask( cmndLine ) );
				try{ Thread.sleep( loopTime * 1000L ); } catch( final InterruptedException ex ){}
				isFirst = false;
				System.out.println( StringUtil.getTimeFormat( "yyyyMMdd HH:mm:ss [" + (cnt++) + "]" ) );	// 6.8.1.5 (2017/09/08)
			}
			catch( final Throwable th ) {
				// MSG0021 = 予期せぬエラーが発生しました。\n\tﾒｯｾｰｼﾞ=[{0}]
				MsgUtil.errPrintln( th , "MSG0021" , th.getMessage() );
				try{ Thread.sleep( 10 * loopTime * 1000L ); } catch( final InterruptedException ex ){}

				mainPrcs.watchStop();
			}
		}
	}
}
