package server.command;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import common.CommonUtils;
import server.AdminFlag;
import server.Player;
import server.SyntaxException;
import server.Utils;
public class IdeaCommand extends Command {
private static final Set<Idea> ideasSorted = new TreeSet<Idea>();
private static final Map<Integer,Idea> ideasById = new HashMap<Integer,Idea>();
private static int nextId = 1;
public IdeaCommand() {
super(CommandCategory.SYSTEM, "Idea submission/voting system.");
}
@Override
public void run(Player player) throws SyntaxException {
String subcmd = CommandProcessor.nextToken();
if (subcmd == null) {
throw new SyntaxException();
}
if (subcmd.equals("list")) {
if (CommandProcessor.nextToken() != null) {
throw new SyntaxException();
}
boolean adminView = player.getAdminFlags().contains(AdminFlag.ADMIN_VIEWS);
boolean gotOne = false;
String[][] data = new String[ideasSorted.size()][4];
String[] headers = new String[] { "id", "submitter", "votes", "description" };
int[] sizes = new int[] { 40, 100, 40 };
int idx = 0;
for (Idea idea : ideasSorted) {
gotOne = true;
String submitter;
if (adminView || idea.player == player.getId()) {
submitter = Utils.capitalize(player.getNickname(idea.player, true));
}
else {
submitter = "";
}
data[idx][0] = String.valueOf(idea.ideaId);
data[idx][1] = submitter;
data[idx][2] = String.valueOf(idea.votes.size());
data[idx][3] = idea.description;
idx++;
}
player.sendTable(data, headers, sizes);
if (!gotOne) {
player.sendText(true, "No ideas found. Why don't you submit one?");
return;
}
}
else if (subcmd.equals("submit")) {
String description = CommandProcessor.getRemaining();
if (description == null || description.length() == 0) {
throw new SyntaxException();
}
Idea idea = new Idea(player.getId(), description);
ideasById.put(idea.ideaId, idea);
ideasSorted.add(idea);
player.sendText(true, "Your idea has been submitted, and has been assigned #" + idea.ideaId);
}
else if (subcmd.equals("delete")) {
String sId = CommandProcessor.nextToken();
if (sId == null || CommandProcessor.nextToken() != null) {
throw new SyntaxException();
}
if (sId.startsWith("#")) {
sId = sId.substring(1);
}
int ideaId;
try {
ideaId = Integer.parseInt(sId);
}
catch (NumberFormatException ex) {
throw new SyntaxException();
}
Idea idea = ideasById.get(ideaId);
if (idea == null) {
player.sendText(true, "Invalid idea number: " + ideaId);
return;
}
if (!player.getAdminFlags().contains(AdminFlag.ADMIN_BUILDER)) {
if (idea.player != player.getId() || idea.votes.size() > 0) {
player.sendText(true, "You can only delete ideas that were submitted by you and have no votes.");
return;
}
}
ideasSorted.remove(idea);
ideasById.remove(idea.ideaId);
player.sendText(true, "Idea #" + idea.ideaId + " has been deleted.");
}
else if (subcmd.equals("vote")) {
String sId = CommandProcessor.nextToken();
if (sId == null || CommandProcessor.nextToken() != null) {
throw new SyntaxException();
}
if (sId.startsWith("#")) {
sId = sId.substring(1);
}
int ideaId;
try {
ideaId = Integer.parseInt(sId);
}
catch (NumberFormatException ex) {
throw new SyntaxException();
}
Idea idea = ideasById.get(ideaId);
if (idea == null) {
player.sendText(true, "Invalid idea number: " + ideaId);
return;
}
if (idea.votes.contains(player.getId())) {
player.sendText(true, "You have already voted for that idea.");
return;
}
ideasSorted.remove(idea);
idea.votes.add(player.getId());
ideasSorted.add(idea); player.sendText(true, "Your vote in favor of idea #" + idea.ideaId + " has been recorded.");
}
else if (subcmd.equals("unvote")) {
String sId = CommandProcessor.nextToken();
if (sId == null || CommandProcessor.nextToken() != null) {
throw new SyntaxException();
}
if (sId.startsWith("#")) {
sId = sId.substring(1);
}
int ideaId;
try {
ideaId = Integer.parseInt(sId);
}
catch (NumberFormatException ex) {
throw new SyntaxException();
}
Idea idea = ideasById.get(ideaId);
if (idea == null) {
player.sendText(true, "Invalid idea number: " + ideaId);
return;
}
if (!idea.votes.contains(player.getId())) {
player.sendText(true, "You haven't voted for that idea.");
return;
}
ideasSorted.remove(idea);
idea.votes.remove(player.getId());
ideasSorted.add(idea); player.sendText(true, "Your vote in favor of idea #" + idea.ideaId + " has been removed.");
}
else {
throw new SyntaxException();
}
}
@Override
public String[] getSyntax(Player player) {
return new String[] {
"LIST",
"SUBMIT <description>",
"VOTE <number>",
"UNVOTE <number>",
"DELETE <number>",
};
}
private static int getFreeId() {
return nextId++;
}
public static void doSave(ObjectOutputStream oos) throws IOException {
oos.writeInt(1); oos.writeObject(ideasById);
}
public static void doLoad(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.readInt(); Map<?,?> ideas = (Map<?,?>) ois.readObject();
Iterator<?> iter = ideas.values().iterator();
while (iter.hasNext()) {
Idea idea = (Idea) iter.next();
nextId = Math.max(nextId, idea.ideaId + 1);
ideasById.put(idea.ideaId, idea);
ideasSorted.add(idea);
}
}
private static class Idea implements Comparable<Idea>, Externalizable {
private static final long serialVersionUID = -5272756720705232111L;
public int ideaId;
public int player;
public String description;
public Set<Integer> votes = new HashSet<Integer>();
public Idea() {
}
public Idea(int player, String description) {
this.ideaId = getFreeId();
this.player = player;
this.description = description.intern();
}
public int compareTo(Idea idea) {
int comp = new Integer(votes.size()).compareTo(new Integer(idea.votes.size()));
if (comp == 0) {
comp = - new Integer(ideaId).compareTo(new Integer(idea.ideaId));
}
return comp;
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(1); out.writeInt(ideaId);
out.writeInt(player);
out.writeObject(description);
out.writeObject(votes);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
in.readInt(); ideaId = in.readInt();
player = in.readInt();
description = (String) in.readObject();
votes = CommonUtils.uncheckedCast(in.readObject());
}
}
}