package com.blueland.config.quartz.service.impl;

import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import com.blueland.model.TPfSysTimetask;
import com.blueland.service.IParameterService;
import com.blueland.service.SysTimetaskService;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.blueland.config.quartz.service.ScheduleServiceI;
import com.blueland.core.util.StringUtil;
import com.blueland.bo.ParameterEntity;
import com.blueland.bo.SysTimetaskEntity;
import com.blueland.sys.timetask.telnet.TelnetTask;

import common.constant.CommonConstant;
import lombok.extern.slf4j.Slf4j;

/**
* @author zhengTao
* @version 创建时间：2019年4月26日 下午8:20:51
   * 类说明
*/
@Slf4j
@Service("scheduleService")
public class ScheduleServiceImpl implements ScheduleServiceI{

	@Autowired
    SysTimetaskService sysTimetaskService;
	@Autowired
    IParameterService iParameterService;
	
    private Scheduler scheduler = null;
    
    /**
      * 暴露接口
     */
    @Override
    public void proceedSchedule() {
        try {
            this.proceed();
        } catch (Exception ex) {
            log.error(ex.getMessage());
        }
 
    }
 
    //
    // 以下方法皆为 私有方法，请勿调用
    //
    private void proceed() throws Exception {

        SysTimetaskEntity condition = new SysTimetaskEntity();
        condition.setStatus(CommonConstant.TASKSTATUS_Y);
        List<SysTimetaskEntity> list = sysTimetaskService.findList(condition);

        if(null == list || list.isEmpty()) {
            return;
        }

        Set<String> currentScheduleCodeSet = this.getCurrentScheduleCodeSet();

        this.proceed(list, currentScheduleCodeSet);
    }
 
 
    /**
       * 细节调用
     * @param list
     * @param currentScheduleCodeSet
     * @throws Exception
     */
    private void proceed(List<SysTimetaskEntity> list, Set<String> currentScheduleCodeSet) throws Exception {
    	ParameterEntity  parameter = iParameterService.getBykey("jwt_token");
    	
        for(SysTimetaskEntity scheduleTask : list) {
            if(null == scheduleTask) {
                continue;
            }
            //本地定时任务处理
            if(CommonConstant.TASKTYPE_LOCAL.equals(scheduleTask.getTaskType())) {
	            if(CommonConstant.TASKSTATUS_Y.equals(scheduleTask.getStatus())) {//启用任务
	                if(!this.isTaskCodeExist(scheduleTask.getTaskCode(), currentScheduleCodeSet)) {//未在进程中
	                    this.startTask(scheduleTask);
	                }
	 
	            }
//	            else if (CommonConstant.TASKSTATUS_N.equals(scheduleTask.getStatus())) {//停用任务
//	                if(this.isTaskCodeExist(scheduleTask.getTaskCode(), currentScheduleCodeSet)) {//已在进程中
//	                    this.stopTask(scheduleTask);
//	                }
//	            }
            }else {
            	//远程如果状态是启用状态，那么还需要调用远程url
            	if(CommonConstant.TASKSTATUS_Y.equals(scheduleTask.getStatus())) {//启用任务
            		if(null != parameter && StringUtil.notEmpty(parameter.getPvalue())) {
            			String authorization = parameter.getPvalue();
            			this.startTask4Telnet(scheduleTask, authorization);
            		}
            	}
            }
        }
    }
 
 
    /**
     * 启用任务
   * @param scheduleTask
   * @throws Exception
   */
   @Override
   public void startTask(SysTimetaskEntity scheduleTask) throws Exception {
      if(!this.validate(scheduleTask)) {
          return;
      }
      ScheduleNaming naming = new ScheduleNaming(scheduleTask);
      Class<? extends Job> clazz = this.getJobClass(naming.getClassName());

      JobDetail jobDetail = this.getJobDetail(clazz, naming.getJobName());
      Trigger trigger = this.getTrigger(naming.getTriggerName(), naming.getScheduleConfiguration());

      this.scheduler.scheduleJob(jobDetail, trigger);
  }
   
