package org.royaldev.thehumanity.ping;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.kitteh.irc.client.library.Client;
import org.kitteh.irc.client.library.element.Channel;
import org.kitteh.irc.client.library.element.User;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class PingRegistry implements Serializable {
private static final long serialVersionUID = 1337L;
private final List<PingRegistration> registrations = Lists.newArrayList();
public static PingRegistry deserializeOrMakePingRegistry() {
final File registryFile = new File("pingregistry.dat");
if (!registryFile.exists()) return new PingRegistry();
try (final ObjectInputStream ois = new ObjectInputStream(new GZIPInputStream(new FileInputStream(registryFile)))) {
return (PingRegistry) ois.readObject();
} catch (final IOException | ClassNotFoundException ex) {
throw new RuntimeException(ex);
}
}
/**
* Adds a registration to the list. If the account already has a registration, an exception will be thrown.
*
* @param account Account to add registration for
* @return The added registration, suitable for modification
* @throws IllegalStateException If the account already has a registration
*/
public PingRegistration addRegistration(@NotNull final String account) {
Preconditions.checkNotNull(account, "account was null");
if (this.hasRegistration(account)) {
throw new IllegalStateException(account + " already has a registration.");
}
final PingRegistration registration = new PingRegistration(account);
// Probably want to receive notifications by default
registration.addOption(PingRegistrationOption.RECEIVE);
// Add the option to ping all authed nicks by default. Only those who have more than one authed nick will need
// to turn this off.
registration.addOption(PingRegistrationOption.PING_ALL_AUTHED_NICKS);
this.registrations.add(registration);
return registration;
}
/**
* Gets the registration for the given account name. If there is no registration for the account, this will return
* null.
*
* @param account Account to get registration for
* @return PingRegistration or null
*/
@Nullable
public PingRegistration getRegistration(@NotNull final String account) {
Preconditions.checkNotNull(account, "account was null");
return this.getRegistrations().stream()
.filter(reg -> reg.getServicesAccount().equals(account))
.findFirst().orElse(null);
}
/**
* Gets an unmodifiable list of registrations.
*
* @return Unmodifiable list
*/
@NotNull
public List<PingRegistration> getRegistrations() {
return Collections.unmodifiableList(this.registrations);
}
/**
* Checks to see if the account already has a registration stored.
*
* @param account Account to check
* @return true if the account has a registration stored
*/
public boolean hasRegistration(@NotNull final String account) {
return this.getRegistration(account) != null;
}
/**
* Removes a registration for this account. If the account has no registration, an exception will be thrown.
*
* @param account Account to remove registration for
* @return Result of the {@link List#remove(Object)} method
* @throws IllegalStateException If the account has no registration
*/
public boolean removeRegistration(@NotNull final String account) {
Preconditions.checkNotNull(account, "account was null");
final PingRegistration registration = this.getRegistration(account);
if (registration == null) {
throw new IllegalStateException(account + " has no registration.");
}
return this.registrations.remove(registration);
}
/**
* Saves the registry.
*/
public void save() {
final File registryFile = new File("pingregistry.dat");
if (!registryFile.exists()) {
try {
if (!registryFile.createNewFile()) {
throw new RuntimeException(new IOException("Could not make ping registry file."));
}
} catch (final IOException ex) {
throw new RuntimeException(ex);
}
}
try (final ObjectOutputStream oos = new ObjectOutputStream(new GZIPOutputStream(new FileOutputStream(registryFile)))) {
oos.writeObject(this);
oos.flush();
} catch (final IOException ex) {
throw new RuntimeException(ex);
}
}
public void sendNotification(@NotNull final User requester, @NotNull final Channel channel, @NotNull final Client client, @NotNull final String nickname, final boolean privmsg) {
Preconditions.checkNotNull(requester, "requester was null");
Preconditions.checkNotNull(channel, "channel was null");
Preconditions.checkNotNull(client, "client was null");
Preconditions.checkNotNull(nickname, "nickname was null");
final String message = "Your presence has been requested by " + requester.getMessagingName() + " for a game of Cards Against Humanity in " + channel.getMessagingName() + ".";
if (privmsg) {
client.sendMessage(nickname, message);
} else {
client.sendNotice(nickname, message);
}
}
public void sendNotifications(@NotNull final User requester, @NotNull final Channel channel, @NotNull final Client client) {
Preconditions.checkNotNull(requester, "requester was null");
Preconditions.checkNotNull(channel, "channel was null");
Preconditions.checkNotNull(client, "client was null");
final List<String> accountsInChannel = channel.getUsers().stream()
.map(User::getAccount)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
this.getRegistrations().stream()
.filter(r -> accountsInChannel.contains(r.getServicesAccount()))
.filter(r -> r.hasOption(PingRegistrationOption.RECEIVE))
.filter(r -> !r.getServicesAccount().equalsIgnoreCase(requester.getAccount().orElse(null)))
.forEach(r -> {
final boolean privmsg = r.hasOption(PingRegistrationOption.PRIVMSG);
final Set<User> users = client.getChannels().stream().flatMap(ch -> ch.getUsers().stream()).distinct().filter(user -> r.getServicesAccount().equalsIgnoreCase(user.getAccount().orElse(null))).filter(account -> account != null).collect(Collectors.toSet());
if (r.hasOption(PingRegistrationOption.PING_ALL_AUTHED_NICKS)) {
users.forEach(user -> this.sendNotification(requester, channel, client, user.getNick(), privmsg));
} else {
users.stream().findFirst().ifPresent(user -> this.sendNotification(requester, channel, client, user.getNick(), privmsg));
}
});
}
}