package com.ozs.da.service.job.impl;

import com.ozs.da.constant.Constant;
import com.ozs.da.entity.task.Task;
import com.ozs.da.service.job.JobPutService;
import org.apache.commons.lang.time.DateUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.CronExpression;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * @author 许明
 * on 2019/3/6.
 * @version 2.0.0
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class JobPutServiceImpl implements JobPutService {

    private static final Logger logger = LogManager.getLogger(JobPutServiceImpl.class);

    @Override
    public void jobRunConditionJudge(Task task) {
        logger.info("进入job执行条件判断Thread,job[" + task.getId() + "]");
        boolean isRunnable = isRunnable(task);
        //如果满足运行条件，则job放到quartz执行
        if (isRunnable) {
            SchedulerTimeTriggeJob.scheduler(task);
        }
        else{
        	logger.info("JOB[" + task.getId() + "]不满足启用条件，无法启用！");
        }
        logger.info("thread end =======");
    }

    @Override
    public boolean isRunnable(Task task) {
        boolean flag = true;
        try {
        	if("2".equals(task.getRunStatus())){
        		logger.info("JOB[" + task.getId() + "]未启用，启用后生效！");
            	return false;
        	}
            //job处于等待运行或运行中状态，无法再次启用
            if(!"0,3,4".contains(task.getRunStatus())){
            	logger.info("JOB[" + task.getId() + "]处于等待运行或运行中状态，无法再次启用！");
            	return false;
            }
            // TODO: 2019/3/8 如果后续有其他触发类型，再进行触发类型的判断
//            flag = fixeTimeTrigger(task);
        } catch (Exception e) {
            logger.error("判断JOB[jobId=" + task.getId() + "]是否达到运行条件出错！", e);
        }
        return flag;
    }


    /**
     * @param task 一个JOB任务
     * @return true:满足运行条件，false:不满足运行条件
     * @description 定时触发
     */
    private boolean fixeTimeTrigger(Task task) throws Exception {
        try {
            String taskCron = task.getTaskCron();
            // 正常跑数据的流程判断 0,0,8,*,*,?
            CronExpression cronExpression = new CronExpression(taskCron);
            Date nextValidTime = cronExpression.getNextValidTimeAfter(getReference(task));
            nextValidTime = filterNextValidTime(task, nextValidTime);
            if (nextValidTime != null) {
                Date date = new Date();
                // 计算配置调度时间和当前时间时间间隔
                long timeInterval = date.getTime() - nextValidTime.getTime();
                return timeInterval >= -1000;
            }
        } catch (ParseException e) {
            logger.error("JOB[jobId=" + task.getId() + "]的Cron表达式错误！", e);
        }
        return false;
    }

    /**
     * @param job 一个JOB任务
     * @return Date:按 不同周期类型格式化后的当前时间
     * @description 获取当前JOB的下次运行时间的参照时间点
     */
    private Date getReference(Task job) {
        Date current = null;
        try {
            job.setDataFormat(getDataFormatByPeriodType(job.getPeriodType()));
            SimpleDateFormat format = new SimpleDateFormat(job.getDataFormat());
            String current4format = format.format(new Date());
            current = format.parse(current4format);
        } catch (ParseException e) {
            logger.error("JOB[" + job.getId() + "]数据日期和数据日期格式不匹配！", e);
        }
        return current;
    }

    private String getDataFormatByPeriodType(int periodType){
        String dataFormat = "";
        switch (periodType){
            case 1:
                dataFormat = "yyyyMM";
                break;
            case 2:
                dataFormat = "yyyyMMdd";
                break;
            case 3:
                dataFormat = "yyyyMMddHH";
                break;
            case 4:
                dataFormat = "yyyyMMddHHmm";
                break;
            case 5:
                dataFormat = "yyyyMMddHHmmss";
                break;
            default:
                break;
        }
        return dataFormat;
    }

    private static Date filterNextValidTime(Task job, Date nextValidTime) {
        Date date = nextValidTime;// 下次运行时间
        if (null != job && null != nextValidTime) {
            int offset = -1;
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            boolean isMillisZero = (calendar.get(Calendar.MILLISECOND) == 0);
            boolean isSecondZero = (calendar.get(Calendar.SECOND) == 0);
            boolean isMinuteZero = (calendar.get(Calendar.MINUTE) == 0 && isSecondZero);
            boolean isHourZero = (calendar.get(Calendar.HOUR) == 0 && isMinuteZero);
            switch (job.getPeriodType()) {
                case Constant.JOB_PERIOD_YEAR:
                    break;
                case Constant.JOB_PERIOD_MONTH:
                    Calendar nowCalendar = Calendar.getInstance();
                    if (isHourZero) {
                        if (calendar.get(Calendar.YEAR) > nowCalendar.get(Calendar.YEAR)
                                || calendar.get(Calendar.MONTH) > nowCalendar.get(Calendar.MONTH)) {
                            date = DateUtils.addMonths(nextValidTime, offset);
                        }
                    }
                    break;
                case Constant.JOB_PERIOD_WEEK:
                    Calendar nowCalendar2 = Calendar.getInstance();
                    if (isHourZero) {
                        if (calendar.get(Calendar.DAY_OF_WEEK) <= nowCalendar2.get(Calendar.DAY_OF_WEEK)) {
                            date = DateUtils.addWeeks(nextValidTime, offset);
                        }
                    } else {
                        if (calendar.get(Calendar.DAY_OF_WEEK) < nowCalendar2.get(Calendar.DAY_OF_WEEK)) {
                            date = DateUtils.addWeeks(nextValidTime, offset);
                        }
                    }
                    break;
                case Constant.JOB_PERIOD_DAY:
                    if (isHourZero) {
                        date = DateUtils.addDays(nextValidTime, offset);
                    }
                    break;
                case Constant.JOB_PERIOD_HOUR:
                    if (isMinuteZero) {
                        date = DateUtils.addHours(nextValidTime, offset);
                    }
                    break;
                case Constant.JOB_PERIOD_MINUTE:
                    if (isSecondZero) {
                        date = DateUtils.addMinutes(nextValidTime, offset);
                    }
                    break;
                case Constant.JOB_PERIOD_SECONDS:
                    if (isMillisZero) {
                        date = DateUtils.addSeconds(nextValidTime, offset);
                    }
                    break;
                default:
                    logger.warn("JOB[jobId==" + job.getId() + "]的周期类型配置错误！");
                    break;
            }
        }
        return date;
    }


    public static void main(String[] args) throws Exception{
        CronExpression cronExpression = new CronExpression("0 0 1 9 3 ? 2019");
        Date current = null;
        SimpleDateFormat format = new SimpleDateFormat("yyyMM");
        SimpleDateFormat format1 = new SimpleDateFormat("yyyMM");
        String current4format = format.format(new Date());
        current = format.parse(current4format);
        Date nextValidTime = cronExpression.getNextValidTimeAfter(current);

        System.out.println(format1.format(nextValidTime) +"=============1");
        Task task = new Task();
        task.setPeriodType(1);
        nextValidTime = filterNextValidTime(task, nextValidTime);

        System.out.println(format1.format(nextValidTime) +"------2");
        if (nextValidTime != null) {
            Date date = new Date();
            // 计算配置调度时间和当前时间时间间隔
            long timeInterval = date.getTime() - nextValidTime.getTime();
            System.out.println(timeInterval +"============");
            System.out.println(timeInterval >= -1000);
        }
    }
}
