package cc.smtweb.system.bpm.web.sys.oneTimeService;

import cc.smtweb.framework.core.common.SwConsts;
import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.exception.BizException;
import cc.smtweb.framework.core.exception.SwException;
import cc.smtweb.framework.core.session.UserSession;
import cc.smtweb.framework.core.util.DateUtil;
import cc.smtweb.framework.core.util.JsonUtil;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created by Akmm at 2018/11/27 23:40
 * 后台一次性系统任务工厂，不允许用户干预的、即时执行的任务
 */
public class OneTimeServiceFactory {
    //允许的最大线程个数
    private static final int max_thread_size = 200;
    private static OneTimeServiceFactory instance = null;

    static {
        instance = new OneTimeServiceFactory();
    }

    public static OneTimeServiceFactory getInstance() {
        return instance;
    }


    private ScheduledExecutorService schedule;

    private Map<String, Class<? extends BaseOneTimeHandler>> mapType = new HashMap<>();

    private OnetimeTaskHelper taskHelper = null;

    public OneTimeServiceFactory() {
    }

    public void regHandle(String type, Class<? extends BaseOneTimeHandler> cls) {
        mapType.put(type, cls);
    }

    public BaseOneTimeHandler getHandle(String type){
        Class<? extends BaseOneTimeHandler> cls = mapType.get(type);
        if (cls == null) throw new SwException("没有注册此服务类（" + type + "）！");

        try {
            return cls.newInstance();
        } catch (Exception e) {
            throw new SwException(e);
        }
    }

    public OnetimeTaskHelper getTasksHelper() {
        if (taskHelper == null) {
            synchronized (OnetimeTaskHelper.class) {
                if (taskHelper == null) {
                    taskHelper = new OnetimeTaskHelper(SwConsts.SysParam.machineId, DbEngine.getInstance().findDao(OnetimeTask.class));
                }
            }
        }
        return taskHelper;
    }

    /**
     * 添加任务
     * @param type 任务类别，必须先调用regHandle注册任务执行类
     * @param key 任务唯一key，同一type下不允许重复
     * @param name 任务名称，共查询时察看
     * @param bizId 业务id，可空，方便业务查询
     * @param inparams 执行Api时的输入参数，json格式字符串
     * @param us 登录信息
     * @throws Exception
     */
    public void push(String type, String key, String name, long bizId, String inparams, UserSession us) {
        if (getTasksHelper().isExistByKey(type, key)) {
            throw new BizException("该任务已经存在，不能新增！");
        }
        OnetimeTask task = new OnetimeTask();
        task.init();
        task.setType(type);
        task.setCode(key);
        task.setName(name);
        task.setBizId(bizId);
        task.setInparams(inparams);
        task.setStatu(OneTimeStatu.WAIT.value);
        task.setCreateTime(DateUtil.nowDateTimeLong());
        task.setCreateUserId(us.getUserId());

        schedule.schedule(new OneTimeSysService(task), 1L, TimeUnit.MILLISECONDS);
    }

    public void push(String type, String key, String name, long bizId, Map<String, Object> inparams, UserSession us) {
        push(type, key, name, bizId, JsonUtil.encodeString(inparams), us);
    }

    public void push(String type, String key, String name, long bizId) {
        push(type, key, name, bizId, "", UserSession.createSys());
    }

    /**
     * 重新执行指定任务
     * @param type 任务类别，必须先调用regHandle注册任务执行类
     * @param key 任务唯一key，同一type下不允许重复
     * @throws Exception
     */
    public void restart(String type, String key) {
        OnetimeTask task = getTasksHelper().findOneByTk(type, key);
        if (task != null && !task.isNew()) {
            schedule.schedule(new OneTimeSysService(task), 1L, TimeUnit.MILLISECONDS);
        }
    }

    //启动任务
    public void start() {
        if (schedule != null) {
            stop();
        }
        List<OnetimeTask> listService = getTasksHelper().findWaiting();
        schedule = Executors.newScheduledThreadPool(max_thread_size);
        for (OnetimeTask task : listService) {
            schedule.schedule(new OneTimeSysService(task), 10L, TimeUnit.SECONDS);
        }
    }

    //停止任务
    public void stop() {
        if (schedule != null) {
            schedule.shutdown();
        }
    }
}
