/* * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT). * * Copyright (c) JCThePants (www.jcwhatever.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.jcwhatever.nucleus.managed.messaging; import com.jcwhatever.nucleus.collections.HierarchyNode; import com.jcwhatever.nucleus.collections.TreeNode; import com.jcwhatever.nucleus.internal.NucMsg; import com.jcwhatever.nucleus.mixins.IHierarchyNode; import com.jcwhatever.nucleus.mixins.IPluginOwned; import com.jcwhatever.nucleus.utils.PreCon; import com.jcwhatever.nucleus.utils.text.TextColor; import org.bukkit.command.CommandSender; import org.bukkit.plugin.Plugin; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import javax.annotation.Nullable; /** * Converts a collection of root nodes into a list of strings that can be used * to display the node hierarchy in chat. */ public class ChatTree<T extends IHierarchyNode<T>> implements IPluginOwned, Iterable<T> { private final Plugin _plugin; protected List<TreeNode<T>> _rootNodes; protected StringBuilder _buffer = new StringBuilder(20); /** * Constructor. */ public ChatTree(Plugin plugin) { PreCon.notNull(plugin); _plugin = plugin; _rootNodes = new ArrayList<>(10); } /** * Constructor. * * @param rootNodes The initial collection of root nodes. */ public ChatTree(Plugin plugin, Collection<? extends T> rootNodes) { PreCon.notNull(plugin); PreCon.notNull(rootNodes); _plugin = plugin; _rootNodes = new ArrayList<>(rootNodes.size()); for (T node : rootNodes) { _rootNodes.add(new HierarchyNode<T>(node)); } } @Override public Plugin getPlugin() { return _plugin; } /** * Add a root node. * * @param rootNode The root node to add. */ public void addRoot(T rootNode) { PreCon.notNull(rootNode); _rootNodes.add(new HierarchyNode<T>(rootNode)); } /** * Add a collection of root nodes. * * @param rootNodes The root nodes to add. */ public void addAllRoots(Collection<? extends T> rootNodes) { for (T node : rootNodes) { _rootNodes.add(new HierarchyNode<T>(node)); } } /** * Add a {@link HierarchyNode}. * * @param rootNode The root node to add. */ public void addRootNode(TreeNode<T> rootNode) { PreCon.notNull(rootNode); _rootNodes.add(rootNode); } /** * Add a collection of root nodes. * * @param rootNodes The root nodes to add. */ public void addAllRootNodes(Collection<? extends TreeNode<T>> rootNodes) { PreCon.notNull(rootNodes); _rootNodes.addAll(rootNodes); } /** * Show the entire node tree to a {@link org.bukkit.command.CommandSender}. * * @param sender The {@link org.bukkit.command.CommandSender}. */ public void show(CommandSender sender) { PreCon.notNull(sender); show(sender, new NodeLineWriter<T>() { @Override public String write(T nodeValue) { return String.valueOf(nodeValue); } }); } /** * Show the entire node tree to a {@link org.bukkit.command.CommandSender}. * * @param sender The {@link org.bukkit.command.CommandSender}. * @param lineWriter The line writer used to convert node objects into a text line. */ public void show(CommandSender sender, NodeLineWriter<T> lineWriter) { PreCon.notNull(sender); PreCon.notNull(lineWriter); List<String> lines = toChatLines(lineWriter); for (String line : lines) { NucMsg.tell(_plugin, sender, line); } } /** * Convert each node into a string for use in chat. */ public List<String> toChatLines() { return toChatLines(new NodeLineWriter<T>() { @Override public String write(T nodeValue) { return String.valueOf(nodeValue); } }); } /** * Convert each node into a string for use in chat. * * @param lineWriter The line writer used to convert node objects into a text line. */ public List<String> toChatLines(NodeLineWriter<T> lineWriter) { PreCon.notNull(lineWriter); List<String> result = new ArrayList<>(_rootNodes.size() * 3); for (TreeNode<T> rootNode : _rootNodes) { for (TreeNode<T> node : rootNode) { String line = lineWriter.write(node.getValue()); if (line != null) { result.add(getDepthPrefix(node) + line); } } } return result; } @Override public Iterator<T> iterator() { List<T> iterable = new ArrayList<>(_rootNodes.size() * 3); for (TreeNode<T> rootNode : _rootNodes) { for (TreeNode<T> node : rootNode) { iterable.add(node.getValue()); } } return iterable.iterator(); } /** * Get the string to prefix to a node line which indicates the node depth. * * @param node The node to get a depth prefix for. */ protected String getDepthPrefix(TreeNode<T> node) { if (node.isRoot()) return ""; TreeNode<T> parent = node.getParent(); assert parent != null; boolean isLast = parent.getIndex(node) == parent.size() - 1; int depth = node.getDepth(); _buffer.setLength(0); _buffer.append(getLinePrefix()); for (int i=0; i < depth; i++) { boolean isLastIteration = i == depth - 1; _buffer.append(' ') .append(getDepthPrefix(i)) .append(isLastIteration ? (isLast ? '\u2514' : '\u251c') : '\u2502'); } return _buffer.toString(); } /** * Get the prefix used on all lines. */ protected String getLinePrefix() { return TextColor.GRAY.getFormatCode(); } /** * Get the prefix used for a specific depth. * * @param depth The depth. */ protected String getDepthPrefix(@SuppressWarnings("unused") int depth) { return ""; } /** * Converts a node object into text. * * @param <T> The node object type. */ public static interface NodeLineWriter<T extends IHierarchyNode<T>> { /** * Write a node value to a string. * * @param nodeValue The node value. * * @return The node's string representation or null to exclude. */ @Nullable String write(T nodeValue); } }