/*
 * Copyright (C) 2020 the original author or authors.
 *
 * 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 vip.justlive.oxygen.core.util.concurrent;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import lombok.experimental.UtilityClass;
import vip.justlive.oxygen.core.CoreConfigKeys;
import vip.justlive.oxygen.core.util.base.SecurityChecker;
import vip.justlive.oxygen.core.util.concurrent.SecurityThreadPoolExecutor.PoolQueue;
import vip.justlive.oxygen.core.util.timer.WheelTimer;

/**
 * 线程工具类
 *
 * @author wubo
 */
@UtilityClass
public class ThreadUtils {

  private final ThreadLocal<Map<String, Object>> LOCAL = ThreadLocal.withInitial(HashMap::new);

  private ThreadFactory threadFactory;
  private SecurityThreadPoolExecutor globalPool;
  private WheelTimer globalTimer;

  /**
   * 线程存储键值
   *
   * @param key 键
   * @param value 值
   */
  public void putVal(String key, Object value) {
    LOCAL.get().put(key, value);
  }

  /**
   * 获取线程存储的值
   *
   * @param key 键
   * @param <T> 泛型类
   * @return 值
   */
  @SuppressWarnings("unchecked")
  public <T> T getVal(String key) {
    return (T) LOCAL.get().get(key);
  }

  /**
   * 清除线程存储值
   */
  public void clear() {
    LOCAL.remove();
  }

  /**
   * 构造线程池
   *
   * @param corePoolSize 线程数
   * @param maxPoolSize 最大线程数
   * @param keepAliveSeconds 空闲线程等待时间
   * @param queueCapacity 队列大小
   * @param nameFormat 线程名称format
   * @return 线程池
   */
  public SecurityThreadPoolExecutor newThreadPool(int corePoolSize, int maxPoolSize,
      int keepAliveSeconds, int queueCapacity, String nameFormat) {
    return newThreadPool(corePoolSize, maxPoolSize, keepAliveSeconds, queueCapacity, nameFormat,
        true);
  }

  /**
   * 构造线程池
   *
   * @param corePoolSize 线程数
   * @param maxPoolSize 最大线程数
   * @param keepAliveSeconds 空闲线程等待时间
   * @param queueCapacity 队列大小
   * @param nameFormat 线程名称format
   * @param daemon 是否为守护线程
   * @return 线程池
   */
  public SecurityThreadPoolExecutor newThreadPool(int corePoolSize, int maxPoolSize,
      int keepAliveSeconds, int queueCapacity, String nameFormat, boolean daemon) {
    return newThreadPool(corePoolSize, maxPoolSize, keepAliveSeconds, queueCapacity, nameFormat,
        new ThreadPoolExecutor.AbortPolicy(), daemon);
  }

  /**
   * 构造线程池
   *
   * @param corePoolSize 线程数
   * @param maxPoolSize 最大线程数
   * @param keepAliveSeconds 空闲线程等待时间
   * @param queueCapacity 队列大小
   * @param nameFormat 线程名称format
   * @param handler 拒绝策略
   * @return 线程池
   */
  public SecurityThreadPoolExecutor newThreadPool(int corePoolSize, int maxPoolSize,
      int keepAliveSeconds, int queueCapacity, String nameFormat,
      RejectedExecutionHandler handler) {
    return newThreadPool(corePoolSize, maxPoolSize, keepAliveSeconds, queueCapacity, nameFormat,
        handler, true);
  }

