package games.strategy.engine.chat;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.swing.DefaultListCellRenderer;
import games.strategy.debug.ClientLogger;
import games.strategy.engine.chat.Chat.CHAT_SOUND_PROFILE;
import games.strategy.engine.message.IChannelMessenger;
import games.strategy.engine.message.IRemoteMessenger;
import games.strategy.net.IMessenger;
import games.strategy.net.INode;
import games.strategy.net.ServerMessenger;
import games.strategy.sound.ClipPlayer;
import games.strategy.sound.SoundPath;
/**
* Headless version of ChatPanel.
*/
public class HeadlessChat implements IChatListener, IChatPanel {
// roughly 1000 chat messages
private static final int MAX_LENGTH = 1000 * 200;
private Chat m_chat;
private boolean m_showTime = true;
private StringBuffer m_allText = new StringBuffer();
private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("'('HH:mm:ss')'");
private final ChatFloodControl floodControl = new ChatFloodControl();
private final Set<String> m_hiddenPlayers = new HashSet<>();
private final Set<INode> m_players = new HashSet<>();
private PrintStream m_out = null;
public HeadlessChat(final IMessenger messenger, final IChannelMessenger channelMessenger,
final IRemoteMessenger remoteMessenger, final String chatName, final CHAT_SOUND_PROFILE chatSoundProfile) {
final Chat chat = new Chat(messenger, chatName, channelMessenger, remoteMessenger, chatSoundProfile);
setChat(chat);
}
@Override
public boolean isHeadless() {
return true;
}
public void setPrintStream(final PrintStream out) {
m_out = out;
}
@Override
public String toString() {
return m_allText.toString();
}
@Override
public String getAllText() {
return m_allText.toString();
}
@Override
public Chat getChat() {
return m_chat;
}
@Override
public void setShowChatTime(final boolean showTime) {
m_showTime = showTime;
}
@Override
public void setPlayerRenderer(final DefaultListCellRenderer renderer) { // nothing
}
@Override
public synchronized void updatePlayerList(final Collection<INode> players) {
m_players.clear();
for (final INode name : players) {
if (!m_hiddenPlayers.contains(name.getName())) {
m_players.add(name);
}
}
}
@Override
public void shutDown() {
if (m_chat != null) {
m_chat.removeChatListener(this);
m_chat.shutdown();
}
m_chat = null;
}
@Override
public void setChat(final Chat chat) {
if (m_chat != null) {
m_chat.removeChatListener(this);
}
m_chat = chat;
if (m_chat != null) {
m_chat.addChatListener(this);
synchronized (m_chat.getMutex()) {
m_allText = new StringBuffer();
try {
if (m_out != null) {
m_out.println();
}
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
for (final ChatMessage message : m_chat.getChatHistory()) {
if (message.getFrom().equals(m_chat.getServerNode().getName())) {
if (message.getMessage().equals(ServerMessenger.YOU_HAVE_BEEN_MUTED_LOBBY)) {
addChatMessage("YOUR LOBBY CHATTING HAS BEEN TEMPORARILY 'MUTED' BY THE ADMINS, TRY AGAIN LATER",
"ADMIN_CHAT_CONTROL", false);
continue;
} else if (message.getMessage().equals(ServerMessenger.YOU_HAVE_BEEN_MUTED_GAME)) {
addChatMessage("YOUR CHATTING IN THIS GAME HAS BEEN 'MUTED' BY THE HOST", "HOST_CHAT_CONTROL", false);
continue;
}
}
addChatMessage(message.getMessage(), message.getFrom(), message.isMyMessage());
}
}
} else {
updatePlayerList(Collections.emptyList());
}
}
/** thread safe. */
@Override
public void addMessage(final String message, final String from, final boolean thirdperson) {
addMessageWithSound(message, from, thirdperson, SoundPath.CLIP_CHAT_MESSAGE);
}
/** thread safe. */
@Override
public void addMessageWithSound(final String message, final String from, final boolean thirdperson,
final String sound) {
// TODO: I don't really think we need a new thread for this...
final Thread t = new Thread(() -> {
if (from.equals(m_chat.getServerNode().getName())) {
if (message.equals(ServerMessenger.YOU_HAVE_BEEN_MUTED_LOBBY)) {
addChatMessage("YOUR LOBBY CHATTING HAS BEEN TEMPORARILY 'MUTED' BY THE ADMINS, TRY AGAIN LATER",
"ADMIN_CHAT_CONTROL", false);
return;
} else if (message.equals(ServerMessenger.YOU_HAVE_BEEN_MUTED_GAME)) {
addChatMessage("YOUR CHATTING IN THIS GAME HAS BEEN 'MUTED' BY THE HOST", "HOST_CHAT_CONTROL", false);
return;
}
}
if (!floodControl.allow(from, System.currentTimeMillis())) {
if (from.equals(m_chat.getLocalNode().getName())) {
addChatMessage("MESSAGE LIMIT EXCEEDED, TRY AGAIN LATER", "ADMIN_FLOOD_CONTROL", false);
}
return;
}
addChatMessage(message, from, thirdperson);
ClipPlayer.play(sound);
});
t.start();
}
private void addChatMessage(final String originalMessage, final String from, final boolean thirdperson) {
final String message = trimMessage(originalMessage);
final String time = simpleDateFormat.format(new Date());
final String prefix = thirdperson ? (m_showTime ? "* " + time + " " + from : "* " + from)
: (m_showTime ? time + " " + from + ": " : from + ": ");
final String fullMessage = prefix + " " + message + "\n";
final String currentAllText = m_allText.toString();
if (currentAllText.length() > MAX_LENGTH) {
m_allText = new StringBuffer(currentAllText.substring(MAX_LENGTH / 2, currentAllText.length()));
}
m_allText.append(fullMessage);
try {
if (m_out != null) {
m_out.print("CHAT: " + fullMessage);
}
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
@Override
public void addStatusMessage(final String message) {
final String fullMessage = "--- " + message + " ---\n";
final String currentAllText = m_allText.toString();
if (currentAllText.length() > MAX_LENGTH) {
m_allText = new StringBuffer(currentAllText.substring(MAX_LENGTH / 2, currentAllText.length()));
}
m_allText.append(fullMessage);
try {
if (m_out != null) {
m_out.print("CHAT: " + fullMessage);
}
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
private static String trimMessage(final String originalMessage) {
// dont allow messages that are too long
if (originalMessage.length() > 200) {
return originalMessage.substring(0, 199) + "...";
} else {
return originalMessage;
}
}
}