package ${domain}.frame.schedule;

import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.ErrorHandler;
import ${domain}.frame.utils.LogUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Scheduler extends ThreadPoolTaskScheduler implements ErrorHandler {

    private Map<String, TaskWrapper> taskMap = new HashMap<>();

    public Scheduler() {
        setErrorHandler(this);
        setPoolSize(4);
        initialize();
    }

    public boolean createOrRepeat(RunTask task) {
        if (taskMap.containsKey(task.taskId())) {
            ScheduledFuture<?> scheduledFuture = taskMap.get(task.taskId()).future;
            scheduledFuture.cancel(false);
        }
        taskMap.put(task.taskId(), new TaskWrapper(task));
        return true;
    }

    public boolean remove(String taskId) {
        if (taskMap.containsKey(taskId)) {
            ScheduledFuture<?> scheduledFuture = taskMap.get(taskId).future;
            scheduledFuture.cancel(false);
            taskMap.remove(taskId);
        }
        return true;
    }

    public boolean start(String taskId) {
        if (taskMap.containsKey(taskId)) {
            taskMap.get(taskId).run = true;
            taskMap.get(taskId).future = taskMap.get(taskId).target.schedule(this);
            return true;
        }
        return false;
    }

    public boolean stop(String taskId) {
        if (taskMap.containsKey(taskId)) {
            taskMap.get(taskId).run = false;
            ScheduledFuture<?> scheduledFuture = taskMap.get(taskId).future;
            scheduledFuture.cancel(false);
            return true;
        }
        return false;
    }

    public List<Schedule> taskList() {
        List<Schedule> result = new ArrayList<>();
        for (TaskWrapper taskWrapper : taskMap.values()) {
            Schedule schedule = new Schedule();
            schedule.setId(taskWrapper.taskId);
            schedule.setName(taskWrapper.taskName);
            schedule.setNote(taskWrapper.taskNote);
            schedule.setRun(taskWrapper.run);
            result.add(schedule);
        }
        return result;
    }

    @Override
    public void handleError(Throwable throwable) {
        LogUtil.dumpException(throwable);

<#if project.frameValue() &gt;= 3>
        String message = throwable.getMessage();
        Pattern compile = Pattern.compile("(\\[.*])执行异常！任务ID(\\(.*\\))");
        Matcher matcher = compile.matcher(message);
        if (matcher.find()) {
            String taskName = matcher.group(1);
            String taskId = matcher.group(2);
            xyz.wbsite.module.wsvr.mgr.LogerrManager logerrManager = xyz.wbsite.frame.auth.LocalData.getBean(xyz.wbsite.module.wsvr.mgr.LogerrManager.class);
            if (logerrManager != null)
                logerrManager.addErr("任务错误", "任务" + taskName + "执行错误", "任务" + taskName + "执行错误" + "，任务ID" + taskId);
        }
</#if>
    }

    class TaskWrapper {
        RunTask target;
        String taskId;
        String taskName;
        String taskNote;
        boolean run;
        ScheduledFuture<?> future;

        public TaskWrapper(RunTask runTask) {
            this.target = runTask;
            this.taskId = runTask.taskId();
            this.taskName = runTask.taskName();
            this.taskNote = runTask.taskNote();
            this.future = runTask.schedule(Scheduler.this);
            this.run = true;
        }
    }

    public static class Schedule {
        private String id;
        private String name;
        private String note;
        private boolean run;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getNote() {
            return note;
        }

        public void setNote(String note) {
            this.note = note;
        }

        public boolean isRun() {
            return run;
        }

        public void setRun(boolean run) {
            this.run = run;
        }
    }
}