package com.xmomen.module.schedule;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.text.ParseException;

/**
 * 任务管理器，当前仅支持一个任务对应一个触发器，如需要定义复杂任务，需添加相应方法
 * Created by Jeng on 2016/2/23.
 */
public class QuartzManager {
    // 静态的调度器工厂对象，用于创建调度器实例
    private static SchedulerFactory gSchedulerFactory = new StdSchedulerFactory();

    /**
     * 添加定时任务的方法。
     *
     * @param jobName 任务名称
     * @param jobGroup 任务组名称
     * @param cls 任务执行类的 Class 对象
     * @param time cron 表达式，用于设置任务的触发时间
     * @throws SchedulerException 当调度器操作出现异常时抛出
     * @throws ParseException 当解析 cron 表达式出现异常时抛出
     */
    public static void addJob(String jobName, String jobGroup, Class cls, String time) throws SchedulerException, ParseException {
        // 获取调度器实例
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        // 根据任务名和任务组获取任务详情
        JobDetail jobDetail = scheduler.getJobDetail(jobName, jobGroup);
        // 如果任务详情已存在，则抛出异常
        if (jobDetail != null) {
            throw new SchedulerException("exist this jobDetail, jobName: " + jobName + ", jobGroup: " + jobGroup + "");
        }
        // 创建新的任务详情对象，指定任务名、任务组和任务执行类
        jobDetail = new JobDetail(jobName, jobGroup, cls);
        // 创建新的 Cron 触发器对象，指定触发器名和触发器组
        CronTrigger trigger = new CronTrigger(jobName, jobGroup);
        // 设置触发器的 cron 表达式
        trigger.setCronExpression(time);
        // 将任务详情和触发器绑定并添加到调度器中
        scheduler.scheduleJob(jobDetail, trigger);
        // 如果调度器未关闭，则启动调度器
        if (!scheduler.isShutdown()) {
            scheduler.start();
        }
    }

