package me.viper.teamplugin.gui; import me.viper.teamplugin.manager.LangManager; import me.viper.teamplugin.manager.MailboxManager; import me.viper.teamplugin.manager.MessageManager; import me.viper.teamplugin.util.Utils; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import java.util.*; /** * MailboxGUI – two-view postfach for TeamPlugin. * * LIST VIEW (54 slots) * ┌─────────────────────────┐ * │ Header row (glass) │ slot 4 = mailbox info item * │ Message items 9-44 │ WRITTEN_BOOK=unread, BOOK=read * │ Footer nav 45/49/53 │ ← page | close | page → * └─────────────────────────┘ * * READ VIEW (54 slots) * ┌─────────────────────────┐ * │ Background filler │ * │ Full message at 22 │ * │ Delete:20 Reply:24 │ * │ Back:49 │ * └─────────────────────────┘ */ public class MailboxGUI { private static final int ITEMS_PER_PAGE = 36; // rows 1-4, slots 9-44 /** UUID → current list-view page number */ private static final Map CURRENT_PAGE = new HashMap<>(); /** UUID → whose mailbox is open (player name) */ private static final Map OPEN_FOR_PLAYER = new HashMap<>(); /** UUID → msgId of message currently being read */ private static final Map READING_ID = new HashMap<>(); // ── Open: list view ─────────────────────────────────────────────── /** Opens the caller's own mailbox at page 0. */ public static void openMailbox(Player viewer) { openMailbox(viewer, viewer.getName(), 0); } /** Opens a specific player's mailbox at a given page (admins can inspect others). */ public static void openMailbox(Player viewer, String targetPlayer, int page) { List messages = MailboxManager.getParsedMessages(targetPlayer); int totalPages = Math.max(1, (int) Math.ceil((double) messages.size() / ITEMS_PER_PAGE)); page = Math.max(0, Math.min(page, totalPages - 1)); OPEN_FOR_PLAYER.put(viewer.getUniqueId(), targetPlayer); CURRENT_PAGE.put(viewer.getUniqueId(), page); Inventory inv = Bukkit.createInventory(null, 54, Utils.color(getListTitle())); // Header row ItemStack headerGlass = filler(Material.CYAN_STAINED_GLASS_PANE); for (int i = 0; i < 9; i++) inv.setItem(i, headerGlass); // Footer row ItemStack footerGlass = filler(Material.BLACK_STAINED_GLASS_PANE); for (int i = 45; i < 54; i++) inv.setItem(i, footerGlass); // Info item (slot 4) int unread = MailboxManager.getUnreadCount(targetPlayer); inv.setItem(4, buildInfoItem(targetPlayer, unread, page + 1, totalPages)); // Message items (slots 9-44) int start = page * ITEMS_PER_PAGE; for (int i = 0; i < ITEMS_PER_PAGE; i++) { int idx = start + i; if (idx >= messages.size()) break; inv.setItem(9 + i, buildMessageListItem(messages.get(idx))); } // Navigation if (page > 0) inv.setItem(45, navItem(Material.ARROW, Utils.color(LangManager.get("mailbox_prev_page")), List.of(Utils.color("&7Vorherige Seite")))); inv.setItem(49, navItem(Material.BARRIER, Utils.color(LangManager.get("mailbox_close")), List.of(Utils.color("&7Postfach schließen")))); if (page + 1 < totalPages) inv.setItem(53, navItem(Material.ARROW, Utils.color(LangManager.get("mailbox_next_page")), List.of(Utils.color("&7Nächste Seite")))); viewer.openInventory(inv); } // ── Open: read view ─────────────────────────────────────────────── private static void openMessage(Player viewer, String[] parts) { // parts: [id, from, isoTimestamp, read, text] String msgId = parts[0]; String from = parts[1]; String date = Utils.prettifyIso(parts[2]); String text = parts[4]; READING_ID.put(viewer.getUniqueId(), msgId); String targetPlayer = OPEN_FOR_PLAYER.getOrDefault(viewer.getUniqueId(), viewer.getName()); MailboxManager.markRead(targetPlayer, msgId); Inventory inv = Bukkit.createInventory(null, 54, Utils.color(getReadTitle())); // Background ItemStack bg = filler(Material.GRAY_STAINED_GLASS_PANE); for (int i = 0; i < 54; i++) inv.setItem(i, bg); // Message paper at slot 22 inv.setItem(22, buildFullMessageItem(from, date, text)); // Delete (slot 20) inv.setItem(20, navItem(Material.RED_CONCRETE, Utils.color(LangManager.get("mailbox_delete_btn")), List.of(Utils.color("&7Nachricht endgültig löschen")))); // Reply (slot 24) inv.setItem(24, navItem(Material.WRITABLE_BOOK, Utils.color(Utils.replace(LangManager.get("mailbox_reply_btn"), "%player%", from)), List.of(Utils.color("&7An &b" + from + " &7antworten")))); // Back (slot 49) inv.setItem(49, navItem(Material.ARROW, Utils.color(LangManager.get("mailbox_back_btn")), List.of(Utils.color("&7Zurück zur Liste")))); viewer.openInventory(inv); } // ── Click handlers ──────────────────────────────────────────────── public static void handleListClick(Player player, InventoryClickEvent e) { e.setCancelled(true); int slot = e.getRawSlot(); ItemStack clicked = e.getCurrentItem(); if (clicked == null || clicked.getType().isAir()) return; String target = OPEN_FOR_PLAYER.getOrDefault(player.getUniqueId(), player.getName()); int page = CURRENT_PAGE.getOrDefault(player.getUniqueId(), 0); switch (slot) { case 45 -> openMailbox(player, target, page - 1); case 49 -> { cleanup(player.getUniqueId()); player.closeInventory(); } case 53 -> openMailbox(player, target, page + 1); default -> { if (slot >= 9 && slot <= 44) { List messages = MailboxManager.getParsedMessages(target); int idx = page * ITEMS_PER_PAGE + (slot - 9); if (idx < messages.size()) openMessage(player, messages.get(idx)); } } } } public static void handleReadClick(Player player, InventoryClickEvent e) { e.setCancelled(true); int slot = e.getRawSlot(); ItemStack clicked = e.getCurrentItem(); if (clicked == null || clicked.getType().isAir()) return; String target = OPEN_FOR_PLAYER.getOrDefault(player.getUniqueId(), player.getName()); String msgId = READING_ID.get(player.getUniqueId()); int page = CURRENT_PAGE.getOrDefault(player.getUniqueId(), 0); switch (slot) { case 20 -> { // delete if (msgId != null) MailboxManager.delete(target, msgId); READING_ID.remove(player.getUniqueId()); player.sendMessage(Utils.color(LangManager.get("mail_deleted"))); openMailbox(player, target, page); } case 24 -> { // reply if (msgId != null) { MailboxManager.getParsedMessages(target).stream() .filter(a -> a[0].equals(msgId)) .findFirst() .ifPresent(parts -> { cleanup(player.getUniqueId()); player.closeInventory(); MessageManager.startReply(player, parts[1]); }); } } case 49 -> { // back READING_ID.remove(player.getUniqueId()); openMailbox(player, target, page); } } } // ── Title helpers ───────────────────────────────────────────────── public static String getListTitle() { return LangManager.get("mailbox_title"); } public static String getReadTitle() { return LangManager.get("mailbox_read_title"); } public static boolean isListTitle(String colored) { return colored.equals(Utils.color(getListTitle())); } public static boolean isReadTitle(String colored) { return colored.equals(Utils.color(getReadTitle())); } // ── State cleanup ───────────────────────────────────────────────── public static void cleanup(UUID uuid) { CURRENT_PAGE.remove(uuid); OPEN_FOR_PLAYER.remove(uuid); READING_ID.remove(uuid); } // ── Item builders ───────────────────────────────────────────────── private static ItemStack buildInfoItem(String owner, int unread, int page, int total) { ItemStack item = new ItemStack(Material.ENCHANTED_BOOK); ItemMeta m = item.getItemMeta(); if (m != null) { m.setDisplayName(Utils.color("&b&lPostfach &8– &7" + owner)); m.setLore(List.of( Utils.color("&7Ungelesen&8: &e" + unread), Utils.color("&7Seite &e" + page + " &7/ &e" + total) )); item.setItemMeta(m); } return item; } private static ItemStack buildMessageListItem(String[] parts) { // parts: [id, from, iso, read, text] boolean read = "true".equals(parts[3]); ItemStack item = new ItemStack(read ? Material.BOOK : Material.WRITTEN_BOOK); ItemMeta m = item.getItemMeta(); if (m != null) { m.setDisplayName(Utils.color((read ? "&7" : "&e&l") + "Von: " + parts[1])); String preview = parts[4].length() > 38 ? parts[4].substring(0, 38) + "…" : parts[4]; m.setLore(List.of( Utils.color("&7" + Utils.prettifyIso(parts[2])), Utils.color("&f" + preview), "", Utils.color(read ? "&8Gelesen" : "&eUngelesen – Klicken zum Lesen") )); item.setItemMeta(m); } return item; } private static ItemStack buildFullMessageItem(String from, String date, String text) { ItemStack item = new ItemStack(Material.PAPER); ItemMeta m = item.getItemMeta(); if (m != null) { m.setDisplayName(Utils.color("&bVon: &e" + from + " &8| &7" + date)); List lore = new ArrayList<>(); lore.add(""); for (String line : wrapText(text, 40)) lore.add(Utils.color("&f" + line)); m.setLore(lore); item.setItemMeta(m); } return item; } // ── Generic helpers ─────────────────────────────────────────────── private static ItemStack filler(Material mat) { ItemStack item = new ItemStack(mat); ItemMeta m = item.getItemMeta(); if (m != null) { m.setDisplayName(" "); item.setItemMeta(m); } return item; } private static ItemStack navItem(Material mat, String name, List lore) { ItemStack item = new ItemStack(mat); ItemMeta m = item.getItemMeta(); if (m != null) { m.setDisplayName(name); m.setLore(lore); item.setItemMeta(m); } return item; } /** Word-wraps {@code text} at {@code maxChars} characters per line. */ private static List wrapText(String text, int maxChars) { List lines = new ArrayList<>(); String[] words = text.split(" "); StringBuilder cur = new StringBuilder(); for (String w : words) { if (cur.length() > 0 && cur.length() + 1 + w.length() > maxChars) { lines.add(cur.toString()); cur = new StringBuilder(w); } else { if (cur.length() > 0) cur.append(' '); cur.append(w); } } if (cur.length() > 0) lines.add(cur.toString()); return lines.isEmpty() ? List.of(text) : lines; } }