package envoy.client.data; import java.io.*; import java.util.*; import javafx.collections.*; import envoy.client.net.WriteProxy; import envoy.data.*; import envoy.data.Message.MessageStatus; import envoy.event.MessageStatusChange; /** * Represents a chat between two {@link User}s * as a list of {@link Message} objects. * * @author Maximilian Käfer * @author Leon Hofmeister * @author Kai S. K. Engelbart * @since Envoy Client v0.1-alpha */ public class Chat implements Serializable { protected transient ObservableList messages = FXCollections.observableArrayList(); protected int unreadAmount; protected boolean disabled; protected final Contact recipient; /** * Stores the last time an {@link envoy.event.IsTyping} event has been sent. */ protected transient long lastWritingEvent; private static final long serialVersionUID = 2L; /** * Provides the list of messages that the recipient receives. *

* Saves the Messages in the corresponding chat at that Point. * * @param recipient the user who receives the messages * @since Envoy Client v0.1-alpha */ public Chat(Contact recipient) { this.recipient = recipient; } private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { stream.defaultReadObject(); messages = FXCollections.observableList((List) stream.readObject()); } private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeObject(new ArrayList<>(messages)); } @Override public String toString() { return String.format( "%s[recipient=%s,messages=%d,disabled=%b]", getClass().getSimpleName(), recipient, messages.size(), disabled ); } /** * Generates a hash code based on the recipient. * * @since Envoy Client v0.1-beta */ @Override public int hashCode() { return Objects.hash(recipient); } /** * Tests equality to another object based on the recipient. * * @since Envoy Client v0.1-beta */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof Chat)) return false; final var other = (Chat) obj; return Objects.equals(recipient, other.recipient); } /** * Sets the status of all chat messages received from the recipient to * {@code READ} starting from the bottom and stopping once a read message is * found. * * @param writeProxy the write proxy instance used to notify the server about * the message status changes * @since Envoy Client v0.3-alpha */ public void read(WriteProxy writeProxy) { for (int i = messages.size() - 1; i >= 0; --i) { final var m = messages.get(i); if (m.getSenderID() == recipient.getID()) if (m.getStatus() == MessageStatus.READ) break; else { m.setStatus(MessageStatus.READ); writeProxy.writeMessageStatusChange(new MessageStatusChange(m)); } } unreadAmount = 0; } /** * @return {@code true} if the newest message received in the chat doesn't have * the status {@code READ} * @since Envoy Client v0.3-alpha */ public boolean isUnread() { return !messages.isEmpty() && messages.get(messages.size() - 1).getStatus() != MessageStatus.READ; } /** * Inserts a message at the correct place according to its creation date. * * @param message the message to insert * @since Envoy Client v0.1-beta */ public void insert(Message message) { for (int i = messages.size() - 1; i >= 0; --i) if (message.getCreationDate().isAfter(messages.get(i).getCreationDate())) { messages.add(i + 1, message); return; } messages.add(0, message); } /** * Removes the message with the given ID. * * @param messageID the ID of the message to remove * @return whether the message has been found and removed * @since Envoy Client v0.3-beta */ public boolean remove(long messageID) { return messages.removeIf(m -> m.getID() == messageID); } /** * Increments the amount of unread messages. * * @since Envoy Client v0.1-beta */ public void incrementUnreadAmount() { ++unreadAmount; } /** * @return the amount of unread messages in this chat * @since Envoy Client v0.1-beta */ public int getUnreadAmount() { return unreadAmount; } /** * @return all messages in the current chat * @since Envoy Client v0.1-beta */ public ObservableList getMessages() { return messages; } /** * @return the recipient of a message * @since Envoy Client v0.1-alpha */ public Contact getRecipient() { return recipient; } /** * @return the last known time a {@link envoy.event.IsTyping} event has been * sent * @since Envoy Client v0.2-beta */ public long getLastWritingEvent() { return lastWritingEvent; } /** * Sets the {@code lastWritingEvent} to {@code System#currentTimeMillis()}. * * @since Envoy Client v0.2-beta */ public void lastWritingEventWasNow() { lastWritingEvent = System.currentTimeMillis(); } /** * Determines whether messages can be sent in this chat. Should be {@code true} * i.e. for chats whose recipient deleted this client as a contact. * * @return whether this chat has been disabled * @since Envoy Client v0.3-beta */ public boolean isDisabled() { return disabled; } /** * Determines whether messages can be sent in this chat. Should be true i.e. for * chats whose recipient deleted this client as a contact. * * @param disabled whether this chat should be disabled * @since Envoy Client v0.3-beta */ public void setDisabled(boolean disabled) { this.disabled = disabled; } }