package org.freecode.irc.votebot;
import org.freecode.irc.CtcpRequest;
import org.freecode.irc.CtcpResponse;
import org.freecode.irc.IrcConnection;
import org.freecode.irc.Privmsg;
import org.freecode.irc.event.CtcpRequestListener;
import org.freecode.irc.event.JoinListener;
import org.freecode.irc.event.NumericListener;
import org.freecode.irc.event.PrivateMessageListener;
import org.freecode.irc.votebot.api.AdminModule;
import org.freecode.irc.votebot.api.FVBModule;
import org.freecode.irc.votebot.dao.PollDAO;
import org.freecode.irc.votebot.dao.VoteDAO;
import org.freecode.irc.votebot.entity.Poll;
import org.freecode.irc.votebot.entity.Vote;
import org.freecode.irc.votebot.modules.admin.LoadModules;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
/**
* User: Shivam
* Date: 17/06/13
* Time: 00:05
*/
public class FreeVoteBot implements PrivateMessageListener, JoinListener {
public static final String CHANNEL_SOURCE = "#freecode";
private String[] channels;
private String nick, realName, serverHost, user;
private int port;
private ScriptModuleLoader sml;
private IrcConnection connection;
private String version;
private ExpiryQueue<String> expiryQueue = new ExpiryQueue<>(1500L);
private LinkedList<FVBModule> moduleList = new LinkedList<>();
private PollDAO pollDAO;
private VoteDAO voteDAO;
public ScheduledExecutorService pollExecutor;
public HashMap<Integer, Future> pollFutures;
private KVStore kvStore;
public void init() {
connectToIRCServer();
NoticeFilter.setFilterQueue(connection, 5000L);
addNickInUseListener();
registerUser();
addCTCPRequestListener();
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
identifyToNickServ();
joinChannels();
kvStore.load();
sml = new ScriptModuleLoader(this);
AdminModule mod = new LoadModules();
mod.setFvb(this);
moduleList.add(mod);
pollExecutor = Executors.newScheduledThreadPool(5);
pollFutures = new HashMap<>();
try {
for (Poll poll : pollDAO.getOpenPolls()) {
long expiry = poll.getExpiry();
int id = poll.getId();
PollExpiryAnnouncer announcer = new PollExpiryAnnouncer(expiry, id, this);
ScheduledFuture future = pollExecutor.scheduleAtFixedRate(announcer, 60000L, 500L, TimeUnit.MILLISECONDS);
announcer.setFuture(future);
pollFutures.put(id, future);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void registerUser() {
try {
connection.register(nick, user, realName);
} catch (IOException e) {
e.printStackTrace();
}
connection.addListener(this);
}
private void addNickInUseListener() {
NumericListener nickInUse = new NumericListener(connection) {
public int getNumeric() {
return IrcConnection.ERR_NICKNAMEINUSE;
}
public void execute(String rawLine) {
FreeVoteBot.this.nick = FreeVoteBot.this.nick + "_";
try {
connection.sendRaw("NICK " + FreeVoteBot.this.nick);
} catch (IOException e) {
e.printStackTrace();
}
}
};
connection.addListener(nickInUse);
}
private void addCTCPRequestListener() {
connection.addListener(new CtcpRequestListener() {
public void onCtcpRequest(CtcpRequest request) {
if (request.getCommand().equals("VERSION")) {
request.getIrcConnection().send(new CtcpResponse(request.getIrcConnection(),
request.getNick(), "VERSION", "FreeVoteBot " + version + " by " + CHANNEL_SOURCE + " on irc.rizon.net"));
} else if (request.getCommand().equals("PING")) {
request.getIrcConnection().send(new CtcpResponse(request.getIrcConnection(),
request.getNick(), "PING", request.getArguments()));
}
}
});
}
private void connectToIRCServer() {
try {
connection = new IrcConnection(serverHost, port);
} catch (IOException e) {
e.printStackTrace();
}
}
private void identifyToNickServ() {
File pass = new File("password.txt");
if (pass.exists()) {
try {
BufferedReader read = new BufferedReader(new FileReader(pass));
String s = read.readLine();
if (s != null) {
connection.send(new Privmsg("NickServ", "identify " + s, connection));
}
read.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void joinChannels() {
for (String channel : channels) {
connection.joinChannel(channel);
}
}
public void onPrivmsg(final Privmsg privmsg) {
if (privmsg.getNick().equalsIgnoreCase(nick)) {
return;
}
String sender = privmsg.getNick().toLowerCase();
if (expiryQueue.contains(sender) || !expiryQueue.insert(sender)) {
return;
}
for (FVBModule module : moduleList) {
try {
if (module.isEnabled() && module.canRun(privmsg)) {
module.process(privmsg);
return;
}
} catch (Exception e) {
privmsg.send(e.getMessage());
}
}
}
public void setNick(String nick) {
this.nick = nick;
}
public void setRealName(String realName) {
this.realName = realName;
}
public void setServerHost(String serverHost) {
this.serverHost = serverHost;
}
public void setUser(String user) {
this.user = user;
}
public void setPort(String port) {
this.port = Integer.parseInt(port);
}
public void setChannels(String channels) {
this.channels = channels.split(",");
}
public void setKvStore(KVStore kvStore) {
this.kvStore = kvStore;
}
public void setModules(final FVBModule[] modules) {
moduleList.clear();
moduleList.addAll(Arrays.asList(modules));
for (FVBModule module : moduleList) {
if (module instanceof AdminModule) {
((AdminModule) module).setFvb(this);
}
}
}
public void setVersion(String version) {
this.version = version;
}
public boolean addModule(final FVBModule module) {
return moduleList.add(module);
}
public void addModules(final Collection<? extends FVBModule> module) {
moduleList.addAll(module);
for (FVBModule mod : moduleList) {
if (mod instanceof AdminModule) {
((AdminModule) mod).setFvb(this);
}
}
}
public boolean removeModule(final FVBModule module) {
return moduleList.remove(module);
}
public void removeModules(final Collection<? extends FVBModule> module) {
moduleList.removeAll(module);
}
public ScriptModuleLoader getScriptModuleLoader() {
return sml;
}
public void sendMsg(String s) {
for (String channel : channels) {
connection.sendMessage(channel, s);
}
}
public void setPollDAO(PollDAO pollDAO) {
this.pollDAO = pollDAO;
}
public PollDAO getPollDAO() {
return pollDAO;
}
public void setVoteDAO(VoteDAO voteDAO) {
this.voteDAO = voteDAO;
}
public VoteDAO getVoteDAO() {
return voteDAO;
}
private DateFormat getDateFormatter() {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z", Locale.UK);
dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/London"));
return dateFormat;
}
static class PollVotes implements Comparable<PollVotes> {
int votes;
String question;
PollVotes(int votes, String question) {
this.votes = votes;
this.question = question;
}
public int compareTo(PollVotes o) {
return o.votes - votes;
}
}
@Override
public void onJoin(String channel, String nick, String mask) {
System.out.println(nick + " joins " + channel);
try {
Poll[] openPolls = pollDAO.getOpenPolls();
Poll[] pollsNotVotedIn = voteDAO.getPollsNotVotedIn(openPolls, nick);
PollVotes[] pollVotes = new PollVotes[pollsNotVotedIn.length];
for (int i = 0; i < pollsNotVotedIn.length; i++) {
Poll poll = pollsNotVotedIn[i];
String question = poll.getQuestion();
int id = poll.getId();
long expiry = poll.getExpiry();
Date date = new Date(expiry);
Vote[] votes = voteDAO.getVotesOnPoll(id);
String msg = String.format("Open poll #%d: \"%s\", ends: %s, votes: %d", id, question, getDateFormatter().format(date), votes.length);
pollVotes[i] = new PollVotes(votes.length, msg);
}
if (pollVotes.length == 0) {
connection.sendNotice(nick, "No new polls to vote in!");
} else {
Arrays.sort(pollVotes);
connection.sendNotice(nick, "Trending polls list:");
if (pollVotes.length >= 3) {
connection.sendNotice(nick, pollVotes[0].question);
connection.sendNotice(nick, pollVotes[1].question);
connection.sendNotice(nick, pollVotes[2].question);
} else {
for (PollVotes p : pollVotes) {
connection.sendNotice(nick, p.question);
}
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}