<commit_before>package com.github.alex1304.ultimategdbot.core.handler;

import java.time.Duration;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

import com.github.alex1304.ultimategdbot.api.Bot;
import com.github.alex1304.ultimategdbot.api.Command;
import com.github.alex1304.ultimategdbot.api.Context;
import com.github.alex1304.ultimategdbot.core.impl.ContextImpl;

import discord4j.core.event.domain.message.MessageCreateEvent;
import discord4j.core.object.entity.Message;
import reactor.core.Disposable;
import reactor.core.publisher.Mono;

public class ReplyMenuHandler implements Handler {
	
	private final Bot bot;
	private final Map<String, ReplyMenu> openedReplyMenus;
	private final Map<ReplyMenu, Disposable> disposableMenus;
	
	private final class ReplyMenu {
		final Context ctx;
		final Message msg;
		final Map<String, Function<Context, Mono<Void>>> menuItems;
		final boolean deleteOnReply;
		final boolean deleteOnTimeout;
		ReplyMenu(Context ctx, Message msg, Map<String, Function<Context, Mono<Void>>> menuItems, boolean deleteOnReply, boolean deleteOnTimeout) {
			this.ctx = ctx;
			this.msg = msg;
			this.menuItems = menuItems;
			this.deleteOnReply = deleteOnReply;
			this.deleteOnTimeout = deleteOnTimeout;
		}
		String toKey() {
			return msg.getChannelId().asString() + ctx.getEvent().getMessage().getAuthorId().get().asString();
		}
		void complete() {
			if (deleteOnReply) {
				msg.delete().doOnError(__ -> {}).subscribe();
			}
			openedReplyMenus.remove(toKey());
			var d = disposableMenus.remove(this);
			if (d != null) {
				d.dispose();
			}
		}
		void timeout() {
			if (deleteOnTimeout) {
				msg.delete().doOnError(__ -> {}).subscribe();
			}
			openedReplyMenus.remove(toKey());
			disposableMenus.remove(this);
		}
	}

	public ReplyMenuHandler(Bot bot) {
		this.bot = Objects.requireNonNull(bot);
		this.openedReplyMenus = new ConcurrentHashMap<>();
		this.disposableMenus = new ConcurrentHashMap<>();
	}

	@Override
	public void prepare() {
	}

	@Override
	public void listen() {
		bot.getDiscordClient().getEventDispatcher().on(MessageCreateEvent.class)
				.filter(event -> event.getMessage().getContent().isPresent()
						&& event.getMessage().getAuthorId().isPresent()
						&& openedReplyMenus.containsKey(event.getMessage().getChannelId().asString()
								+ event.getMessage().getAuthorId().get().asString()))
				.map(event -> new ContextImpl(event, Arrays.asList(event.getMessage().getContent().get().split(" +")), bot))
				.subscribe(ctx -> {
					var replyMenu = openedReplyMenus.get(ctx.getEvent().getMessage().getChannelId().asString()
							+ ctx.getEvent().getMessage().getAuthorId().get().asString());
					var replyItem = ctx.getArgs().get(0);
					var action = replyMenu.menuItems.get(replyItem);
					if (action == null) {
						return;
					}
					Command.invoke(action, ctx);
					replyMenu.complete();
				});
	}
	
