001 package org.bukkit;
002
003 import java.util.Map;
004 import java.util.regex.Pattern;
005
006 import org.apache.commons.lang.Validate;
007
008 import com.google.common.collect.Maps;
009
010 /**
011 * All supported color values for chat
012 */
013 public enum ChatColor {
014 /**
015 * Represents black
016 */
017 BLACK('0', 0x00),
018 /**
019 * Represents dark blue
020 */
021 DARK_BLUE('1', 0x1),
022 /**
023 * Represents dark green
024 */
025 DARK_GREEN('2', 0x2),
026 /**
027 * Represents dark blue (aqua)
028 */
029 DARK_AQUA('3', 0x3),
030 /**
031 * Represents dark red
032 */
033 DARK_RED('4', 0x4),
034 /**
035 * Represents dark purple
036 */
037 DARK_PURPLE('5', 0x5),
038 /**
039 * Represents gold
040 */
041 GOLD('6', 0x6),
042 /**
043 * Represents gray
044 */
045 GRAY('7', 0x7),
046 /**
047 * Represents dark gray
048 */
049 DARK_GRAY('8', 0x8),
050 /**
051 * Represents blue
052 */
053 BLUE('9', 0x9),
054 /**
055 * Represents green
056 */
057 GREEN('a', 0xA),
058 /**
059 * Represents aqua
060 */
061 AQUA('b', 0xB),
062 /**
063 * Represents red
064 */
065 RED('c', 0xC),
066 /**
067 * Represents light purple
068 */
069 LIGHT_PURPLE('d', 0xD),
070 /**
071 * Represents yellow
072 */
073 YELLOW('e', 0xE),
074 /**
075 * Represents white
076 */
077 WHITE('f', 0xF),
078 /**
079 * Represents magical characters that change around randomly
080 */
081 MAGIC('k', 0x10, true),
082 /**
083 * Makes the text bold.
084 */
085 BOLD('l', 0x11, true),
086 /**
087 * Makes a line appear through the text.
088 */
089 STRIKETHROUGH('m', 0x12, true),
090 /**
091 * Makes the text appear underlined.
092 */
093 UNDERLINE('n', 0x13, true),
094 /**
095 * Makes the text italic.
096 */
097 ITALIC('o', 0x14, true),
098 /**
099 * Resets all previous chat colors or formats.
100 */
101 RESET('r', 0x15);
102
103 /**
104 * The special character which prefixes all chat colour codes. Use this if
105 * you need to dynamically convert colour codes from your custom format.
106 */
107 public static final char COLOR_CHAR = '\u00A7';
108 private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf(COLOR_CHAR) + "[0-9A-FK-OR]");
109
110 private final int intCode;
111 private final char code;
112 private final boolean isFormat;
113 private final String toString;
114 private final static Map<Integer, ChatColor> BY_ID = Maps.newHashMap();
115 private final static Map<Character, ChatColor> BY_CHAR = Maps.newHashMap();
116
117 private ChatColor(char code, int intCode) {
118 this(code, intCode, false);
119 }
120
121 private ChatColor(char code, int intCode, boolean isFormat) {
122 this.code = code;
123 this.intCode = intCode;
124 this.isFormat = isFormat;
125 this.toString = new String(new char[] {COLOR_CHAR, code});
126 }
127
128 /**
129 * Gets the char value associated with this color
130 *
131 * @return A char value of this color code
132 */
133 public char getChar() {
134 return code;
135 }
136
137 @Override
138 public String toString() {
139 return toString;
140 }
141
142 /**
143 * Checks if this code is a format code as opposed to a color code.
144 */
145 public boolean isFormat() {
146 return isFormat;
147 }
148
149 /**
150 * Checks if this code is a color code as opposed to a format code.
151 */
152 public boolean isColor() {
153 return !isFormat && this != RESET;
154 }
155
156 /**
157 * Gets the color represented by the specified color code
158 *
159 * @param code Code to check
160 * @return Associative {@link org.bukkit.ChatColor} with the given code,
161 * or null if it doesn't exist
162 */
163 public static ChatColor getByChar(char code) {
164 return BY_CHAR.get(code);
165 }
166
167 /**
168 * Gets the color represented by the specified color code
169 *
170 * @param code Code to check
171 * @return Associative {@link org.bukkit.ChatColor} with the given code,
172 * or null if it doesn't exist
173 */
174 public static ChatColor getByChar(String code) {
175 Validate.notNull(code, "Code cannot be null");
176 Validate.isTrue(code.length() > 0, "Code must have at least one char");
177
178 return BY_CHAR.get(code.charAt(0));
179 }
180
181 /**
182 * Strips the given message of all color codes
183 *
184 * @param input String to strip of color
185 * @return A copy of the input string, without any coloring
186 */
187 public static String stripColor(final String input) {
188 if (input == null) {
189 return null;
190 }
191
192 return STRIP_COLOR_PATTERN.matcher(input).replaceAll("");
193 }
194
195 /**
196 * Translates a string using an alternate color code character into a
197 * string that uses the internal ChatColor.COLOR_CODE color code
198 * character. The alternate color code character will only be replaced if
199 * it is immediately followed by 0-9, A-F, a-f, K-O, k-o, R or r.
200 *
201 * @param altColorChar The alternate color code character to replace. Ex: &
202 * @param textToTranslate Text containing the alternate color code character.
203 * @return Text containing the ChatColor.COLOR_CODE color code character.
204 */
205 public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
206 char[] b = textToTranslate.toCharArray();
207 for (int i = 0; i < b.length - 1; i++) {
208 if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i+1]) > -1) {
209 b[i] = ChatColor.COLOR_CHAR;
210 b[i+1] = Character.toLowerCase(b[i+1]);
211 }
212 }
213 return new String(b);
214 }
215
216 /**
217 * Gets the ChatColors used at the end of the given input string.
218 *
219 * @param input Input string to retrieve the colors from.
220 * @return Any remaining ChatColors to pass onto the next line.
221 */
222 public static String getLastColors(String input) {
223 String result = "";
224 int length = input.length();
225
226 // Search backwards from the end as it is faster
227 for (int index = length - 1; index > -1; index--) {
228 char section = input.charAt(index);
229 if (section == COLOR_CHAR && index < length - 1) {
230 char c = input.charAt(index + 1);
231 ChatColor color = getByChar(c);
232
233 if (color != null) {
234 result = color.toString() + result;
235
236 // Once we find a color or reset we can stop searching
237 if (color.isColor() || color.equals(RESET)) {
238 break;
239 }
240 }
241 }
242 }
243
244 return result;
245 }
246
247 static {
248 for (ChatColor color : values()) {
249 BY_ID.put(color.intCode, color);
250 BY_CHAR.put(color.code, color);
251 }
252 }
253 }