    /**
     * 修改一个任务的触发时间的方法。
     *
     * @param triggerName 触发器名称
     * @param triggerGroupName 触发器组名称
     * @param time 新的 cron 表达式
     * @throws SchedulerException 当调度器操作出现异常时抛出
     * @throws ParseException 当解析 cron 表达式出现异常时抛出
     */
    public static void modifyJobTime(String triggerName, String triggerGroupName, String time) throws SchedulerException, ParseException {
        // 获取调度器实例
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        // 根据触发器名和触发器组获取触发器对象
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerName, triggerGroupName);
        // 如果触发器不存在，则直接返回
        if (trigger == null) {
            return;
        }
        // 获取触发器原来的 cron 表达式
        String oldTime = trigger.getCronExpression();
        // 如果新的 cron 表达式与原来的不同，则进行修改
        if (!oldTime.equalsIgnoreCase(time)) {
            CronTrigger ct = (CronTrigger) trigger;
            // 设置新的 cron 表达式
            ct.setCronExpression(time);
            // 重启触发器
            scheduler.resumeTrigger(triggerName, triggerGroupName);
        }
    }

    /**
     * 移除一个任务的方法（使用默认的任务组名，触发器名，触发器组名）。
     *
     * @param jobName 任务名称
     * @param jobGroup 任务组名称
     * @throws SchedulerException 当调度器操作出现异常时抛出
     */
    public static void removeJob(String jobName, String jobGroup) throws SchedulerException {
        // 获取调度器实例
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        // 如果任务详情不存在，则直接返回
        if (scheduler.getJobDetail(jobName, jobGroup) == null) {
            return;
        }
        // 如果触发器状态不是暂停状态，则暂停触发器
        if (Trigger.STATE_PAUSED != scheduler.getTriggerState(jobName, jobGroup)) {
            scheduler.pauseTrigger(jobName, jobGroup);
        }
        // 移除触发器
        scheduler.unscheduleJob(jobName, jobGroup);
        // 删除任务
        scheduler.deleteJob(jobName, jobGroup);
    }

    /**
     * 启动任务调度器中所有定时任务的方法。
     *
     * @throws SchedulerException 当调度器操作出现异常时抛出
     */
    public static void startJobs() throws SchedulerException {
        // 获取调度器实例并启动
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        scheduler.start();
    }

    /**
     * 关闭任务调度器的方法。
     *
     * @throws SchedulerException 当调度器操作出现异常时抛出
     */
    public static void shutdownJobs() throws SchedulerException {
        // 获取调度器实例
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        // 如果调度器未关闭，则关闭调度器
        if (!scheduler.isShutdown()) {
            scheduler.shutdown();
        }
    }

    /**
     * 暂停定时任务的方法。
     *
     * @param jobName 任务名称
     * @param jobGroup 任务组名称
     * @throws SchedulerException 当调度器操作出现异常时抛出
     */
    public static void pauseJob(String jobName, String jobGroup) throws SchedulerException {
        // 获取调度器实例
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        // 如果触发器状态不是暂停状态，则暂停任务
        if (Trigger.STATE_PAUSED != scheduler.getTriggerState(jobName, jobGroup)) {
            scheduler.pauseJob(jobName, jobGroup);
        }
    }

    /**
     * 停止任务的方法。
     *
     * @param jobName 任务名称
     * @param jobGroup 任务组名称
     * @throws SchedulerException 当调度器操作出现异常时抛出
     */
    public static void unscheduleJob(String jobName, String jobGroup) throws SchedulerException {
        // 获取调度器实例并停止触发器
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        scheduler.unscheduleJob(jobName, jobGroup);
    }

    /**
     * 恢复已暂停的定时任务的方法。
     *
     * @param jobName 任务名称
     * @param jobGroup 任务组名称
     * @throws SchedulerException 当调度器操作出现异常时抛出
     */
    public static void resumeJob(String jobName, String jobGroup) throws SchedulerException {
        // 获取调度器实例并恢复任务
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        scheduler.resumeJob(jobName, jobGroup);
    }

    /**
     * 获取任务触发器状态的方法。
     *
     * @param jobName 任务名称
     * @param jobGroup 任务组名称
     * @return 触发器的状态（整数表示）
     * @throws SchedulerException 当调度器操作出现异常时抛出
     */
    public static int getJobTriggerState(String jobName, String jobGroup) throws SchedulerException {
        // 获取调度器实例并返回触发器状态
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        return scheduler.getTriggerState(jobName, jobGroup);
    }

    /**
     * 获取 scheduler 任务调度器的方法。
     *
     * @return 任务调度器实例
     * @throws SchedulerException 当获取调度器出现异常时抛出
     */
    public static Scheduler getScheduler() throws SchedulerException {
        // 从调度器工厂获取调度器实例
        return gSchedulerFactory.getScheduler();
    }

    /**
     * 获取任务明细对象的方法。
     *
     * @param jobName 任务名称
     * @param jobGroup 任务组名称
     * @return 任务明细对象
     * @throws SchedulerException 当获取任务明细出现异常时抛出
     */
    public static JobDetail getJobDetail(String jobName, String jobGroup) throws SchedulerException {
        // 获取调度器实例并返回任务明细对象
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        return scheduler.getJobDetail(jobName, jobGroup);
    }

    /**
     * 获取触发器对象的方法。
     *
     * @param jobName 任务名称
     * @param jobGroup 任务组名称
     * @return 触发器对象
     * @throws SchedulerException 当获取触发器出现异常时抛出
     */
    public static Trigger getTrigger(String jobName, String jobGroup) throws SchedulerException {
        // 获取调度器实例并返回触发器对象
        Scheduler scheduler = gSchedulerFactory.getScheduler();
        return scheduler.getTrigger(jobName, jobGroup);
    }

    /**
     * 判断任务是否正在运行的方法。
     *
     * @param jobName 任务名称
     * @param jobGroup 任务组名称
     * @return 如果任务正在运行则返回 true，否则返回 false
     * @throws SchedulerException 当获取触发器状态出现异常时抛出
     */
    public static boolean isRunning(String jobName, String jobGroup) throws SchedulerException {
        // 如果触发器状态为正常（运行中），则返回 true
        if (Trigger.STATE_NORMAL == getJobTriggerState(jobName, jobGroup)) {
            return true;
        }
        return false;
    }
}