// Copyright (c) 2015 Christopher "BlayTheNinth" Baker
package net.blay09.mods.eirairc.util;
import com.google.common.collect.Maps;
import net.blay09.mods.eirairc.api.irc.IRCChannel;
import net.blay09.mods.eirairc.api.irc.IRCUser;
import net.blay09.mods.eirairc.config.SharedGlobalConfig;
import net.blay09.mods.eirairc.config.settings.ThemeSettings;
import net.blay09.mods.eirairc.irc.IRCUserImpl;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumChatFormatting;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public enum IRCFormatting {
BOLD("\u0002", "l"),
UNDERLINE("\u001f", "n"),
SECRET("\u0016", "k"),
RESET("\u000f", "r");
public static final String IRC_COLOR_PREFIX = "\u0003";
public static final String MC_FORMATTING_PREFIX = "\u00a7";
public static class RGB {
private float r;
private float g;
private float b;
public RGB(float r, float g, float b) {
this.r = r;
this.g = g;
this.b = b;
}
}
private static final Pattern ircColorPattern = Pattern.compile("\u0003([0-9][0-9]?)(?:[,][0-9][0-9]?)?");
private static final Pattern mcColorPattern = Pattern.compile("\u00a7([0-9a-f])");
private static final IRCFormatting[] values = values();
private static final EnumChatFormatting[] mcChatFormatting = EnumChatFormatting.values();
private static final RGB[] mcColorValues = new RGB[16];
private static final Map<String, EnumChatFormatting> twitchColorCache = Maps.newHashMap();
static {
// mcColorValues[EnumChatFormatting.BLACK.ordinal()] = new RGB(0f, 0f, 0f);
// mcColorValues[EnumChatFormatting.DARK_BLUE.ordinal()] = new RGB(0f, 0f, 0.66f);
mcColorValues[EnumChatFormatting.DARK_GREEN.ordinal()] = new RGB(0f, 0.66f, 0f);
mcColorValues[EnumChatFormatting.DARK_AQUA.ordinal()] = new RGB(0f, 0.66f, 0.66f);
mcColorValues[EnumChatFormatting.DARK_RED.ordinal()] = new RGB(0.66f, 0f, 0f);
mcColorValues[EnumChatFormatting.DARK_PURPLE.ordinal()] = new RGB(0.66f, 0f, 0.66f);
mcColorValues[EnumChatFormatting.GOLD.ordinal()] = new RGB(1f, 0.66f, 0f);
mcColorValues[EnumChatFormatting.GRAY.ordinal()] = new RGB(0.66f, 0.66f, 0.66f);
mcColorValues[EnumChatFormatting.DARK_GRAY.ordinal()] = new RGB(0.33f, 0.33f, 0.33f);
mcColorValues[EnumChatFormatting.BLUE.ordinal()] = new RGB(0.33f, 0.33f, 1f);
mcColorValues[EnumChatFormatting.GREEN.ordinal()] = new RGB(0.33f, 1f, 0.33f);
mcColorValues[EnumChatFormatting.AQUA.ordinal()] = new RGB(0.33f, 1f, 1f);
mcColorValues[EnumChatFormatting.RED.ordinal()] = new RGB(1f, 0.33f, 0.33f);
mcColorValues[EnumChatFormatting.LIGHT_PURPLE.ordinal()] = new RGB(1f, 0.33f, 1f);
mcColorValues[EnumChatFormatting.YELLOW.ordinal()] = new RGB(1f, 1f, 0.33f);
mcColorValues[EnumChatFormatting.WHITE.ordinal()] = new RGB(1f, 1f, 1f);
twitchColorCache.put("#008000", EnumChatFormatting.DARK_GREEN);
twitchColorCache.put("#0000FF", EnumChatFormatting.BLUE);
twitchColorCache.put("#1E90FF", EnumChatFormatting.BLUE);
twitchColorCache.put("#FF0000", EnumChatFormatting.RED);
twitchColorCache.put("#B22222", EnumChatFormatting.DARK_RED);
twitchColorCache.put("#FF7F50", EnumChatFormatting.GOLD);
twitchColorCache.put("#9ACD32", EnumChatFormatting.GREEN);
twitchColorCache.put("#FF4500", EnumChatFormatting.GOLD);
twitchColorCache.put("#2E8B57", EnumChatFormatting.DARK_AQUA);
twitchColorCache.put("#DAA520", EnumChatFormatting.YELLOW);
twitchColorCache.put("#D2691E", EnumChatFormatting.GOLD);
twitchColorCache.put("#5F9EA0", EnumChatFormatting.AQUA);
twitchColorCache.put("#FF69B4", EnumChatFormatting.LIGHT_PURPLE);
twitchColorCache.put("#8A2BE2", EnumChatFormatting.LIGHT_PURPLE);
twitchColorCache.put("#00FF7F", EnumChatFormatting.GREEN);
}
private final String ircCode;
private final String mcCode;
IRCFormatting(String ircCode, String mcCode) {
this.ircCode = ircCode;
this.mcCode = MC_FORMATTING_PREFIX + mcCode;
}
public static String toIRC(String s, boolean killFormatting) {
String result = s;
for(IRCFormatting format : values) {
result = result.replaceAll(format.mcCode, killFormatting ? "" : format.ircCode);
}
if(killFormatting) {
Matcher matcher = mcColorPattern.matcher(result);
while(matcher.find()) {
result = result.replaceFirst(Matcher.quoteReplacement(matcher.group()), "");
}
} else {
Matcher matcher = mcColorPattern.matcher(result);
while(matcher.find()) {
char mcColorCode = matcher.group(1).charAt(0);
int ircColorCode = getIRCColorCodeFromMCColorCode(mcColorCode);
result = result.replaceFirst(Matcher.quoteReplacement(matcher.group()), IRC_COLOR_PREFIX + ircColorCode);
}
}
return result;
}
public static String toMC(String s, boolean killFormatting) {
String result = s;
result = result.replace(MC_FORMATTING_PREFIX, "$");
for(IRCFormatting format : values) {
result = result.replaceAll(format.ircCode, killFormatting ? "" : format.mcCode);
}
if(killFormatting) {
Matcher matcher = ircColorPattern.matcher(result);
while(matcher.find()) {
result = result.replaceFirst(Matcher.quoteReplacement(matcher.group()), "");
}
} else {
Matcher matcher = ircColorPattern.matcher(result);
while(matcher.find()) {
String colorMatch = matcher.group(1);
int colorCode = Integer.parseInt(colorMatch);
EnumChatFormatting colorFormat = IRCFormatting.getColorFromIRCColorCode(colorCode);
if(colorFormat != null) {
result = result.replaceFirst(Matcher.quoteReplacement(matcher.group()), colorFormat.toString());
} else {
result = result.replaceFirst(Matcher.quoteReplacement(matcher.group()), "");
}
}
}
return result;
}
public static EnumChatFormatting getColorFromIRCColorCode(int code) {
switch(code) {
case 0: return EnumChatFormatting.WHITE;
case 1: return EnumChatFormatting.BLACK;
case 2: return EnumChatFormatting.DARK_BLUE;
case 3: return EnumChatFormatting.DARK_GREEN;
case 4: return EnumChatFormatting.RED;
case 5: return EnumChatFormatting.DARK_RED;
case 6: return EnumChatFormatting.DARK_PURPLE;
case 7: return EnumChatFormatting.GOLD;
case 8: return EnumChatFormatting.YELLOW;
case 9: return EnumChatFormatting.GREEN;
case 10: return EnumChatFormatting.AQUA;
case 11: return EnumChatFormatting.BLUE;
case 12: return EnumChatFormatting.DARK_AQUA;
case 13: return EnumChatFormatting.LIGHT_PURPLE;
case 14: return EnumChatFormatting.DARK_GRAY;
case 15: return EnumChatFormatting.GRAY;
}
return null;
}
public static int getIRCColorCodeFromMCColorCode(char colorCode) {
switch(colorCode) {
case '0': return 1; // black
case '1': return 2; // dark blue
case '2': return 3; // dark green
case '3': return 12; // dark aqua
case '4': return 5; // dark red
case '5': return 6; // dark purple
case '6': return 7; // gold
case '7': return 15; // gray
case '8': return 14; // dark gray
case '9': return 11; // blue
case 'a': return 9; // green
case 'b': return 10; // aqua
case 'c': return 4; // red
case 'd': return 13; // light purple
case 'e': return 8; // yellow
case 'f': return 0; // white
}
return 1;
}
public static final String[] mcColorNames = new String[] {
"black", "dark_blue", "dark_green", "dark_aqua", "dark_red", "dark_purple", "gold", "gray", "dark_gray", "blue", "green", "aqua", "red", "light_purple", "yellow", "white"
};
public static EnumChatFormatting getColorFromName(String name) {
name = name.toLowerCase();
switch(name) {
case "black": return EnumChatFormatting.BLACK;
case "dark_blue": return EnumChatFormatting.DARK_BLUE;
case "dark_green": return EnumChatFormatting.DARK_GREEN;
case "dark_aqua": return EnumChatFormatting.DARK_AQUA;
case "dark_red": return EnumChatFormatting.DARK_RED;
case "dark_purple": return EnumChatFormatting.DARK_PURPLE;
case "gold": return EnumChatFormatting.GOLD;
case "gray":
case "grey": return EnumChatFormatting.GRAY;
case "dark_gray":
case "dark_grey": return EnumChatFormatting.DARK_GRAY;
case "blue": return EnumChatFormatting.BLUE;
case "green": return EnumChatFormatting.GREEN;
case "aqua": return EnumChatFormatting.AQUA;
case "red": return EnumChatFormatting.RED;
case "light_purple": return EnumChatFormatting.LIGHT_PURPLE;
case "yellow": return EnumChatFormatting.YELLOW;
case "white": return EnumChatFormatting.WHITE;
}
return null;
}
public static String getNameFromColor(EnumChatFormatting color) {
switch(color) {
case BLACK: return "black";
case DARK_BLUE: return "dark_blue";
case DARK_GREEN: return "dark_green";
case DARK_AQUA: return "dark_aqua";
case DARK_RED: return "dark_red";
case DARK_PURPLE: return "dark_purple";
case GOLD: return "gold";
case GRAY: return "gray";
case DARK_GRAY: return "dark_gray";
case BLUE: return "blue";
case GREEN: return "green";
case AQUA: return "aqua";
case RED: return "red";
case LIGHT_PURPLE: return "light_purple";
case YELLOW: return "yellow";
case WHITE: return "white";
}
return null;
}
public static EnumChatFormatting getColorFromMCColorCode(char colorCode) {
switch(colorCode) {
case '0': return EnumChatFormatting.BLACK; // black
case '1': return EnumChatFormatting.DARK_BLUE; // dark blue
case '2': return EnumChatFormatting.DARK_GREEN; // dark green
case '3': return EnumChatFormatting.DARK_AQUA; // dark aqua
case '4': return EnumChatFormatting.DARK_RED; // dark red
case '5': return EnumChatFormatting.DARK_PURPLE; // dark purple
case '6': return EnumChatFormatting.GOLD; // gold
case '7': return EnumChatFormatting.GRAY; // gray
case '8': return EnumChatFormatting.DARK_GRAY; // dark gray
case '9': return EnumChatFormatting.BLUE; // blue
case 'a': return EnumChatFormatting.GREEN; // green
case 'b': return EnumChatFormatting.AQUA; // aqua
case 'c': return EnumChatFormatting.RED; // red
case 'd': return EnumChatFormatting.LIGHT_PURPLE; // light purple
case 'e': return EnumChatFormatting.YELLOW; // yellow
case 'f': return EnumChatFormatting.WHITE; // white
}
return null;
}
public static EnumChatFormatting getColorFromTwitch(String twitchColor) {
EnumChatFormatting color = twitchColorCache.get(twitchColor);
if(color == null) {
RGB twitchRGB = hexToRGB(twitchColor);
float minDist = Float.MAX_VALUE;
EnumChatFormatting minColor = null;
for(int i = 0; i < mcColorValues.length; i++) {
if(mcColorValues[i] == null) {
continue;
}
float dist = (twitchRGB.r - mcColorValues[i].r) * (twitchRGB.r - mcColorValues[i].r) + (twitchRGB.g - mcColorValues[i].g) * (twitchRGB.g - mcColorValues[i].g) + (twitchRGB.b - mcColorValues[i].b) * (twitchRGB.b - mcColorValues[i].b);
if(dist < minDist) {
minDist = dist;
minColor = mcChatFormatting[i];
}
}
if(minColor != null) {
twitchColorCache.put(twitchColor, minColor);
color = minColor;
}
}
return color != null ? color : EnumChatFormatting.WHITE;
}
private static RGB hexToRGB(String hexColor) {
return new RGB(
(float) Integer.valueOf(hexColor.substring(1, 3), 16) / 255f,
(float) Integer.valueOf(hexColor.substring(3, 5), 16) / 255f,
(float) Integer.valueOf(hexColor.substring(5, 7), 16) / 255f);
}
public static void addValidColorsToList(List<String> list) {
for(EnumChatFormatting mcFormatting : mcChatFormatting) {
list.add(mcFormatting.name().toLowerCase());
}
}
public static EnumChatFormatting getColorFormattingForPlayer(EntityPlayer player) {
NBTTagCompound tagCompound = player.getEntityData().getCompoundTag(EntityPlayer.PERSISTED_NBT_TAG).getCompoundTag(Globals.NBT_EIRAIRC);
ThemeSettings theme = SharedGlobalConfig.theme;
int nameColorId = -1;
if(SharedGlobalConfig.enablePlayerColors.get()) {
if (tagCompound.hasKey(Globals.NBT_NAMECOLOR)) {
nameColorId = tagCompound.getInteger(Globals.NBT_NAMECOLOR);
}
}
if(nameColorId != -1) {
return mcChatFormatting[nameColorId];
} else if(Utils.isOP(player)) {
return theme.mcOpNameColor.get();
}
return theme.mcNameColor.get();
}
public static EnumChatFormatting getColorFormattingForUser(IRCChannel channel, IRCUser user) {
EnumChatFormatting nameColor = ((IRCUserImpl) user).getNameColor();
if(nameColor != null && SharedGlobalConfig.twitchNameColors.get()) {
return nameColor;
}
ThemeSettings theme = ConfigHelper.getTheme(channel);
if(channel == null) {
return theme.ircPrivateNameColor.get();
}
if(user.isOperator(channel)) {
return theme.ircOpNameColor.get();
} else if(user.hasVoice(channel)) {
return theme.ircVoiceNameColor.get();
}
return theme.ircNameColor.get();
}
public static boolean isValidColor(String colorName) {
try {
EnumChatFormatting formatting = EnumChatFormatting.valueOf(colorName.toUpperCase());
return formatting.isColor();
} catch (IllegalArgumentException e) {
return false;
}
}
}