	public String open(Context ctx, Message msg, Map<String, Function<Context, Mono<Void>>> menuItems, boolean deleteOnReply, boolean deleteOnTimeout) {
		if (!msg.getAuthorId().isPresent()) {
			return "";
		}
		var rm = new ReplyMenu(ctx, msg, menuItems, deleteOnReply, deleteOnTimeout);
		var key = rm.toKey();
		var existing = openedReplyMenus.get(key);
		if (existing != null) {<commit_msg>replies are neow deleted in reply menus<commit_after>package com.github.alex1304.ultimategdbot.core.handler;

import java.time.Duration;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

import com.github.alex1304.ultimategdbot.api.Bot;
import com.github.alex1304.ultimategdbot.api.Command;
import com.github.alex1304.ultimategdbot.api.Context;
import com.github.alex1304.ultimategdbot.core.impl.ContextImpl;

import discord4j.core.event.domain.message.MessageCreateEvent;
import discord4j.core.object.entity.Message;
import reactor.core.Disposable;
import reactor.core.publisher.Mono;

public class ReplyMenuHandler implements Handler {
	
	private final Bot bot;
	private final Map<String, ReplyMenu> openedReplyMenus;
	private final Map<ReplyMenu, Disposable> disposableMenus;
	
	private final class ReplyMenu {
		final Context ctx;
		final Message msg;
		final Map<String, Function<Context, Mono<Void>>> menuItems;
		final boolean deleteOnReply;
		final boolean deleteOnTimeout;
		ReplyMenu(Context ctx, Message msg, Map<String, Function<Context, Mono<Void>>> menuItems, boolean deleteOnReply, boolean deleteOnTimeout) {
			this.ctx = ctx;
			this.msg = msg;
			this.menuItems = menuItems;
			this.deleteOnReply = deleteOnReply;
			this.deleteOnTimeout = deleteOnTimeout;
		}
		String toKey() {
			return msg.getChannelId().asString() + ctx.getEvent().getMessage().getAuthorId().get().asString();
		}
		void complete() {
			if (deleteOnReply) {
				msg.delete().doOnError(__ -> {}).subscribe();
			}
			openedReplyMenus.remove(toKey());
			var d = disposableMenus.remove(this);
			if (d != null) {
				d.dispose();
			}
		}
		void timeout() {
			if (deleteOnTimeout) {
				msg.delete().doOnError(__ -> {}).subscribe();
			}
			openedReplyMenus.remove(toKey());
			disposableMenus.remove(this);
		}
	}

	public ReplyMenuHandler(Bot bot) {
		this.bot = Objects.requireNonNull(bot);
		this.openedReplyMenus = new ConcurrentHashMap<>();
		this.disposableMenus = new ConcurrentHashMap<>();
	}

	@Override
	public void prepare() {
	}

	@Override
	public void listen() {
		bot.getDiscordClient().getEventDispatcher().on(MessageCreateEvent.class)
				.filter(event -> event.getMessage().getContent().isPresent()
						&& event.getMessage().getAuthorId().isPresent()
						&& openedReplyMenus.containsKey(event.getMessage().getChannelId().asString()
								+ event.getMessage().getAuthorId().get().asString()))
				.map(event -> new ContextImpl(event, Arrays.asList(event.getMessage().getContent().get().split(" +")), bot))
				.subscribe(ctx -> {
					var replyMenu = openedReplyMenus.get(ctx.getEvent().getMessage().getChannelId().asString()
							+ ctx.getEvent().getMessage().getAuthorId().get().asString());
					var replyItem = ctx.getArgs().get(0);
					var action = replyMenu.menuItems.get(replyItem);
					if (action == null) {
						return;
					}
					Command.invoke(action, ctx);
					replyMenu.complete();
					ctx.getEvent().getMessage().delete().doOnError(__ -> {}).subscribe();
				});
	}
	
	public String open(Context ctx, Message msg, Map<String, Function<Context, Mono<Void>>> menuItems, boolean deleteOnReply, boolean deleteOnTimeout) {
		if (!msg.getAuthorId().isPresent()) {
			return "";
		}
		var rm = new ReplyMenu(ctx, msg, menuItems, deleteOnReply, deleteOnTimeout);
		var key = rm.toKey();
		var existing = openedReplyMenus.get(key);
		if (existing != null) {
{'fraction_non_alphanumeric': 0.14129960750109027, 'fraction_numerical': 0.006687018461985754, 'mean_word_length': 4.517241379310345, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4269671', 'n_tokens_mistral': 2470, 'n_tokens_neox': 2140, 'n_words': 410}