package net.northking.cctp.upperComputer.deviceManager.thread.util;

/**
 * 线程工作<br>
 * 产生与线程块的待执行任务工作
 */
public class ThreadJob {

    private final LaunchBlock launchBlock;

    private final Object lock = new Object();

    private final long timeToRun;

    private Object result = null;

    ThreadJob(LaunchBlock block) {
        this(block, 0L);
    }

    public ThreadJob(LaunchBlock launchBlock, long timeToRun) {
        this.launchBlock = launchBlock;
        this.timeToRun = timeToRun;
    }

    /**
     * 是否有效
     */
    private boolean valid = true;

    /**
     * 是否已经运行结束
     */
    private boolean finish = false;

    public boolean isTimeToRun() {
        return System.currentTimeMillis() >= timeToRun && valid;
    }

    public void run() {
        try {
            launchBlock.run(this);
            finish = true;
            synchronized (lock) {
                lock.notifyAll();
            }
        } catch (Exception e) {
            synchronized (lock) {
                lock.notifyAll();
            }
            finish = true;
            throw e;
        }
    }

    /**
     * 等待至工作执行完成
     *
     * @throws InterruptedException 中断
     */
    public void join() throws InterruptedException {
        if (finish) return;
        synchronized (lock) {
            lock.wait();
        }
    }

    /**
     * 是否有效<br>
     * 无效的任务将不被执行
     *
     * @return 有效
     */
    public boolean isValid() {
        return valid;
    }

    /**
     * 取消工作
     * 取消后工作将无效，等待任务结束的线程将会被立即唤醒
     */
    public void cancel() {
        valid = false;
        synchronized (lock) {
            lock.notifyAll();
        }
    }

    /**
     * 是否保持运行<br>
     * 如果逻辑中需要判断是否应该继续而不是被取消工作，使用此方法判断
     *
     * @return 是否应继续运行逻辑
     */
    public boolean keepRun() {
        return valid && !finish;
    }

    /**
     * 设置工作结果，应该只在launch内调用
     *
     * @param result 工作结果
     */
    public void setResult(Object result) {
        if (!valid || finish) return;
        this.result = result;
    }

    /**
     * 获取返回结果
     *
     * @param clazz 返回对象的Class
     * @param <T>   返回对象的类型
     * @return 结果，如果对象类型与结果类型不一致，也会返回null
     */
    public <T> T getResult(Class<T> clazz) {
        if (result == null) return null;
        if (result.getClass() != clazz) {
            return null;
        }
        //noinspection unchecked
        return (T) result;
    }
}
