package com.game.part.io;

import java.text.MessageFormat;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.game.part.ThreadNamingFactory;
import com.game.part.util.Assert;
import com.game.part.util.StringUtil;

/**
 * 异步 IO 过程
 * 
 * @author hjj2019
 * 
 */
class AsyncIoOperProc implements IIoOperProc<IIoOper> {
	/** 单例对象 */
	static final AsyncIoOperProc OBJ = new AsyncIoOperProc();

	/** 过程名称 */
	private static final String THREAD_NAME_PREFIX = "com.game::AsyncIoOperProc";
	/** 运行服务字典 */
	private final ConcurrentHashMap<String, ExecutorService> _execServMap = new ConcurrentHashMap<>();

	/**
	 * 类默认构造器
	 *
	 */
	private AsyncIoOperProc() {
	}

	@Override
	public void execute(IIoOper oper) {
		if (oper == null) {
			return;
		}

		// 将异步操作包装成一个有状态的对象, 
		// 然后带入 invokeDoInit, invokeDoIo 函数中!
		this.nextStep(new StatefulIoOper(oper));
	}

	/**
	 * 调用异步操作对象的 doInit 函数
	 * 
	 * @param oper
	 */
	private void invokeDoInit(StatefulIoOper oper) {
		if (oper == null) {
			return;
		}

		try {
			// 执行初始化过程并进入下一步
			oper.doInit();
			this.nextStep(oper);
		} catch (Exception ex) {
			// 记录错误日志
			IoOperLog.LOG.error(ex.getMessage(), ex);
		}
	}

	/**
	 * 调用异步操作对象的 doIo 函数
	 * 
	 * @param oper
	 * 
	 */
	private void invokeDoIo(StatefulIoOper oper) {
		if (oper == null ||
			StringUtil.isNullOrEmpty(oper.getThreadKey())) {
			// 如果参数对象为空, 
			// 则直接退出!
			IoOperLog.LOG.error(
				"异步操作对象为空, 或者 key 为空"
			);
			return;
		}

		// 获取执行服务
		ExecutorService execServ = this.getES(oper.getThreadKey());

		if (execServ == null) {
			// 如果执行服务为空, 
			// 则直接退出!
			return;
		}

		// 提交多线程服务
		execServ.submit(() -> {
			try {
				// 执行 IO 操作
				oper.doIo();
			} catch (Exception ex) {
				// 记录错误日志
				IoOperLog.LOG.error(MessageFormat.format(
					"IO 线程 {0} 抛出异常 {1}",
					Thread.currentThread().getName(),
					ex.getMessage()
				), ex);
			}
		});
	}

	/**
	 * 获取多线程服务
	 *
	 * @param threadKey
	 * @return
	 *
	 */
	private ExecutorService getES(String threadKey) {
		// 断言参数不为空
		Assert.notNull(threadKey, "threadKey");

		// 获取线程池
		ExecutorService es = this._execServMap.get(threadKey);

		if (es == null) {
			// 如果线程池为空,
			// 则新建!
			// 在新建线程池之前需要加锁以避免创建多个对象...
			synchronized (this) {
				// 从字典中重新获取线程池,
				// 并做二次判断
				es = this._execServMap.get(threadKey);

				if (es == null) {
					// 如果二次判断之后还是空,
					// 那么创建线程池!
					es = Executors.newSingleThreadExecutor(new ThreadNamingFactory(
						THREAD_NAME_PREFIX + "::" + threadKey
					));
					// 将线程池添加到字典
					this._execServMap.put(threadKey, es);
				}
			}
		}

		return es;
	}

	/**
	 * 执行下一步操作
	 * 
	 * @param oper
	 */
	void nextStep(StatefulIoOper oper) {
		if (oper == null) {
			return;
		}

		IoOperStateEnum currState = oper.getCurrState();

		if (currState == null) {
			this.invokeDoInit(oper);
			return;
		}

		switch (oper.getCurrState()) {
			case exit:
			case ioFinished:
				return;

			case initOk:
				this.invokeDoIo(oper);
				return;

			default:
				return;
		}
	}
}

@@ -2155,18 +2155,21 @@
 Service 
-es
+oldES
  = this.
@@ -2200,26 +2200,29 @@
 ey);%0A%0A%09%09if (
-es
+oldES
  == null) %7B%0A
@@ -2341,18 +2341,21 @@
 %E6%AC%A1%E5%88%A4%E6%96%AD%0A%09%09%09%09
-es
+oldES
  = this.
@@ -2392,18 +2392,21 @@
 %09%09%09%09if (
-es
+oldES
  == null
@@ -2442,16 +2442,17 @@
 %09// %E9%82%A3%E4%B9%88%E5%88%9B%E5%BB%BA
+%E6%96%B0
 %E7%BA%BF%E7%A8%8B%E6%B1%A0!%0A%09%09%09
@@ -2453,18 +2453,37 @@
 %E6%B1%A0!%0A%09%09%09%09%09
-es
+ExecutorService newES
  = Execu
@@ -2608,24 +2608,32 @@
 %E6%B1%A0%E6%B7%BB%E5%8A%A0%E5%88%B0%E5%AD%97%E5%85%B8%0A%09%09%09%09%09
+oldES = 
 this._execSe
@@ -2641,16 +2641,24 @@
 vMap.put
+IfAbsent
 (threadK
@@ -2665,12 +2665,75 @@
 ey, 
-es);
+newES);%0A%09%09%09%09%09%0A%09%09%09%09%09if (oldES == null) %7B%0A%09%09%09%09%09%09oldES = newES;%0A%09%09%09%09%09%7D
 %0A%09%09%09
@@ -2754,18 +2754,21 @@
 %09return 
-es
+oldES
 ;%0A%09%7D%0A%0A%09/

修改 FindBug 中提示的错误;