package com.leanwo.activiti.service.base.impl;

import java.util.Date;

import javax.inject.Named;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.leanwo.activiti.dto.BaseResponse;
import com.leanwo.activiti.dto.base.TaskDefineDto;
import com.leanwo.activiti.dto.base.TaskType;
import com.leanwo.activiti.service.base.QuartzEngine;
import com.leanwo.activiti.util.LoginContextUtil;

/**
 * 任务调度框架 引擎 Spring Quartz 特点：
 * <ul>
 * <li>1. 默认多线程异步执行</li>
 * <li>2.
 * 一个任务在上一次调度未完成执行，下一次调度时间到时，会另起一个线程开始新的调度。在业务繁忙时，一个任务或许会有多个线程在执行，导致数据处理异常。</li>
 * <li>3. 单任务同步：配置属性，可以使一个任务的一次调度在未完成时，而不会开启下一次调度</li>
 * <li>4. 多个任务同时运行，任务之间没有直接的影响，多任务执行的快慢取决于CPU的性能</li>
 * </ul>
 * 
 * @author YangZhiJie 20190329
 *
 */
@Named
public class QuartzEngineImpl implements QuartzEngine {

	private static Logger logger = LoggerFactory.getLogger(QuartzEngineImpl.class);

	@Override
	public void start() throws SchedulerException {
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		if (scheduler.isStarted() == false) {
			scheduler.start();
		}
	}

	@Override
	public void stop() throws SchedulerException {
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		scheduler.shutdown();
	}

	@Override
	public void addProcessJob(Long accountId, TaskDefineDto taskDefineDto) throws SchedulerException {
		// 创建Scheduler
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

		// 任务
		JobKey jobKey = new JobKey(taskDefineDto.getId().toString(), ProcessReportJobGroup);
		String jobDescription = String.format("流程报表任务%s", taskDefineDto.toString());

		// 是否创建Job
		boolean createJob = false;
		JobDetail existJobDetail = scheduler.getJobDetail(jobKey);
		if (existJobDetail != null) {
			JobDataMap jobDataMap = existJobDetail.getJobDataMap();
			if (jobDataMap == null || jobDataMap.containsKey(TaskDefineDto) == false) {
				scheduler.deleteJob(jobKey);
				logger.info("删除现有的流程报表任务:" + taskDefineDto.toString());
				createJob = true;
			} else {
				TaskDefineDto existProcessReportExecutorDto = (TaskDefineDto) jobDataMap.get(TaskDefineDto);
				// 如果任务的内容相同，那么不重新创建JOB，否则重新创建JOB
				if (existProcessReportExecutorDto.toString().equals(taskDefineDto.toString())) {
					createJob = false;
				} else {
					scheduler.deleteJob(jobKey);
					logger.info("流程报表任务发生更改，删除现有的流程报表任务:" + taskDefineDto.toString());
					createJob = true;
				}
			}
		} else {
			createJob = true;
		}

		if (createJob) {
			JobDataMap jobDataMap = new JobDataMap();
			jobDataMap.put(TaskDefineDto, taskDefineDto);
			jobDataMap.put(AccountId, accountId);

			// 构建任务属性
			JobDetail jobDetail = JobBuilder.newJob(ProcessReportAutoRun.class).withDescription(jobDescription)
					.withIdentity(jobKey).setJobData(jobDataMap).build();

			// 触发器
			Date triggerDate = taskDefineDto.getStartDate();
			if (triggerDate == null) {
				triggerDate = new Date();
			} else {
				// 触发时间必须大于当前时间
				if (triggerDate.getTime() < new Date().getTime()) {
					triggerDate = new Date();
				}
			}
			String triggerDescription = String.format("流程报表触发器%s", taskDefineDto.toString());
			String triggerName = String.format("流程报表触发器%s", taskDefineDto.toString());

			// 构建触发器
			Trigger trigger = TriggerBuilder.newTrigger().withDescription(triggerDescription)
					.withIdentity(triggerName, ProcessReportTiggerGroup)
					.withSchedule(CronScheduleBuilder.cronSchedule(taskDefineDto.getCronExpression()))
					.startAt(triggerDate)// 不设置，默认为当前时间
					.build();

			// 调度器添加任务和触发器
			scheduler.scheduleJob(jobDetail, trigger);
			logger.info("添加流程报表任务:" + taskDefineDto.toString());
		}
	}

