/* * 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.utils.text.format; import com.google.common.collect.ImmutableMap; import com.jcwhatever.nucleus.utils.ArrayUtils; import com.jcwhatever.nucleus.utils.PreCon; import com.jcwhatever.nucleus.utils.text.components.IChatLineSettings; import com.jcwhatever.nucleus.utils.text.components.IChatMessage; import javax.annotation.Nullable; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Map.Entry; /** * Settings for {@link TextFormatter}. */ public class TextFormatterSettings implements IChatLineSettings { private final Object _sync = new Object(); private final Map<String, ITagFormatter> _formatters; private volatile char[] _escaped; // characters to escape private volatile FormatPolicy _lineReturnPolicy = FormatPolicy.FORMAT; private volatile FormatPolicy _unicodePolicy = FormatPolicy.FORMAT; private volatile FormatPolicy _colorPolicy = FormatPolicy.FORMAT; private volatile FormatPolicy _tagPolicy = FormatPolicy.FORMAT; private volatile boolean _isArgsFormatted = true; private volatile int _maxLineLen = -1; private volatile IChatMessage _linePrefix; private volatile char _escapedCache; /** * Specifies how a formatting aspects are handled. */ public enum FormatPolicy { /** * Formatting component is formatted. */ FORMAT, /** * Ignored the formatting component, left as is. */ IGNORE, /** * Remove the formatting component. */ REMOVE } /** * Constructor. * * @param formatters A map of formatters to use. */ public TextFormatterSettings(@Nullable Map<String, ITagFormatter> formatters) { ImmutableMap.Builder<String, ITagFormatter> builder = new ImmutableMap.Builder<>(); if (formatters != null) { for (Entry<String, ITagFormatter> entry : formatters.entrySet()) { builder.put(entry.getKey(), entry.getValue()); } } _formatters = builder.build(); } /** * Constructor. * * @param formatters The formatters to use. */ public TextFormatterSettings(ITagFormatter... formatters) { PreCon.notNull(formatters); ImmutableMap.Builder<String, ITagFormatter> builder = new ImmutableMap.Builder<>(); for (ITagFormatter formatter : formatters) { builder.put(formatter.getTag(), formatter); } _formatters = builder.build(); } /** * Constructor. * * @param source The {@link TextFormatterSettings} to copy. * @param formatters The formatters to use. Overwrites source settings if duplicate. */ public TextFormatterSettings(TextFormatterSettings source, ITagFormatter... formatters) { PreCon.notNull(formatters); _escaped = source._escaped != null ? Arrays.copyOf(source._escaped, source._escaped.length) : null; _lineReturnPolicy = source._lineReturnPolicy; _unicodePolicy = source._unicodePolicy; _colorPolicy = source._colorPolicy; _tagPolicy = source._tagPolicy; _isArgsFormatted = source._isArgsFormatted; _escapedCache = source._escapedCache; ImmutableMap.Builder<String, ITagFormatter> builder = new ImmutableMap.Builder<>(); for (Entry<String, ITagFormatter> entry : source._formatters.entrySet()) { builder.put(entry.getKey(), entry.getValue()); } for (ITagFormatter formatter : formatters) { builder.put(formatter.getTag(), formatter); } _formatters = builder.build(); } /** * Constructor. * * @param source The {@link TextFormatterSettings} to copy. * @param formatters A map of formatters to use. Overwrites source settings if duplicate. */ public TextFormatterSettings(TextFormatterSettings source, @Nullable Map<String, ITagFormatter> formatters) { PreCon.notNull(source); _escaped = source._escaped != null ? Arrays.copyOf(source._escaped, source._escaped.length) : null; _lineReturnPolicy = source._lineReturnPolicy; _unicodePolicy = source._unicodePolicy; _colorPolicy = source._colorPolicy; _tagPolicy = source._tagPolicy; _isArgsFormatted = source._isArgsFormatted; _escapedCache = source._escapedCache; ImmutableMap.Builder<String, ITagFormatter> builder = new ImmutableMap.Builder<>(); for (Entry<String, ITagFormatter> entry : source._formatters.entrySet()) { builder.put(entry.getKey(), entry.getValue()); } if (formatters != null) { for (Entry<String, ITagFormatter> entry : formatters.entrySet()) { builder.put(entry.getKey(), entry.getValue()); } } _formatters = builder.build(); } @Override public int getMaxLineLen() { return _maxLineLen; } @Override public TextFormatterSettings setMaxLineLen(int len) { _maxLineLen = len; return this; } @Override @Nullable public IChatMessage getLinePrefix() { return _linePrefix; } @Override public TextFormatterSettings setLinePrefix(@Nullable IChatMessage text) { _linePrefix = text; return this; } /** * Determine if format arguments are formatted before being inserted into the * format template. */ public boolean isArgsFormatted() { return _isArgsFormatted; } /** * Set format arguments formatted before insertion. * * @param isFormatted True to format, false to insert as is. * * @return Self for chaining. */ public TextFormatterSettings setIsArgsFormatted(boolean isFormatted) { _isArgsFormatted = isFormatted; return this; } /** * Determine if a character should be escaped. * * @param character The character to check. */ public boolean isEscaped(char character) { if (_escaped == null) return false; if (_escapedCache == character) return true; synchronized (_sync) { for (char escaped : _escaped) { if (escaped == character) { _escapedCache = escaped; return true; } } } return false; } /** * Get an array of characters that should be escaped. */ public char[] getEscaped() { if (_escaped == null) return ArrayUtils.EMPTY_CHAR_ARRAY; synchronized (_sync) { return Arrays.copyOf(_escaped, _escaped.length); } } /** * Set the array of characters to escape. * * @param escaped The characters that should be escaped. */ public TextFormatterSettings setEscaped(char... escaped) { PreCon.notNull(escaped); synchronized (_sync) { _escaped = Arrays.copyOf(escaped, escaped.length); } return this; } /** * Determine if line returns sequences should be formatted into actual line returns, * ignored, or removed. */ public FormatPolicy getLineReturnPolicy() { return _lineReturnPolicy; } /** * Set line return sequences formatted into actual line returns, ignored, or removed. * * @param policy The format policy to use. * * @return Self for chaining. */ public TextFormatterSettings setLineReturnPolicy(FormatPolicy policy) { PreCon.notNull(policy); _lineReturnPolicy = policy; return this; } /** * Determine if unicode sequences should be formatted into unicode characters. */ public FormatPolicy getUnicodePolicy() { return _unicodePolicy; } /** * Set unicode sequences formatted into unicode characters, ignored, or removed. * * @param policy The format policy to use. * * @return Self for chaining. */ public TextFormatterSettings setUnicodePolicy(FormatPolicy policy) { PreCon.notNull(policy); _unicodePolicy = policy; return this; } /** * Determine if color tags should be formatted into color codes, ignored, or removed. */ public FormatPolicy getColorPolicy() { return _colorPolicy; } /** * Set color tags formatted into color codes, ignored, or removed. * * @param policy The format policy to use. * * @return Self for chaining. */ public TextFormatterSettings setColorPolicy(FormatPolicy policy) { PreCon.notNull(policy); _colorPolicy = policy; return this; } /** * Determine if tags (excluding color tags) should be formatted, ignored, or removed. */ public FormatPolicy getTagPolicy() { return _tagPolicy; } /** * Set tags (excluding color tags) formatted, ignored or removed. * * @param policy The format policy to use. * * @return Self for chaining. */ public TextFormatterSettings getTagPolicy(FormatPolicy policy) { PreCon.notNull(policy); _tagPolicy = policy; return this; } /** * Get all default tag formatters. */ public Collection<ITagFormatter> getFormatters() { return Collections.unmodifiableCollection(_formatters.values()); } /** * Get all default tag formatters. * * @param output The output collection to add results to. * * @return The output collection. */ public <T extends Collection<ITagFormatter>> T getFormatters(T output) { PreCon.notNull(output); output.addAll(_formatters.values()); return output; } /** * Get a default tag formatter by case sensitive tag. * * @param tag The tag text. */ public ITagFormatter getFormatter(String tag) { return _formatters.get(tag); } Map<String, ITagFormatter> getFormatMap() { return _formatters; } }