package in.twizmwaz.cardinal.util;
import com.google.common.collect.Lists;
import org.bukkit.ChatColor;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Contains static values and operations designed to assist with aligning text
*
* Original author:
* @author AmoebaMan
* https://github.com/AmoebaMan/Utils/blob/master/src/main/java/net/amoebaman/amoebautils/chat/Align.java
*
* Modified for use in CardinalPGM
*/
public class Align {
/**
* The default Minecraft chat box width, in font-pixels
*/
private static final int SCREEN_WIDTH = 310;
/**
* Most characters in Minecraft's default font are this many font-pixels wide
*/
private static final int DEFAULT_CHAR_WIDTH = 6;
/**
* A map of the width of all irregular characters in Minecraft's default font
*/
private static final Map<Character, Integer> IRREG_CHAR_WIDTH = new HashMap<>();
static {
IRREG_CHAR_WIDTH.put(' ', 4);
IRREG_CHAR_WIDTH.put('f', 5);
IRREG_CHAR_WIDTH.put('i', 2);
IRREG_CHAR_WIDTH.put('ï',4);
IRREG_CHAR_WIDTH.put('ì',4);
IRREG_CHAR_WIDTH.put('í',4);
IRREG_CHAR_WIDTH.put('I', 4);
IRREG_CHAR_WIDTH.put('k', 5);
IRREG_CHAR_WIDTH.put('l', 3);
IRREG_CHAR_WIDTH.put('t', 4);
IRREG_CHAR_WIDTH.put('!', 2);
IRREG_CHAR_WIDTH.put('¡', 2);
IRREG_CHAR_WIDTH.put('(', 5);
IRREG_CHAR_WIDTH.put(')', 5);
IRREG_CHAR_WIDTH.put('~', 7);
IRREG_CHAR_WIDTH.put(',', 2);
IRREG_CHAR_WIDTH.put('.', 2);
IRREG_CHAR_WIDTH.put('<', 5);
IRREG_CHAR_WIDTH.put('>', 5);
IRREG_CHAR_WIDTH.put(':', 2);
IRREG_CHAR_WIDTH.put(';', 2);
IRREG_CHAR_WIDTH.put('"', 5);
IRREG_CHAR_WIDTH.put('[', 4);
IRREG_CHAR_WIDTH.put(']', 4);
IRREG_CHAR_WIDTH.put('{', 5);
IRREG_CHAR_WIDTH.put('}', 5);
IRREG_CHAR_WIDTH.put('|', 2);
IRREG_CHAR_WIDTH.put('`', 3);
IRREG_CHAR_WIDTH.put('\'', 3);
IRREG_CHAR_WIDTH.put('*', 5);
IRREG_CHAR_WIDTH.put('@', 7);
IRREG_CHAR_WIDTH.put('®', 7);
IRREG_CHAR_WIDTH.put('\u2591', 8);
IRREG_CHAR_WIDTH.put('\u2592', 9);
IRREG_CHAR_WIDTH.put('\u2593', 9);
IRREG_CHAR_WIDTH.put('\u2588', 9);
IRREG_CHAR_WIDTH.put(ChatColor.COLOR_CHAR, 0);
}
/**
* Gets the width of a character in Minecraft's default font, in font-pixels.
*
* @param value a character
* @param bold whether this character is in bold style (+1 px)
* @return the width of the character
*/
private static int getCharWidth(char value, boolean bold) {
if (IRREG_CHAR_WIDTH.containsKey(value))
return IRREG_CHAR_WIDTH.get(value) + (bold ? 1 : 0);
return DEFAULT_CHAR_WIDTH + (bold ? 1 : 0);
}
/**
* Gets the total width of some text in font-pixels, the sum of its characters.
*
* @param str some text
* @return the width of the text
*/
public static int getStringWidth(String str) {
int length = 0;
boolean bold = false;
for (int i = 0; i < str.length(); i++)
if (str.charAt(i) != ChatColor.COLOR_CHAR)
if (i == 0)
length += getCharWidth(str.charAt(i), bold);
else if (str.charAt(i - 1) != ChatColor.COLOR_CHAR)
length += getCharWidth(str.charAt(i), bold);
else if (str.charAt(i) == 'l')
bold = true;
else if (!Lists.newArrayList('m', 'n', 'o').contains(str.charAt(i)))
bold = false;
return length;
}
/**
* Repeat character 'c' n times.
*/
public static String repeat(String c, int n) {
assert n >= 0;
return new String(new char[n]).replace("\0", c);
}
public static String padMessage(String message) {
return padMessage(message, ChatColor.BLUE);
}
public static String padMessage(String message, ChatColor dashColor) {
return padMessage(message, dashColor, SCREEN_WIDTH);
}
public static String padMessage(String message, ChatColor dashColor, int maxLen) {
message = " " + message + ChatColor.RESET + " ";
int len = maxLen - getStringWidth(message);
String dash1 = getDash(dashColor, len / 2);
String dash2 = len % 2 == 0 ? dash1 : getDash(dashColor, (len / 2) + 1);
return dash1 + ChatColor.RESET + message + ChatColor.RESET + dash2;
}
public static String getDash() {
return getDash(ChatColor.BLUE, SCREEN_WIDTH);
}
public static String getLine(ChatColor color) {
return getDash(color, SCREEN_WIDTH);
}
/**
* Returns a dash made out of spaces " " and dashes "-", with the desired len in pixels.
*
* @param color color the line should have
* @param len number of pixels
* @return A string with the desired length as long as the len is >= 4. Else it returns an empty string.
*/
public static String getDash(ChatColor color, int len) {
if (len < 4) return "";
switch (len) {
case 4:
return "" + color + ChatColor.STRIKETHROUGH + " ";
case 5:
return "" + color + ChatColor.STRIKETHROUGH + ChatColor.BOLD + " ";
case 6:
return "" + color + ChatColor.STRIKETHROUGH + "-";
case 7:
return "" + color + ChatColor.STRIKETHROUGH + ChatColor.BOLD + "-";
default:
if (len % 4 == 0) {
return "" + color + ChatColor.STRIKETHROUGH + repeat(" ", len / 4);
} else {
return "" + color + ChatColor.STRIKETHROUGH +
repeat(" ", (len / 4) - 1) + getDash(color, len % 4 + 4);
}
}
}
/**
* Breaks a raw string up into a series of lines. Words are wrapped using
* spaces as decimeters and the newline character is respected.
*
* @param rawString The raw string to break.
* @param lineLength The length of a line of text.
* @return An array of word-wrapped lines.
*/
public static List<String> wordWrap(String rawString, int lineLength) {
// A null string is a single line
if (rawString == null) {
return Lists.newArrayList("");
}
// A string shorter than the lineWidth is a single line
if (getStringWidth(rawString) <= lineLength && !rawString.contains("\n")) {
return Lists.newArrayList(rawString);
}
char[] rawChars = (rawString + ' ').toCharArray(); // add a trailing space to trigger pagination
StringBuilder word = new StringBuilder();
StringBuilder line = new StringBuilder();
List<String> lines = new LinkedList<>();
for (int i = 0; i < rawChars.length; i++) {
char c = rawChars[i];
if (c == ' ' || c == '\n') {
if (getStringWidth(line.toString() + (line.length() > 0 ? " " : "") + word.toString()) > lineLength) {
for (String partialWord : wordSplit(word.toString(), lineLength)) {
if (line.length() > 0) lines.add(line.toString());
line = new StringBuilder(partialWord);
}
} else {
if (line.length() > 0) {
line.append(' ');
}
line.append(word);
}
word = new StringBuilder();
if (c == '\n') { // Newline forces the line to flush
lines.add(line.toString());
line = new StringBuilder();
}
} else {
word.append(c);
}
}
if(line.length() > 0) { // Only add the last line if there is anything to add
lines.add(line.toString());
}
// Iterate over the wrapped lines, applying the last color from one line to the beginning of the next
for (int i = 1; i < lines.size(); i++) {
lines.set(i, ChatColor.getLastColors(lines.get(i-1)) + lines.get(i));
}
return lines;
}
public static List<String> wordSplit(String word, int lineLength) {
if (getStringWidth(word) <= lineLength) return Lists.newArrayList(word);
List<String> lines = new LinkedList<>();
StringBuilder line = new StringBuilder();
char[] rawChars = word.toCharArray();
for (int i = 0; i < rawChars.length; i++) {
char c = rawChars[i];
if (getStringWidth(line.toString() + c) > lineLength) {
lines.add(line.toString());
line = new StringBuilder();
}
line.append(c);
}
return lines;
}
}