	@Override
	public void addHttpJob(Long accountId, TaskDefineDto taskDefineDto) throws SchedulerException {

		// 创建Scheduler
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

		JobKey jobKey = new JobKey(taskDefineDto.getId().toString(), HttpTaskJobGroup);
		String jobDescription = String.format("Http任务%s", taskDefineDto.toString());
		// 是否创建Job
		boolean createJob = false;
		JobDetail existJobDetail = scheduler.getJobDetail(jobKey);
		if (existJobDetail != null) {
			JobDataMap jobDataMap = existJobDetail.getJobDataMap();
			if (jobDataMap == null || jobDataMap.containsKey(HttpTask) == false) {
				scheduler.deleteJob(jobKey);
				logger.info("删除现有的HTTP任务:" + taskDefineDto.toString());
				createJob = true;
			} else {
				TaskDefineDto existProcessReportExecutorDto = (TaskDefineDto) jobDataMap.get(HttpTask);
				// 如果任务的内容相同，那么不重新创建JOB，否则重新创建JOB
				if (existProcessReportExecutorDto.toString().equals(taskDefineDto.toString())) {
					createJob = false;
				} else {
					scheduler.deleteJob(jobKey);
					logger.info("HTTP任务发生更改，删除现有的HTTP任务:" + taskDefineDto.toString());
					createJob = true;
				}
			}
		} else {
			createJob = true;
		}

		if (createJob) {
			JobDataMap jobDataMap = new JobDataMap();
			jobDataMap.put(HttpTask, taskDefineDto);
			jobDataMap.put(AccountId, accountId);

			JobDetail jobDetail = JobBuilder.newJob(HttpTaskJob.class).withDescription(jobDescription)
					.withIdentity(jobKey).setJobData(jobDataMap).build();

			// 触发器
			Date triggerDate = taskDefineDto.getStartDate();
			if (triggerDate == null) {
				triggerDate = new Date();
			} else {
				// 触发时间必须大于当前时间
				if (triggerDate.getTime() < new Date().getTime()) {
					triggerDate = new Date();
				}
			}
			String triggerDescription = String.format("Http任务触发器%s", taskDefineDto.toString());
			String triggerName = String.format("Http任务触发器%s", taskDefineDto.toString());

			Trigger trigger = TriggerBuilder.newTrigger().withDescription(triggerDescription)
					.withIdentity(triggerName, HttpTaskTiggerGroup)
					.withSchedule(CronScheduleBuilder.cronSchedule(taskDefineDto.getCronExpression()))
					.startAt(triggerDate)// 不设置，默认为当前时间
					.build();

			// 加入这个调度
			scheduler.scheduleJob(jobDetail, trigger);
			logger.info("添加HTTP任务:" + taskDefineDto.toString());
		}
	}

	@Override
	public void deleteProcessJob(Long accountId, TaskDefineDto taskDefineDto) throws SchedulerException {
		// 创建Scheduler
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

		// 任务
		JobKey jobKey = new JobKey(taskDefineDto.getId().toString(), ProcessReportJobGroup);

		JobDetail existJobDetail = scheduler.getJobDetail(jobKey);
		JobDataMap jobDataMap = existJobDetail.getJobDataMap();
		if (jobDataMap != null && jobDataMap.containsKey(TaskDefineDto) == true) {
			scheduler.deleteJob(jobKey);
			logger.info("删除现有的流程报表任务:" + taskDefineDto.toString());
		}
	}

	@Override
	public void deleteHttpJob(Long accountId, TaskDefineDto taskDefineDto) throws SchedulerException {
		// 创建Scheduler
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

		// 任务
		JobKey jobKey = new JobKey(taskDefineDto.getId().toString(), HttpTaskJobGroup);

		JobDetail existJobDetail = scheduler.getJobDetail(jobKey);
		JobDataMap jobDataMap = existJobDetail.getJobDataMap();
		if (jobDataMap != null && jobDataMap.containsKey(HttpTask) == true) {
			scheduler.deleteJob(jobKey);
			logger.info("删除现有的HTTP任务:" + taskDefineDto.toString());
		}
	}
}