   /**
    * 启用任务(远程)
  * @param scheduleTask
  * @throws Exception
  */
  @Override
  public void startTask4Telnet(SysTimetaskEntity scheduleTask,String authorization) throws Exception {
     if(!this.validate(scheduleTask)) {
         return;
     }
     ScheduleNaming naming = new ScheduleNaming(scheduleTask);
     TelnetTask task = new TelnetTask(authorization,scheduleTask.getAction(),scheduleTask.getTaskCode(),scheduleTask.getDescription());

     JobDetail jobDetail = this.getJobDetail(task.getClass(), scheduleTask.getId());
     Map<String,String> param = new HashMap<String,String>();
     param.put("authorization",authorization);
     param.put("url",scheduleTask.getAction());
     param.put("bizId",scheduleTask.getTaskCode());
	 param.put("bizType",scheduleTask.getDescription());
	 jobDetail.getJobDataMap().put("data",param);
     Trigger trigger = this.getTrigger(naming.getTriggerName(), naming.getScheduleConfiguration());

     this.scheduler.scheduleJob(jobDetail, trigger);
 }
 
    /**
     * 停用任务
     * @param scheduleTask
     * @throws Exception
     */
   public void stopTask(SysTimetaskEntity scheduleTask) throws Exception {
        if(!this.validate(scheduleTask)) {
            return;
        }
        ScheduleNaming naming = new ScheduleNaming(scheduleTask);
 
        this.scheduler.unscheduleJob(TriggerKey.triggerKey(naming.getTriggerName(), Scheduler.DEFAULT_GROUP));
        this.scheduler.deleteJob(JobKey.jobKey(naming.getJobName(), Scheduler.DEFAULT_GROUP));
    }
 
 
    /**
     * 验证参数
     * @param schedule
     * @return
     */
    private boolean validate(SysTimetaskEntity schedule) {
        if(null == schedule) {
            return false;
        } else if (null == schedule.getTaskCode()
                || null == schedule.getTaskType()
                || null == schedule.getCronExp()
                || null == schedule.getAction()) {
            return false;
        }
 
        return true;
    }
 
    /**
     * 必须返回 继承 Job 的 Class
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    @SuppressWarnings("unchecked")
    private Class<? extends Job> getJobClass(String className) throws ClassNotFoundException {
        return (Class<? extends Job>) Class.forName(className);
    }
 
 
    /**
     * 获取 jobDetail
     * @param clazz
     * @param jobName
     * @return
     */
    private JobDetail getJobDetail(Class<? extends Job> clazz, String jobName) {
        JobDetail jobDetail = JobBuilder.newJob(clazz)
                .withIdentity(jobName, Scheduler.DEFAULT_GROUP)
                .build()
                ;
 
        return jobDetail;
    }
 
 
    /**
     * 获取 trigger
     * @param triggerName
     * @param conf
     * @return
     */
    private Trigger getTrigger(String triggerName, String conf) {
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerName, Scheduler.DEFAULT_GROUP)
                .withSchedule(CronScheduleBuilder.cronSchedule(conf))
                .startNow()
                .build();
 
        return trigger;
    }
 
    private boolean isTaskCodeExist(String taskCode, Set<String> set) {
 
        return set.contains(taskCode);
    }
 
 
    private Set<String> getCurrentScheduleCodeSet() throws Exception{
 
        Set<JobKey> jobKeySet = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(Scheduler.DEFAULT_GROUP));
        Set<String> scheduleCodeSet = new HashSet<String>();
        for(JobKey jobKey : jobKeySet) {
            scheduleCodeSet.add(jobKey.getName());
        }
 
        return scheduleCodeSet;
 
    }
 
 
    /**
     * 内部类，用来统一定义名称
     */
    class ScheduleNaming {
        private String taskCode = "taskCode";
        private String className;
        private String triggerName;
        private String jobName;
        private String scheduleConfiguration;
 
        ScheduleNaming(SysTimetaskEntity schedule) {
            if(null != schedule.getTaskCode()) {
                this.taskCode = schedule.getTaskCode();
            }
            this.className = schedule.getAction();
            this.triggerName = this.taskCode;
            this.jobName = this.taskCode;
            this.scheduleConfiguration = schedule.getCronExp();
        }
 
        public String getClassName() {
            return className;
        }
 
        public String getTriggerName() {
            return triggerName;
        }
 
        public String getJobName() {
            return jobName;
        }
 
        public String getScheduleConfiguration() {
            return scheduleConfiguration;
        }
    }


	@Override
	public void setScheduler(Scheduler scheduler) {
		 this.scheduler = scheduler;
	}
 

}