  /**
   * 构造线程池
   *
   * @param corePoolSize 线程数
   * @param maxPoolSize 最大线程数
   * @param keepAliveSeconds 空闲线程等待时间
   * @param queueCapacity 队列大小
   * @param nameFormat 线程名称format
   * @param handler 拒绝策略
   * @param daemon 是否为守护线程
   * @return 线程池
   */
  public SecurityThreadPoolExecutor newThreadPool(int corePoolSize, int maxPoolSize,
      int keepAliveSeconds, int queueCapacity, String nameFormat, RejectedExecutionHandler handler,
      boolean daemon) {
    PoolQueue queue = new PoolQueue(queueCapacity);
    SecurityThreadPoolExecutor pool = new SecurityThreadPoolExecutor(corePoolSize, maxPoolSize,
        keepAliveSeconds, TimeUnit.SECONDS, queue,
        new ThreadFactoryBuilder().setNameFormat(nameFormat).setDaemon(daemon).build(), handler);
    queue.setPool(pool);
    return pool;
  }

  /**
   * 构造定时任务池
   *
   * @param corePoolSize 线程数
   * @param nameFormat 线程名称format
   * @return 任务池
   */
  public ScheduledExecutorService newScheduledExecutor(int corePoolSize, String nameFormat) {
    return newScheduledExecutor(corePoolSize, nameFormat, new ThreadPoolExecutor.AbortPolicy());
  }

  /**
   * 构造定时任务池
   *
   * @param corePoolSize 线程数
   * @param nameFormat 线程名称format
   * @param handler 拒绝策略
   * @return 任务池
   */
  public ScheduledExecutorService newScheduledExecutor(int corePoolSize, String nameFormat,
      RejectedExecutionHandler handler) {
    return new ScheduledThreadPoolExecutor(corePoolSize,
        new ThreadFactoryBuilder().setNameFormat(nameFormat).setDaemon(true).build(), handler);
  }

  /**
   * 线程sleep等待
   *
   * @param millis 毫秒值
   */
  public void sleep(long millis) {
    sleep(millis, TimeUnit.MILLISECONDS);
  }

  /**
   * 线程sleep等待
   *
   * @param time 时间
   * @param unit 单位
   */
  public void sleep(long time, TimeUnit unit) {
    try {
      unit.sleep(time);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
  }

  /**
   * 默认全局线程工厂
   *
   * @return ThreadFactory
   */
  public synchronized ThreadFactory defaultThreadFactory() {
    if (threadFactory == null) {
      threadFactory = new ThreadFactoryBuilder().setDaemon(true).setPriority(Thread.NORM_PRIORITY)
          .setNameFormat("def-pool-%d").build();
    }
    return threadFactory;
  }

  /**
   * 添加关闭钩子
   *
   * @param runnable 任务
   * @return Thread
   */
  public Thread addShutdownHook(Runnable runnable) {
    Thread thread = defaultThreadFactory().newThread(runnable);
    Runtime.getRuntime().addShutdownHook(thread);
    return thread;
  }

  /**
   * 全局pool
   *
   * @return pool
   */
  public synchronized SecurityThreadPoolExecutor globalPool() {
    if (globalPool == null) {
      globalPool = newThreadPool(1, CoreConfigKeys.THREAD_POOL_SIZE.castValue(int.class), 120,
          CoreConfigKeys.THREAD_POOL_QUEUE.castValue(int.class), "global-pool-%d");
      globalPool.setSecurityChecker(new SecurityChecker()
          .addChecker(new OwnerThreadChecker(ThreadUtils.addShutdownHook(globalTimer::shutdown))));
    }
    return globalPool;
  }

  /**
   * 全局时间轮,通过以下参数可进行配置,默认为毫秒级时间轮
   *
   * @return WheelTimer
   */
  public synchronized WheelTimer globalTimer() {
    if (globalTimer == null) {
      globalTimer = new WheelTimer(CoreConfigKeys.WHEEL_TIMER_DURATION.castValue(long.class),
          CoreConfigKeys.WHEEL_TIMER_WHEEL_SIZE.castValue(int.class),
          CoreConfigKeys.WHEEL_TIMER_POOL_SIZE.castValue(int.class));
      globalTimer.getSecurityChecker()
          .addChecker(new OwnerThreadChecker(ThreadUtils.addShutdownHook(globalTimer::shutdown)));
    }
    return globalTimer;
  }
}