package com.mcmoddev.bot.util;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.io.FileUtils;
import com.google.common.collect.Lists;
import com.mcmoddev.bot.MMDBot;
import sx.blah.discord.api.internal.json.objects.EmbedObject;
import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IEmbed;
import sx.blah.discord.handle.obj.IMessage;
import sx.blah.discord.handle.obj.IRole;
import sx.blah.discord.handle.obj.IUser;
import sx.blah.discord.util.DiscordException;
import sx.blah.discord.util.EmbedBuilder;
import sx.blah.discord.util.MissingPermissionsException;
import sx.blah.discord.util.RequestBuffer;
public class Utilities {
/**
* Static reference to the line seperator on the current operating system.
*/
public static final String SEPERATOR = System.lineSeparator();
public static final DateTimeFormatter FORMAT_TIME_STANDARD = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
/**
* A wrapper for {@link FileUtils#copyURLToFile(URL, File)}. Allows for quick download of
* files based on input from users.
*
* @param site The site/url to download the file from.
* @param fileName The location to save the file to.
*
* @return The file that was downloaded.
*/
public static File downloadFile (String site, String fileName) {
final File file = new File(fileName);
try {
FileUtils.copyURLToFile(new URL(site), file);
}
catch (final IOException e) {
e.printStackTrace();
}
return file;
}
/**
* Creates a ping message for a user based upon their user ID.
*
* @param userID The user ID of the user to generate a ping message for.
*
* @return String A short string which will ping the specified user when sent into the
* chat.
*/
public static String getPingMessage (String userID) {
return "<@" + userID + ">";
}
/**
* Makes a String message italicized. This only applies to chat.
*
* @param message The message to format.
*
* @return String The message with the formatting codes applied.
*/
public static String makeItalic (String message) {
return "*" + message + "*";
}
/**
* Makes a String message bold. This only applies to chat.
*
* @param message The message to format.
*
* @return String The message with the bold formatting codes applied.
*/
public static String makeBold (String message) {
return "**" + message + "**";
}
/**
* Makes a String message scratched out. This only applies to chat.
*
* @param message The message to format.
*
* @return String The message with the scratched out formatting codes applied.
*/
public static String makeScratched (String message) {
return "~~" + message + "~~";
}
/**
* Makes a String message underlined. This only applies to chat.
*
* @param message The message to format.
*
* @return String The message with the underlined formatting codes applied.
*/
public static String makeUnderlined (String message) {
return "__" + message + "__";
}
/**
* Makes a String message appear in a code block. This only applies to chat.
*
* @param message The message to format.
*
* @return String The message with the code block format codes applied.
*/
public static String makeCodeBlock (String message) {
return "`" + message + "`";
}
/**
* Makes a string which represents multiple lines of text.
*
* @param lines The lines of text to display. Each entry is a new line.
*
* @return A string which has been split up.
*/
public static String makeMultilineMessage (String... lines) {
String text = "";
for (final String line : lines)
text += line + SEPERATOR;
return text;
}
/**
* Makes a String message appear in a multi-lined code block. This only applies to chat.
*
* @param message The message to format.
*
* @return String The message with the multi-lined code block format codes applied.
*/
public static String makeMultiCodeBlock (String message) {
return "```" + message + "```";
}
/**
* Attempts to send a private message to a user. If a private message channel does not
* already exist, it will be created.
*
* @param user The user to send the private message to.
* @param message The message to send to the user.
*/
public static void sendPrivateMessage (IUser user, String message) {
try {
sendMessage(MMDBot.instance.getOrCreatePMChannel(user), message);
}
catch (final Exception e) {
e.printStackTrace();
}
}
public static void sendMessage (IChannel channel, EmbedBuilder embed, int color) {
embed.ignoreNullEmptyFields();
embed.withColor(color);
sendMessage(channel, embed.build());
}
public static void sendMessage (IChannel channel, EmbedObject object) {
RequestBuffer.request( () -> {
try {
channel.sendMessage(object);
}
catch (DiscordException | MissingPermissionsException e) {
e.printStackTrace();
}
});
}
public static void sendMessage (IChannel channel, String message, EmbedObject object) {
if (message.contains("@") || object.description.contains("@")) {
Utilities.sendMessage(channel, "I tried to send a message, but it contained an @. I can not ping people!");
System.out.println(message);
System.out.println(object.description);
return;
}
if (message.length() > 2000 || object.description.length() > 2000) {
Utilities.sendMessage(channel, "I tried to send a message, but it was too long. " + message.length() + "/2000 chars! Embedded: " + object.description.length() + "/2000!");
System.out.println(message);
System.out.println(object.description);
return;
}
RequestBuffer.request( () -> {
try {
channel.sendMessage(message, object, false);
}
catch (DiscordException | MissingPermissionsException e) {
e.printStackTrace();
}
});
}
public static void sendMessage (IChannel channel, String message, Object... args) {
sendMessage(channel, String.format(message, args));
}
/**
* Sends a message into the chat. This version of the method will handle exceptions for
* you.
*
* @param channel The channel to send to message to.
* @param message The message to send to the channel.
*/
public static void sendMessage (IChannel channel, String message) {
if (message.contains("@")) {
Utilities.sendMessage(channel, "I tried to send a message, but it contained an @. I can not ping people!");
System.out.println(message);
return;
}
if (message.length() > 2000) {
Utilities.sendMessage(channel, "I tried to send a message, but it was too long. " + message.length() + "/2000 chars!");
System.out.println(message);
return;
}
RequestBuffer.request( () -> {
try {
channel.sendMessage(message);
}
catch (MissingPermissionsException | DiscordException e) {
e.printStackTrace();
}
});
}
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue (Map<K, V> map, boolean invert) {
List<Map.Entry<K, V>> list = new LinkedList<>(map.entrySet());
Collections.sort(list, Comparator.comparing(Entry<K,V>::getValue));
if (invert)
list = Lists.reverse(list);
final Map<K, V> result = new LinkedHashMap<>();
for (final Map.Entry<K, V> entry : list)
result.put(entry.getKey(), entry.getValue());
return result;
}
public static String formatMessage (IMessage message) {
String ret = "";
if (message.getAttachments() == null || message.getAttachments().isEmpty())
ret = String.format("[%s|%s] %s: %s", message.getTimestamp().toLocalDate(), message.getTimestamp().toLocalTime(), message.getAuthor().getName(), message.getFormattedContent());
else
ret = String.format("[%s|%s] %s: %s [%s]", message.getTimestamp().toLocalDate(), message.getTimestamp().toLocalTime(), message.getAuthor().getName(), message.getFormattedContent(), formatAttachments(message.getAttachments()));
final List<IEmbed> embeds = message.getEmbedded();
if (embeds != null && !embeds.isEmpty()) {
ret += " {";
for (final IEmbed embed : embeds) {
String emb = "[" + embed.getDescription();
final List<IEmbed.IEmbedField> embedFields = embed.getEmbedFields();
if (embedFields != null && !embedFields.isEmpty())
for (final IEmbed.IEmbedField field : embedFields)
emb += "|" + field.getValue();
emb += "]";
ret += emb;
}
ret += "}";
}
return ret;
}
public static String formatAttachments (List<IMessage.Attachment> attachments) {
String s = "";
for (int i = 0, attachmentsSize = attachments.size(); i < attachmentsSize; i++) {
final IMessage.Attachment attachment = attachments.get(i);
s += attachment.getFilename();
s += "|" + humanReadableByteCount(attachment.getFilesize(), true);
s += "(" + attachment.getUrl() + ")";
if (i != attachmentsSize - 1)
s += ", ";
}
return s;
}
public static String humanReadableByteCount (long bytes, boolean si) {
final int unit = si ? 1000 : 1024;
if (bytes < unit)
return bytes + " B";
final int exp = (int) (Math.log(bytes) / Math.log(unit));
final String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
public static boolean isPrivateMessage (IMessage message) {
return message.getGuild() == null;
}
public static <K, V> String mapToString (Map<K, V> map) {
String output = "";
for (final Entry<K, V> entry : map.entrySet())
output += entry.getKey().toString() + " - " + entry.getValue().toString() + SEPERATOR;
return output;
}
public static String formatTime (LocalDateTime time) {
return time.format(FORMAT_TIME_STANDARD).toString();
}
public static String toString (List<IRole> roles, String delimiter) {
if (roles.isEmpty() || roles.size() == 1 && roles.get(0).isEveryoneRole())
return "None";
String ret = "";
for (final IRole role : roles)
if (!role.isEveryoneRole())
ret += role.getName() + delimiter;
return ret.substring(0, ret.length() - delimiter.length());
}
public static String userString (IUser user) {
return user.getName() + "#" + user.getDiscriminator() + " - " + user.getID();
}
}