package com.yanzuoguang.util.thread;

import com.yanzuoguang.util.helper.Event;
import com.yanzuoguang.util.exception.ExceptionHelper;
import com.yanzuoguang.util.helper.StringHelper;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 自动执行任务
 *
 * @author 颜佐光
 */
public class RunPlan {
    /**
     * 任务锁
     */
    private final Object lock = new Object();
    /**
     * 任务队列
     */
    private final List<RunPlanData> list = new ArrayList<>();
    /**
     * 增加时触发的事件队列
     */
    private final Event<Runnable> onAdd = new Event<>();
    /**
     * 增加时触发的事件队列
     */
    private final Event<Runnable> onRemove = new Event<>();
    /**
     * 单项成功执行时的事件队列
     */
    private final Event<Runnable> onItemExecuted = new Event<>();
    /**
     * 全部执行完时触发的事件队列
     */
    private final Event<Runnable> onExecuted = new Event<>();

    /**
     * 增加时触发的事件队列
     *
     * @return 事件队列
     */
    public Event<Runnable> getOnAdd() {
        return onAdd;
    }

    /**
     * 增加时触发的事件队列
     *
     * @return 事件队列
     */
    public Event<Runnable> getOnRemove() {
        return onRemove;
    }

    /**
     * 单项成功执行时的事件队列
     *
     * @return 事件队列
     */
    public Event<Runnable> getOnItemExecuted() {
        return onItemExecuted;
    }

    /**
     * 全部执行完时触发的事件队列
     *
     * @return 事件队列
     */
    public Event<Runnable> getOnExecuted() {
        return onExecuted;
    }

    /**
     * 执行完任务后,是否需要删除该任务,并且设置允许执行的最大错误
     *
     * @param isRemove 执行完成是否删除
     * @param maxError 最大错误次数
     */
    public final void run(boolean isRemove, int maxError) {
        for (int i = list.size() - 1; i >= 0; i--) {
            long now = System.currentTimeMillis();
            RunPlanData item;
            synchronized (this.lock) {
                item = list.size() > i ? list.get(i) : null;
            }

            if (item == null) {
                continue;
            }

            double millSeconds = 0;
            // 在Window CE中时间相减可能会出错
            try {
                // 处理非法改动时间
                if (item.getDate() > now) {
                    item.setDate(now);
                }
                millSeconds = (now - item.getDate());
            } catch (Exception ex) {
                ExceptionHelper.handleException(ThreadHelper.class, ex);
            }
            // 未到执行时间
            if (millSeconds <= item.getTime()) {
                continue;
            }

            if (maxError == -1 || item.getExecuteError() < maxError) {
                try {
                    item.addCount();
                    item.getExecute().run();
                    item.initError();

                    this.triggerEvent(this.onItemExecuted);
                } catch (Exception ex) {
                    ExceptionHelper.handleException(RunPlan.class, ex);
                }
                item.initDate();
            }

            try {
                if (isRemove) {
                    synchronized (this.lock) {
                        this.list.remove(i);
                        this.triggerEvent(this.onRemove);
                    }
                }
            } catch (Exception ex) {
                ExceptionHelper.handleException(RunPlan.class, ex);
            }
        }

        this.triggerEvent(this.onExecuted);
    }

    /**
     * 设置需要执行的任务
     *
     * @param run   需要执行的程序
     * @param vTime 间隔时间
     * @return 执行标志
     */
    public final String set(Runnable run, int vTime) {
        // 创建临时任务数据
        RunPlanData temp = new RunPlanData();
        temp.setFlag(StringHelper.getNewID());
        temp.setExecute(run);
        temp.setTime(vTime);

        synchronized (lock) {
            list.add(temp);
        }

        this.triggerEvent(this.onAdd);
        return temp.getFlag();
    }

    /**
     * 清除需要执行的任务
     *
     * @param flag 执行标志
     */
    public final void remove(String flag) {
        synchronized (lock) {
            for (RunPlanData item : this.list) {
                if (item.getFlag().equals(flag)) {
                    this.list.remove(item);
                    this.triggerEvent(this.onRemove);
                    break;
                }
            }
        }
    }

    /**
     * 清除需要执行的任务
     *
     * @param run 执行的方法,注意有多个同样的方法时,只会清除第一个
     */
    public final void remove(Runnable run) {
        synchronized (lock) {
            for (RunPlanData item : this.list) {
                if (item.getExecute().equals(run)) {
                    this.list.remove(item);
                    this.triggerEvent(this.onRemove);
                    break;
                }
            }
        }
    }

    /**
     * 触发事件
     *
     * @param run 需要触发的事件队列
     */
    private void triggerEvent(Event<Runnable> run) {
        try {
            if (run != null) {
                run.exeucte(new RunExecute());
            }
        } catch (Exception ex) {
            ExceptionHelper.handleException(ThreadHelper.class, ex);
        }
    }

    /**
     * 获取需要执行的任务长度
     *
     * @return 长度信息
     */
    public final int getCount() {
        return this.list.size();
    }
}