package com.bocloud.ims.service.config;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.SchedulingException;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.config.TriggerTask;
import org.springframework.stereotype.Component;

import com.bocloud.ims.service.utils.BeanUtils;

/**
 * 
 * @ClassName: DefaultSchedulingConfigurer.java
 * @Description: 平台定时任务调度类
 *
 * @author: ymh
 * @date: 2021年3月16日 下午5:29:43
 */
@Component
@EnableScheduling
public class DefaultSchedulingConfigurer implements SchedulingConfigurer {

	private final String FIELD_SCHEDULED_FUTURES = "scheduledTasks";// "scheduledFutures";
	private ScheduledTaskRegistrar taskRegistrar;
	private Set<ScheduledFuture<?>> scheduledFutures = null;
	private Map<String, ScheduledFuture<?>> taskFutures = new ConcurrentHashMap<String, ScheduledFuture<?>>();
	private Map<String, String> taskCrons = new ConcurrentHashMap<String, String>();

	@Override
	public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
		this.taskRegistrar = taskRegistrar;
	}

	@SuppressWarnings("unchecked")
	private Set<ScheduledFuture<?>> getScheduledFutures() {
		if (scheduledFutures == null) {
			try {
				scheduledFutures = (Set<ScheduledFuture<?>>) BeanUtils.getProperty(taskRegistrar,
						FIELD_SCHEDULED_FUTURES);
			} catch (NoSuchFieldException e) {
				throw new SchedulingException("not found scheduledFutures field.");
			}
		}
		return scheduledFutures;
	}

	/**
	 * 添加任务
	 * 
	 * @param taskId
	 * @param triggerTask
	 */
	public void addTriggerTask(String taskId, TriggerTask triggerTask, String cron) {
		if (taskFutures.containsKey(taskId)) {
			throw new SchedulingException("the taskId[" + taskId + "] was added.");
		}
		TaskScheduler scheduler = taskRegistrar.getScheduler();
		ScheduledFuture<?> future = scheduler.schedule(triggerTask.getRunnable(), triggerTask.getTrigger());
		getScheduledFutures().add(future);
		taskFutures.put(taskId, future);
		taskCrons.put(taskId, cron);
	}

	/**
	 * 取消任务
	 * 
	 * @param taskId
	 */
	public void cancelTriggerTask(String taskId) {
		ScheduledFuture<?> future = taskFutures.get(taskId);
		if (future != null) {
			future.cancel(true);
		}
		getScheduledFutures().remove(future);
		taskFutures.remove(taskId);
		taskCrons.remove(taskId);
	}

	/**
	 * 重置任务
	 * 
	 * @param taskId
	 * @param triggerTask
	 */
	public void resetTriggerTask(String taskId, TriggerTask triggerTask, String cron) {
		cancelTriggerTask(taskId);
		addTriggerTask(taskId, triggerTask, cron);
	}

	/**
	 * 任务编号
	 * 
	 * @return
	 */
	public Set<String> taskIds() {
		return taskFutures.keySet();
	}
	
	public Set<String> taskIds(String prefix) {
		Set<String> keySet = taskFutures.keySet() == null ? new HashSet<String>() : taskFutures.keySet();
		if (!StringUtils.isEmpty(prefix)) {
			keySet = keySet.stream().filter(taskId -> taskId.startsWith(prefix)).collect(Collectors.toSet());
		}
		return keySet;
	}

	/**
	 * 任务编号
	 * 
	 * @return
	 */
	public String getTaskCron(String taskId) {
		return taskCrons.get(taskId);
	}

	/**
	 * 清空当前定时全部定时任务
	 * 
	 * @return
	 */
	public void clearTasks() {
		for (String taskId : taskIds()) {
			this.cancelTriggerTask(taskId);
		}
		taskFutures.clear();
		taskCrons.clear();
	}
	
	public void clearTasks(String prefix) {
		Set<String> taskIds = taskIds();
		for (String taskId : taskIds) {
			if (!StringUtils.isEmpty(prefix) && taskId.startsWith(prefix)) {
				this.cancelTriggerTask(taskId);
			}
		}
	}

	/**
	 * 是否存在任务
	 * 
	 * @param taskId
	 * @return
	 */
	public boolean hasTask(String taskId) {
		return this.taskFutures.containsKey(taskId);
	}

	/**
	 * 任务调度是否已经初始化完成
	 * 
	 * @return
	 */
	public boolean inited() {
		return this.taskRegistrar != null && this.taskRegistrar.getScheduler() != null;
	}
}
