package cc.smtweb.framework.core.mvc.scheduler.job;

import cc.smtweb.framework.core.mvc.scheduler.AbstractJob;
import cc.smtweb.framework.core.mvc.scheduler.AbstractJobExecutor;
import cc.smtweb.framework.core.mvc.scheduler.AbstractJobQueue;

import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

public class GroupJobQueue extends AbstractJobQueue {
    private Deque<AbstractJob> queue;
    private Set<String> keySet;
    private String currentJobName;

    public GroupJobQueue(AbstractJobExecutor jobManager) {
        super(jobManager);
    }

    private synchronized void setCurrent(AbstractJob job) {
        currentJobName = job.getName();
    }

    private synchronized AbstractJob pull() {
        AbstractJob result = null;

        if (queue != null) {
            result = queue.pop();

            if (result != null) {
                keySet.remove(result.getName());
            }
        }

        if (result != null) {
            this.currentJobName = result.getName();
        } else {
            this.currentJobName = null;
        }

        return result;
    }

    private synchronized boolean push(AbstractJob job) {
        String jobName = job.getName();

        if (jobName.equals(currentJobName)) {
            return false;
        }

        if (keySet == null) {
            keySet = new HashSet<>();
        } else if (keySet.contains(jobName)) {
            // 避免重复加入
            return false;
        }

        keySet.add(jobName);

        if (queue == null) {
            queue = new LinkedList<>();
        }

        queue.push(job);
        return true;
    }

    @Override
    public void execute(AbstractJob job) {
        if (tryLock()) {
            try {
                setCurrent(job);
                do {
                    super.execute(job);
                } while ((job = pull()) != null);
            } finally {
                unlock();
            }
        } else {
            push(job);
        }
    }
}
