import org.spongepowered.api.text.Text; import org.spongepowered.api.text.channel.MessageReceiver; import javax.annotation.Nullable; import java.util.*; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; public class TextChannel implements MessageChannel, MessageReceiver { // Static public static final TextChannel TO_NONE = new TextChannel(Stream::of); public static TextChannel.Mutable from(MessageReceiver... recipients) { return fromCollection(Arrays.asList(recipients)); } public static TextChannel.Mutable fromCollection(Collection recipients) { Set recipientsSet = Collections.newSetFromMap(new WeakHashMap<>()); recipientsSet.addAll(recipients); return new TextChannel.Mutable(recipientsSet); } public static TextChannel fromIterable(Supplier> iterableSupplier) { return fromStream(() -> StreamSupport.stream(iterableSupplier.get().spliterator(), false)); } public static TextChannel.SpongeWrapper fromSpongeChannel(org.spongepowered.api.text.channel.MessageChannel spongeMessageChannel) { return new TextChannel.SpongeWrapper(spongeMessageChannel); } public static TextChannel fromStream(Supplier> streamSupplier) { return new TextChannel(streamSupplier); } // Class private final Supplier> recipientsSupplier; private TextChannel.SpongeUnwrapper wrapperMessageChannel = null; @SuppressWarnings("unchecked") // Cast is safe protected TextChannel(@Nullable Supplier> recipientsSupplier) { this.recipientsSupplier = recipientsSupplier == null ? Stream::of : (Supplier>) (Supplier) recipientsSupplier; } /** * Converts this TextChannel into a SpongeAPI {@link org.spongepowered.api.text.channel.MessageChannel MessageChannel} for use in the Sponge ecosystem. * * @return A MessageChannel described by this TextChannel */ @Override public org.spongepowered.api.text.channel.MessageChannel getMessageChannel() { // Create the subclass on-demand, save object for future use. if (wrapperMessageChannel == null) wrapperMessageChannel = new TextChannel.SpongeUnwrapper(this); return wrapperMessageChannel; } @Override public Stream getRecipients() { return recipientsSupplier.get(); } @Override public void sendMessage(Text message) { send(message); } @Override public void sendTo(MessageReceiver recipient, Text message) { // Basic loop prevention if (recipient != this) recipient.sendMessage(message); } @Override public void setMessageChannel(org.spongepowered.api.text.channel.MessageChannel channel) { // Do nothing } // Subclasses public static class Mutable extends TextChannel implements MutableMessageChannel { private final Collection recipients; @SuppressWarnings("unchecked") // Cast is safe protected Mutable(Collection recipients) { super(recipients::stream); this.recipients = (Collection) recipients; } @Override public boolean addRecipient(MessageReceiver recipient) { return recipients.add(recipient); } @Override public void clearRecipients() { recipients.clear(); } @Override public boolean removeRecipient(MessageReceiver recipient) { return recipients.remove(recipient); } } public static class SpongeWrapper extends TextChannel { private final org.spongepowered.api.text.channel.MessageChannel spongeMessageChannel; protected SpongeWrapper(org.spongepowered.api.text.channel.MessageChannel spongeMessageChannel) { super(null); this.spongeMessageChannel = spongeMessageChannel; } @Override public org.spongepowered.api.text.channel.MessageChannel getMessageChannel() { return spongeMessageChannel; } @Override public Stream getRecipients() { return spongeMessageChannel.getMembers().stream(); } @Override public Optional transformMessage(@Nullable Object sender, MessageReceiver recipient, Text originalMessage) { return spongeMessageChannel.transformMessage(sender, recipient, originalMessage); } } public static class SpongeUnwapper implements org.spongepowered.api.text.channel.MessageChannel { private final TextChannel textChannel; protected SpongeUnwrapper(TextChannel textChannel) { this.textChannel = textChannel; } @Override public Collection getMembers() { return textChannel.getRecipients().collect(Collectors.toList()); } @Override public void send(Text original) { textChannel.send(original); } @Override public void send(@Nullable Object sender, Text original) { textChannel.send(sender, original); } @Override public Optional transformMessage(@Nullable Object sender, MessageReceiver recipient, Text original) { return textChannel.transformMessage(sender, recipient, original); } } }