package util;
import gui.ChatPane;
import gui.CombinedChatPane;
import gui.forms.GUIMain;
import lib.pircbot.User;
import util.comm.Command;
import util.comm.ConsoleCommand;
import util.settings.Settings;
import javax.swing.*;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTML;
import java.awt.*;
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created with IntelliJ IDEA.
* User: Nick
* Date: 6/3/13
* Time: 7:46 PM
* <p>
* This class is used for helpful methods that perform helpful deeds
* elsewhere in the code.
*/
public class Utils {
/**
* Returns a random number from 0 to the specified.
*
* @param param The max number to choose.
*/
public static int nextInt(int param) {
return random(0, param);
}
/**
* Calls the #getExtension(String) method using the file name of the file.
*
* @param f The file to get the extension of.
* @return The extension of the file, or null if there is none.
*/
public static String getExtension(File f) {
return getExtension(f.getName());
}
/**
* Gets the extension of a file.
*
* @param fileName Name of the file to get the extension of.
* @return The file's extension (ex: ".png" or ".wav"), or null if there is none.
*/
public static String getExtension(String fileName) {
String ext = null;
int i = fileName.lastIndexOf('.');
int len = fileName.length();
int after = len - i;
if (i > 0 && (i < len - 1) && after < 5) {//has to be near the end
ext = fileName.substring(i).toLowerCase();
}
return ext;
}
/**
* Sets the extension of a file to the specified extension.
* <p>
* This can also be used as an assurance that the extension of the
* file is the specified extension.
* <p>
* It's expected that this method will be called before any file saving is
* done.
*
* @param fileName The name of the file to change the extension of.
* @param extension The extension (ex: ".png" or ".wav") for the file.
* @return The filename with the new extension.
*/
public static String setExtension(String fileName, String extension) {
String ext = getExtension(fileName);
if (ext != null) {
if (!ext.equalsIgnoreCase(extension)) {
fileName = fileName.substring(0, fileName.indexOf(ext)) + extension;
}
} else {
fileName = fileName + extension;
}
return fileName;
}
/**
* Converts a font to string. Only really used in the Settings GUI.
* (Font#toString() was too messy for me, and fuck making a wrapper class.
*
* @return The name, size, and style of the font.
*/
public static String fontToString(Font f) {
String toRet = "";
if (f != null) {
String type;
if (f.isBold()) {
type = f.isItalic() ? "Bold Italic" : "Bold";
} else {
type = f.isItalic() ? "Italic" : "Plain";
}
toRet = f.getName() + "," + f.getSize() + "," + type;
}
return toRet;
}
/**
* Converts a formatted string (@see #fontToString()) into a font.
*
* @param fontString The string to be turned into a font.
* @return The font.
*/
public static Font stringToFont(String fontString) {
String[] toFont = fontString.substring(fontString.indexOf('[') + 1, fontString.length() - 1).split(",");
Font f = new Font("Calibri", Font.PLAIN, 18);
if (toFont.length == 4) {
String name = "Calibri";
int size = 18;
int type = Font.PLAIN;
for (String keyValPair : toFont) {
String[] split = keyValPair.split("=");
String key = split[0];
String val = split[1];
switch (key) {
case "name":
name = val;
break;
case "style":
switch (val) {
case "plain":
type = Font.PLAIN;
break;
case "italic":
type = Font.ITALIC;
break;
case "bolditalic":
type = Font.BOLD + Font.ITALIC;
break;
case "bold":
type = Font.BOLD;
break;
default:
type = Font.PLAIN;
break;
}
break;
case "size":
try {
size = Integer.parseInt(val);
} catch (Exception e) {
size = 18;
}
break;
default:
break;
}
}
f = new Font(name, type, size);
}
return f;
}
/**
* Adds a single string to an array of strings, first checking to see if the array contains it.
*
* @param toAdd The string(s) to add to the array.
* @param array The array to add the string to.
* @return The array of Strings.
*/
public static String[] addStringsToArray(String[] array, String... toAdd) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, array);
checkAndAdd(list, toAdd);
return list.toArray(new String[list.size()]);
}
/**
* Compares two arrays of Strings and adds the non-repeating ones to the same one.
*
* @param list List of strings to compare to.
* @param toAdd String(s) to add to the list.
*/
public static void checkAndAdd(ArrayList<String> list, String... toAdd) {
for (String s : toAdd) {
if (!list.contains(s)) {
list.add(s);
}
}
}
/**
* Checks individual files one by one like #areFilesGood(String...) and
* returns the good and legitimate files.
*
* @param files The path(s) to the file(s) to check.
* @return The array of paths to files that actually exist.
* @see #areFilesGood(String...) for determining if files exist.
*/
public static String[] checkFiles(String... files) {
ArrayList<String> list = new ArrayList<>();
for (String s : files) {
if (areFilesGood(s)) {
list.add(s);
}
}
return list.toArray(new String[list.size()]);
}
/**
* Checks to see if the file(s) is (are) actually existing and non-blank.
*
* @param files The path(s) to the file(s) to check.
* @return true if (all) the file(s) exist(s)
* @see #checkFiles(String...) For removing bad files and adding the others anyway.
*/
public static boolean areFilesGood(String... files) {
int i = 0;
for (String s : files) {
File test = new File(s);
if (test.exists() && test.length() > 0) i++;
}
return i == files.length;
}
/**
* Logs the chat to a file.
*
* @param message The chat separated by newline characters.
* @param channel The channel the chat was in.
* @param type The int that determines what the logger should do.
* 0 = boot
* 1 = append (clear chat)
* 2 = shutdown
*/
public static void logChat(String[] message, String channel, int type) {
if (channel.startsWith("#")) channel = channel.substring(1);
try {
PrintWriter out = new PrintWriter(new BufferedWriter(
new FileWriter(new File(Settings.logDir.getAbsolutePath() + File.separator + channel + ".txt"), true)));
if (type == 0) {
out.println("====================== " + Settings.date + " ======================");
}
if (message != null && !(message.length == 0 || (message.length == 1 && message[0].equalsIgnoreCase("")))) {
for (String s : message) {
if (s != null && !s.equals("") && !s.equals("\n")) {
out.println(s);
}
}
}
if (type == 2) {
out.println("====================== End of " + Settings.date + " ======================");
}
out.close();
} catch (IOException e) {
GUIMain.log(e);
}
}
/**
* Removes the last file extension from a path.
* <p>
* Note that if the string contains multiple extensions, this will only remove the last one.
* <p>
* Ex: "portal.png.exe.java" becomes "portal.png.exe" after this method returns.
*
* @param s The path to a file, or the file name with its extension.
* @return The file/path name without the extension.
*/
public static String removeExt(String s) {
int pos = s.lastIndexOf(".");
if (pos == -1) return s;
return s.substring(0, pos);
}
/**
* Checks to see if the input is IRC-worthy of printing.
*
* @param input The input in question.
* @return The given input if it checks out, otherwise nothing.
*/
public static String checkText(String input) {
input = input.trim();
return !input.isEmpty() ? input : "";
}
/**
* Returns a number between a given minimum and maximum (exclusive).
*
* @param min The minimum number to generate on.
* @param max The non-inclusive maximum number to generate on.
* @return Some random number between the given numbers.
*/
public static int random(int min, int max) {
return min + (max == min ? 0 : new Random().nextInt(max - min));
}
/**
* Generates a color from the #hashCode() of any java.lang.Object.
* <p>
* Author - Dr_Kegel from Gocnak's stream.
*
* @param seed The Hashcode of the object you want dynamic color for.
* @return The Color of the object's hash.
*/
public static Color getColorFromHashcode(final int seed) {
/* We do some bit hacks here
hashCode has 32 bit, we use every bit as a random source */
final int HUE_BITS = 12, HUE_MASK = ((1 << HUE_BITS) - 1);
final int SATURATION_BITS = 8, SATURATION_MASK = ((1 << SATURATION_BITS) - 1);
final int BRIGHTNESS_BITS = 12, BRIGHTNESS_MASK = ((1 << BRIGHTNESS_BITS) - 1);
int t = seed;
/*
* We want the full hue spectrum, that means all colors of the color
* circle
*/
/* [0 .. 1] */
final float h = (t & HUE_MASK) / (float) HUE_MASK;
t >>= HUE_BITS;
final float s = (t & SATURATION_MASK) / (float) SATURATION_MASK;
t >>= SATURATION_BITS;
final float b = (t & BRIGHTNESS_MASK) / (float) BRIGHTNESS_MASK;
/* some tweaks that nor black nor white can be reached */
/* at the moment h,s,b are in the range of [0 .. 1) */
/* For s and b this is restricted to [0.75 .. 1) at the moment. */
return Color.getHSBColor(h, s * 0.25f + 0.75f, b * 0.25f + 0.75f);
}
/**
* Returns the SimpleAttributeSet for a specified URL.
*
* @param URL The link to make into a URL.
* @return The SimpleAttributeSet of the URL.
*/
public static SimpleAttributeSet URLStyle(String URL) {
SimpleAttributeSet attrs = new SimpleAttributeSet();
StyleConstants.setForeground(attrs, new Color(43, 162, 235));
StyleConstants.setFontFamily(attrs, Settings.font.getValue().getFamily());
StyleConstants.setFontSize(attrs, Settings.font.getValue().getSize());
StyleConstants.setUnderline(attrs, true);
attrs.addAttribute(HTML.Attribute.HREF, URL);
return attrs;
}
/**
* Credit: TDuva
*
* @param URL The URL to check
* @return True if the URL can be formed, else false
*/
public static boolean checkURL(String URL) {
try {
new URI(URL);
} catch (Exception ignored) {
return false;
}
return true;
}
/**
* Checks if the given integer is within the range of any of the key=value
* pairs of the Map (inclusive).
* <p>
* Credit: TDuva
*
* @param i The integer to check.
* @param ranges The map of the ranges to check.
* @return true if the given int is within the range set, else false
*/
public static boolean inRanges(int i, Map<Integer, Integer> ranges) {
for (Map.Entry<Integer, Integer> range : ranges.entrySet()) {
if (i >= range.getKey() && i <= range.getValue()) {
return true;
}
}
return false;
}
/**
* Converts a given int to the correct millis form, except for 0.
*
* @param given Integer to convert.
* @return The correct Integer in milliseconds.
*/
public static int handleInt(int given) {
if (given < 1000 && given > 0) {// not in millis
given = given * 1000; //convert to millis
}
return given;
}
/**
* Gets a time (in seconds) from a parsable string.
*
* @param toParse The string to parse.
* @return A time (in seconds) as an integer.
*/
public static int getTime(String toParse) {
int toRet;
if (toParse.contains("m")) {
String toParseSub = toParse.substring(0, toParse.indexOf("m"));
try {
toRet = Integer.parseInt(toParseSub) * 60;
if (toParse.contains("s")) {
toParseSub = toParse.substring(toParse.indexOf("m") + 1, toParse.indexOf("s"));
toRet += Integer.parseInt(toParseSub);
}
} catch (Exception e) {
toRet = -1;
}
} else {
if (toParse.contains("s")) {
toParse = toParse.substring(0, toParse.indexOf('s'));
}
try {
toRet = Integer.parseInt(toParse);
} catch (Exception e) {
toRet = -1;
}
}
return toRet;
}
/**
* Adds a command to the command map.
* <p>
* To do this in chat, simply type !addcommand command message
* More examples at http://bit.ly/1366RwM
*
* @param s The string from the chat.
* @return true if added, false if fail
*/
public static Response addCommands(String s) {
Response toReturn = new Response();
String[] split = s.split(" ");
if (GUIMain.commandSet != null) {
try {
String name = split[1];//name of the command, [0] is "addcommand"
if (name.startsWith("!")) name = name.substring(1);
if (getCommand(name) != null) {
toReturn.setResponseText("Failed to add command, !" + name + " already exists!");
return toReturn;
}
ArrayList<String> arguments = new ArrayList<>();
if (s.contains(" | ")) {//command with arguments
StringTokenizer st = new StringTokenizer(s.substring(0, s.indexOf(" | ")), " ");
while (st.hasMoreTokens()) {
String work = st.nextToken();
if (work.startsWith("%") && work.endsWith("%")) {
arguments.add(work);
}
}
}
int bingo;
if (!arguments.isEmpty()) {
bingo = s.indexOf(" | ") + 3;//message comes after the pipe separator
} else {
int bingoIndex = s.indexOf(" ", s.indexOf(" ") + 1);
if (bingoIndex == -1) {
toReturn.setResponseText("Failed to add command; there is no command content!");
return toReturn;
}
bingo = bingoIndex + 1;//after second space is the message without arguments
}
String[] message = s.substring(bingo).split("]");
Command c = new Command(name, message);
if (!arguments.isEmpty()) c.addArguments(arguments.toArray(new String[arguments.size()]));
if (GUIMain.commandSet.add(c)) {
toReturn.wasSuccessful();
toReturn.setResponseText("Successfully added command \"!" + name + "\"");
}
} catch (Exception e) {
toReturn.setResponseText("Failed to add command due to Exception: " + e.getMessage());
}
}
return toReturn;
}
/**
* Removes a command from the command map.
*
* @param key The !command trigger, or key.
* @return true if removed, else false
*/
public static Response removeCommands(String key) {
Response toReturn = new Response();
if (GUIMain.commandSet != null && key != null) {
Command c = getCommand(key);
if (c != null) {
if (GUIMain.commandSet.remove(c)) {
toReturn.wasSuccessful();
toReturn.setResponseText("Successfully removed command \"" + key + "\"");
}
} else {
toReturn.setResponseText("Failed to remove command, " + key + " does not exist!");
}
}
return toReturn;
}
/**
* Tests to see if the tab of the given index is selected.
*
* @param tabIndex The index of the chat pane.
* @return True if the t, else false.
*/
public static boolean isTabSelected(int tabIndex) {
return !GUIMain.chatPanes.isEmpty() && GUIMain.channelPane.getSelectedIndex() == tabIndex;
}
/**
* Checks to see if a chat pane tab of a given name is visible.
*
* @param name The name of the chat pane.
* @return True if the tab is visible in the TabbedPane, else false.
*/
public static boolean isTabVisible(String name) {
if (!GUIMain.chatPanes.isEmpty()) {
Set<String> keys = GUIMain.chatPanes.keySet();
for (String s : keys) {
ChatPane cp = GUIMain.getChatPane(s);
if (cp.getChannel().equalsIgnoreCase(name)) {
return cp.isTabVisible();
}
}
}
return false;
}
/**
* Gets a chat pane of the given index.
*
* @param index The index of the tab.
* @return The chat pane if it exists on the index, or null.
*/
public static ChatPane getChatPane(int index) {
if (GUIMain.chatPanes != null && !GUIMain.chatPanes.isEmpty()) {
Set<String> keys = GUIMain.chatPanes.keySet();
for (String s : keys) {
ChatPane cp = GUIMain.getChatPane(s);
if (cp.isTabVisible() && cp.getIndex() == index) return cp;
}
}
return null;
}
/**
* Gets the combined chat pane of the given index.
*
* @param index The index of the tab.
* @return The combined chat pane if it exists, or null.
*/
public static CombinedChatPane getCombinedChatPane(int index) {
if (!GUIMain.combinedChatPanes.isEmpty()) {
for (CombinedChatPane cp : GUIMain.combinedChatPanes) {
if (cp.getIndex() == index) return cp;
}
}
return null;
}
/**
* Get the Command from the given !<string> trigger.
*
* @param key The !command trigger, or key.
* @return The Command that the key relates to, or null if there is no command.
*/
public static Command getCommand(String key) {
if (GUIMain.commandSet != null && key != null) {
for (Command c1 : GUIMain.commandSet) {
if (key.equals(c1.getTrigger())) {
return c1;
}
}
}
return null;
}
/**
* Gets the console command if the user met the trigger and permission of it.
*
* @param key The name of the command.
* @param channel The channel the user is in.
* @return The console command, or null if the user didn't meet the requirements.
*/
public static ConsoleCommand getConsoleCommand(String key, String channel, User u) {
String master = Settings.accountManager.getUserAccount().getName();
if (!channel.contains(master)) return null;
if (u != null) {
for (ConsoleCommand c : GUIMain.conCommands) {
if (key.equalsIgnoreCase(c.getTrigger())) {
int conPerm = c.getClassPermission();
String[] certainPerms = c.getCertainPermissions();
if (conPerm == -1) {
if (certainPerms != null) {
for (String s : certainPerms) {//specified name permission
if (s.equalsIgnoreCase(u.getNick())) {
return c;
}
}
}
} else {//int class permission
if (Permissions.hasAtLeast(Permissions.getUserPermissions(u, channel), conPerm)) {
return c;
}
}
}
}
}
return null;
}
/**
* Checks to see if a given channel is the main Botnak user's channel.
*
* @param channel The channel to check.
* @return true if indeed the channel, otherwise false.
*/
public static boolean isMainChannel(String channel) {
return Settings.accountManager.getUserAccount() != null &&
(channel.replaceAll("#", "").equalsIgnoreCase(Settings.accountManager.getUserAccount().getName()));
}
/**
* Gets the String value of the integer permission.
*
* @param permission The permission to get the String representation of.
* @return The String representation of the permission.
*/
public static String getPermissionString(int permission) {
return (permission > 0 ? (permission > 1 ? (permission > 2 ? (permission > 3 ?
"Only the Broadcaster" :
"Only Mods and the Broadcaster") :
"Donators, Mods, and the Broadcaster") :
"Subscribers, Donators, Mods, and the Broadcaster") :
"Everyone");
}
/**
* Sets the permission of a console command based on the input received.
* <p>
* Ex:
* !setpermission mod 0
* >Everybody can now mod each other
* <p>
* !setpermission mod gocnak,gmansoliver
* >Only Gocnak and Gmansoliver can mod people
* <p>
* etc.
* <p>
* Note: This WILL reset the permissions and /then/ set it to specified.
* If you wish to add another name, you will have to retype the ones already
* allowed!
*
* @param mess The entire message to dissect.
*/
public static Response setCommandPermission(String mess) {
Response toReturn = new Response();
if (mess == null) {
toReturn.setResponseText("Failed to set command permission, message is null!");
return toReturn;
}
String[] split = mess.split(" ");
String trigger = split[1];
for (ConsoleCommand c : GUIMain.conCommands) {
if (trigger.equalsIgnoreCase(c.getTrigger())) {
int classPerm;
String[] certainPerm = null;
try {
classPerm = Integer.parseInt(split[2]);
} catch (Exception e) {
classPerm = -1;
certainPerm = split[2].split(",");
}
c.setCertainPermission(certainPerm);
c.setClassPermission(classPerm);
toReturn.wasSuccessful();
toReturn.setResponseText("Successfully set the command permission for " + trigger + " !");
break;
}
}
return toReturn;
}
/**
* Gets the SimpleAttributeSet with the correct color for the message.
* Cycles through all of the keywords, so the first keyword it matches is the color.
*
* @param message The message to dissect.
* @return The set with the correct color.
*/
public static SimpleAttributeSet getSetForKeyword(String message) {
SimpleAttributeSet setToRet = new SimpleAttributeSet(GUIMain.norm);
Set<String> keys = GUIMain.keywordMap.keySet();
//case doesnt matter
keys.stream().filter(
s -> message.toLowerCase().contains(s.toLowerCase())).forEach(
s -> StyleConstants.setForeground(setToRet, GUIMain.keywordMap.get(s)));
return setToRet;
}
/**
* Checks to see if the message contains a keyword.
*
* @param message The message to check.
* @return True if the message contains a keyword, else false.
*/
public static boolean mentionsKeyword(String message) {
Set<String> keys = GUIMain.keywordMap.keySet();
for (String s : keys) {
if (message.toLowerCase().contains(s.toLowerCase())) {//case doesnt matter
return true;
}
}
return false;
}
/**
* Handles the adding/removing of a keyword and the colors.
*
* @param mess The entire message to dissect.
*/
public static Response handleKeyword(String mess) {
Response toReturn = new Response();
if (mess == null || "".equals(mess)) {
toReturn.setResponseText("Failed to handle keyword, the message is null!");
return toReturn;
}
String[] split = mess.split(" ");
if (split.length > 1) {
String trigger = split[0];
String word = split[1];
if (trigger.equalsIgnoreCase("addkeyword")) {
String color = mess.substring(mess.indexOf(" ", mess.indexOf(" ") + 1) + 1);
Color c = getColor(color, null);
if (!c.equals(Color.white)) {
GUIMain.keywordMap.put(word, c);
toReturn.wasSuccessful();
toReturn.setResponseText("Successfully added keyword \"" + word + "\" !");
} else {
toReturn.setResponseText("Failed to add keyword, the color cannot be white!");
}
} else if (trigger.equalsIgnoreCase("removekeyword")) {
Set<String> keys = GUIMain.keywordMap.keySet();
for (String s : keys) {
if (s.equalsIgnoreCase(word)) {
GUIMain.keywordMap.remove(s);
toReturn.wasSuccessful();
toReturn.setResponseText("Successfully removed keyword \"" + word + "\" !");
return toReturn;
}
}
toReturn.setResponseText("Failed to remove keyword, \"" + word + "\" does not exist!");
}
} else {
toReturn.setResponseText("Failed to handle keyword, the keyword is null!");
}
return toReturn;
}
/**
* Generates a pseudo-random color that works for Botnak.
*
* @return The randomly generated color.
*/
public static Color getRandomColor() {
return new Color(random(100, 256), random(100, 256), random(100, 256));
}
/**
* Gets the color from the given string. Supports hexadecimal, RGB, and color
* name.
*
* @param message The message to dissect.
* @param fallback The fallback color to set to if the parsing failed. Defaults to white if null.
* @return The parsed color from the message, or the fallback color if parsing failed.
*/
public static Color getColor(String message, Color fallback) {
Color toRet = (fallback == null ? new Color(255, 255, 255) : fallback);
String[] split = message.split(" ");
if (split.length > 1) { //R G B
int R;
int G;
int B;
try {
R = Integer.parseInt(split[0]);
} catch (NumberFormatException e) {
R = 0;
}
try {
G = Integer.parseInt(split[1]);
} catch (NumberFormatException e) {
G = 0;
}
try {
B = Integer.parseInt(split[2]);
} catch (NumberFormatException e) {
B = 0;
}
if (checkInts(R, G, B)) toRet = new Color(R, G, B);
} else {
try {
//this is for hexadecimal
Color toCheck = Color.decode(split[0]);
if (checkColor(toCheck)) toRet = toCheck;
} catch (Exception e) {
//didn't parse it right, so it may be a name of a color
for (NamedColor nc : Constants.namedColors) {
if (split[0].equalsIgnoreCase(nc.getName())) {
toRet = nc.getColor();
break;
}
}
if (split[0].equalsIgnoreCase("random")) {
toRet = getRandomColor();
}
}
}
return toRet;
}
/**
* Sets a color to the user based on either a R G B value in their message
* or a standard color from the Color class.
*
* @param user User to change the color for.
* @param mess Their message.
*/
public static Response handleColor(String user, String mess, Color old) {
Response toReturn = new Response();
if (user != null && mess != null) {
//mess = "!setcol r g b" or "!setcol #cd4fd5"
//so let's send just the second part.
Color newColor = getColor(mess.substring(mess.indexOf(" ") + 1), old);
if (!newColor.equals(old)) {
GUIMain.userColMap.put(user, newColor);
toReturn.setResponseText("Successfully set color for user " + user + " !");
toReturn.wasSuccessful();
} else {
toReturn.setResponseText("Failed to update color, it may be too dark!");
}
} else {
toReturn.setResponseText("Failed to update user color, user or message is null!");
}
return toReturn;
}
/**
* Gets a color from the given user, whether it be
* 1. From the manually-set User Color map.
* 2. From their Twitch color set on the website.
* 3. The generated color from their name's hash code.
*
* @param u The user to get the color of.
* @return The color of the user.
*/
public static Color getColorFromUser(User u) {
Color c;
String name = u.getNick();
if (u.getColor() != null) {
if (GUIMain.userColMap.containsKey(name)) {
c = GUIMain.userColMap.get(name);
} else {
c = u.getColor();
if (!Utils.checkColor(c)) {
c = Utils.getColorFromHashcode(name.hashCode());
}
}
} else {//temporarily assign their color as randomly generated
c = Utils.getColorFromHashcode(name.hashCode());
}
return c;
}
/**
* Checks a color to see if it will show up in botnak.
*
* @param c The color to check.
* @return True if the color is not null, and shows up in botnak.
*/
public static boolean checkColor(Color c) {
return c != null && checkInts(c.getRed(), c.getGreen(), c.getBlue());
}
/**
* Checks if the red, green, and blue show up in Botnak,
* using the standard Luminance formula.
*
* @param r Red value
* @param g Green value
* @param b Blue value
* @return true if the Integers meet the specification.
*/
public static boolean checkInts(int r, int g, int b) {
double luma = (0.3 * (double) r) + (0.6 * (double) g) + (0.1 * (double) b);
return luma > (double) 35;
}
/**
* Checks to see if the regex is valid.
*
* @param toCheck The regex to check.
* @return <tt>true</tt> if valid regex.
*/
public static boolean checkRegex(String toCheck) {
try {
Pattern.compile(toCheck);
return true;
} catch (Exception e) {
GUIMain.log(e);
return false;
}
}
/**
* Checks the file name to see if Windows will store it properly.
*
* @param toCheck The name to check.
* @return true if the name is invalid.
*/
public static boolean checkName(String toCheck) {
Matcher m = Constants.fileExclPattern.matcher(toCheck);
return m.find();
}
/**
* Parses a buffered reader and adds what is read to the provided StringBuilder.
*
* @param toRead The stream to read.
* @param builder The builder to add to.
*/
public static void parseBufferedReader(BufferedReader toRead, StringBuilder builder, boolean includeNewLine) {
try (BufferedReader toReadr = toRead) {
String line;
while ((line = toReadr.readLine()) != null) {
builder.append(line);
if (includeNewLine) builder.append("\n");
}
} catch (Exception e) {
GUIMain.log("Failed to read buffered reader due to exception: ");
GUIMain.log(e);
}
}
/**
* One to many methods required creating a BufferedReader just to read one line from it.
* This method does that and saves the effort of writing the code elsewhere.
*
* @param input The InputStream to read from.
* @return The string read from the input.
*/
public static String createAndParseBufferedReader(InputStream input) {
String toReturn = "";
try (InputStreamReader inputStreamReader = new InputStreamReader(input, Charset.forName("UTF-8"));
BufferedReader br = new BufferedReader(inputStreamReader)) {
StringBuilder sb = new StringBuilder();
parseBufferedReader(br, sb, false);
toReturn = sb.toString();
} catch (Exception e) {
GUIMain.log("Could not parse buffered reader due to exception: ");
GUIMain.log(e);
}
return toReturn;
}
/**
* Override for the #createAndParseBufferedReader(InputStream) method for just simple URLs.
* @param URL The URL to try to open.
* @return The parsed buffered reader if successful, otherwise an empty string.
*/
public static String createAndParseBufferedReader(String URL)
{
try
{
return createAndParseBufferedReader(new URL(URL).openStream());
} catch (Exception e)
{
GUIMain.log("Could not parse buffered reader due to exception: ");
GUIMain.log(e);
}
return "";
}
/**
* Opens a web page in the default web browser on the system.
*
* @param URL The URL to open.
*/
public static void openWebPage(String URL) {
try {
Desktop desktop = Desktop.getDesktop();
URI uri = new URL(URL).toURI();
desktop.browse(uri);
} catch (Exception ev) {
GUIMain.log("Failed openWebPage due to exception: ");
GUIMain.log(ev);
}
}
/**
* Caps a number between two given numbers.
*
* @param numLesser The lower-bound (inclusive) number to compare against.
* @param numHigher The higher-bound (inclusive) number to compare against.
* @param toCompare The number to check and perhaps cap.
* @param <E> Generics, used for making one method for all number types.
* @return If the number is within the two bounds, the number is returned.
* Otherwise, return the supplied number bound that the number is closer to.
*/
public static <E extends Number> E capNumber(E numLesser, E numHigher, E toCompare) {
E toReturn = toCompare;
if (toCompare.floatValue() > numHigher.floatValue()) toReturn = numHigher;//floats are the most precise here
else if (toCompare.floatValue() < numLesser.floatValue()) toReturn = numLesser;
return toReturn;
}
/**
* Parses Twitch's tags for an IRC message and spits them out into a HashMap.
*
* @param line The line to parse.
* @return A HashMap full of Key and Value pairs for the tags.
*/
public static HashMap<String, String> parseTagsToMap(String line)
{
HashMap<String, String> toReturn = new HashMap<>();
if (line != null)
{
line = line.substring(1);
String[] parts = line.split(";");
for (String part : parts)
{
String[] objectPair = part.split("=");
//Don't add this key/pair value if there is no value.
if (objectPair.length <= 1) continue;
toReturn.put(objectPair[0], objectPair[1].replaceAll("\\\\s", " "));
}
}
return toReturn;
}
public static void populateComboBox(JComboBox<String> channelsBox)
{
channelsBox.removeAllItems();
if (GUIMain.bot == null || GUIMain.bot.getBot() == null) return;
String[] channels = GUIMain.bot.getBot().getChannels();
for (String s : channels)
channelsBox.addItem(s.replaceAll("#", ""));
channelsBox.setSelectedItem(GUIMain.getCurrentPane().getChannel());
}
}