package com.github.otbproject.otbproject.messages.send;

import com.github.otbproject.otbproject.App;
import com.github.otbproject.otbproject.bot.Control;
import com.github.otbproject.otbproject.channel.Channel;
import com.github.otbproject.otbproject.config.BotConfig;
import com.github.otbproject.otbproject.config.Configs;
import com.github.otbproject.otbproject.util.ThreadUtil;
import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.PriorityBlockingQueue;

// This class is not in general thread-safe. Thread safety should be enforced by the
// class using this one
public class ChannelMessageSender {
    private static final ExecutorService EXECUTOR_SERVICE;

    private final Channel channel;
    private final PriorityBlockingQueue<MessageOut> queue =
            new PriorityBlockingQueue<>(11, MessageOut.PRIORITY_COMPARATOR);
    private Future<?> future;
    private volatile boolean active = false;

    static {
        EXECUTOR_SERVICE = ThreadUtil.newCachedThreadPool();
    }

    public ChannelMessageSender(Channel channel) {
        this.channel = channel;
    }

    public boolean start() {
        if (active) {
            return false;
        }
        active = true;
        future = EXECUTOR_SERVICE.submit(this::sendMessages);
        return true;
    }

    public boolean stop() {
        if (!active) {
            return false;
        }
        active = false;
        future.cancel(true);
        queue.clear();
        return true;
    }

    // Queue itself is thread-safe, method is not
    public boolean send(MessageOut message) {
        if (!active) {
            return false;
        }

        MessagePriority priority = message.priority;
        // Defaults to no limit
        int limit = -1;

        if (priority == MessagePriority.HIGH) {
            limit = channel.getConfig().get(config -> config.queueLimits.getHighPriorityLimit());
        } else if (priority == MessagePriority.DEFAULT) {
            limit = channel.getConfig().get(config -> config.queueLimits.getDefaultPriorityLimit());
        } else if (priority == MessagePriority.LOW) {
            limit = channel.getConfig().get(config -> config.queueLimits.getLowPriorityLimit());
        }

        // Yes, I am aware that this can be simplified, but it ends up being just
        //  about unreadable
        if ((limit >= 0) && queue.size() > limit) {
            return false;
        }

        message.recordInsertionTime();
        return queue.add(message);
    }

    public void clearQueue() {
        queue.clear();
    }

    private void sendMessages() {
        try {
            Thread.currentThread().setName(channel.getName() + " Message Sender");
            MessageOut message;
            int sleepTime = Configs.getBotConfig().get(BotConfig::getMessageSendDelayInMilliseconds);

            while (true) {
                message = queue.take();
                Control.bot().sendMessage(channel.getName(), message.message);
                Thread.sleep(sleepTime);
            }
        } catch (InterruptedException e) {
            App.logger.info("Stopped message sender for " + channel.getName());
            Thread.currentThread().interrupt();
        }
    }
}

@@ -379,71 +379,8 @@
 til;
-%0Aimport com.google.common.util.concurrent.ThreadFactoryBuilder;
 %0A%0Aim
@@ -426,47 +426,8 @@
 ce;%0A
-import java.util.concurrent.Executors;%0A
 impo
@@ -712,16 +712,51 @@
 _SERVICE
+ = ThreadUtil.newCachedThreadPool()
 ;%0A%0A    p
@@ -952,16 +952,16 @@
 future;%0A
+
     priv
@@ -1002,89 +1002,8 @@
 e;%0A%0A
-    static %7B%0A        EXECUTOR_SERVICE = ThreadUtil.newCachedThreadPool();%0A    %7D%0A%0A
     

Tidy up ChannelMessageSender