/*
 * Copyright (c) 2005- Shinji Kashihara.
 * All rights reserved. This program are made available under
 * the terms of the Eclipse Public License v1.0 which accompanies
 * this distribution, and is available at epl-v10.html.
 */
package jp.sourceforge.mergedoc.pleiades.runtime;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;

import jp.sourceforge.mergedoc.pleiades.log.Logger;

/**
 * 非同期実行キューです。
 * <p>
 * @author cypher256
 */
public class AsyncQueue {

	/** ロガー */
	private static final Logger log = Logger.getLogger(AsyncQueue.class);

	/** スレッド・プール */
	private static ExecutorService threadPool = Executors.newCachedThreadPool();

	/** スレッド・プール (待ち受け用) */
	private static ExecutorService threadPoolAwait = Executors.newCachedThreadPool();

	/**
	 * 生成できません。
	 */
	private AsyncQueue() {
	}

	/**
	 * 非同期実行キューにコマンドを追加します。
	 * @param command コマンド
	 * @param pool スレッド・プール
	 */
	private static void add(AsyncCommand command, ExecutorService pool) {

		if (pool == null) {
			// Eclipse 4.5 から多発するため警告ログに変更 2015.06.22
			/*
			String msg = "非同期実行はすでにシャットダウンされています。";
			log.fatal(msg);
			throw new IllegalStateException(msg);
			*/
			log.warn("非同期実行はすでにシャットダウンされているため、同期実行します。");
			command.run();
			return;
		}
		try {
			pool.execute(command);

		} catch (RejectedExecutionException e) {
			log.warn("RejectedExecutionException が発生したため、同期実行します。");
			command.run();
		}
	}

	/**
	 * 非同期実行キューにコマンドを追加します。
	 * @param command コマンド
	 */
	public static void add(AsyncCommand command) {
		add(command, threadPool);
	}

	/**
	 * 非同期実行待ち受けキューにコマンドを追加します。
	 * <ul>
	 * <li>主に -clean の設定を行うコマンドを登録します。
	 * <li>-clean 関連の処理は、追加したコマンドが終了するまで実行されません。
	 * </ul>
	 * @param command コマンド
	 */
	public static void addAwait(AsyncCommand command) {
		add(command, threadPoolAwait);
	}

	/**
	 * 非同期実行待ち受けキューの終了を待ちます。
	 */
	public static synchronized void awaitTermination() {

		if (threadPoolAwait != null) {
			log.debug("非同期実行待ち受けキューの終了待ちを開始します。");
			threadPoolAwait.shutdown();
			try {
				threadPoolAwait.awaitTermination(5, TimeUnit.SECONDS);
				log.debug("非同期実行待ち受けキューの終了待ちを終了します。");

			} catch (InterruptedException e) {
				log.warn("非同期実行待ち受けキューの終了待ちで割り込みが発生しました。");
			}
			threadPoolAwait = null;
		}
	}

	/**
	 * 非同期実行をシャットダウンします。
	 * すでにシャットダウンされている場合は何も行いません。
	 */
	public static synchronized void shutdown() {

		log.debug("非同期実行をシャットダウンします。");

		if (threadPool != null) {
			threadPool.shutdown();
			threadPool = null;
		}
		if (threadPoolAwait != null) {
			threadPoolAwait.shutdown();
			threadPoolAwait = null;
		}
	}
}
