package VASSAL.build.module.dice;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Vector;
import java.util.concurrent.ExecutionException;
import org.jdesktop.swingworker.SwingWorker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import VASSAL.build.GameModule;
import VASSAL.build.module.DiceButton;
import VASSAL.build.module.DieRoll;
import VASSAL.build.module.InternetDiceButton;
import VASSAL.tools.ErrorDialog;
import VASSAL.tools.FormattedString;
import VASSAL.tools.io.IOUtils;
/**
* Base DieServer Class
* Does most of the work. Individual Die Servers just need to implement
* {@link #buildInternetRollString} and {@link #parseInternetRollString}
* methods.
*/
public abstract class DieServer {
private static final Logger logger = LoggerFactory.getLogger(DieServer.class);
protected java.util.Random ran;
protected String name;
protected String description;
protected boolean emailOnly;
protected int maxRolls;
protected int maxEmails;
protected String serverURL;
protected boolean passwdRequired = false;
protected String password = "";
protected boolean useEmail;
protected String primaryEmail;
protected String secondaryEmail;
protected boolean canDoSeparateDice = false;
/*
* Each implemented die server must provide this routine to build a
* string that will be sent to the internet site to drive the web-based
* die server. This will usually be a control string passed to a cgi script
* on the site.
*/
public abstract String[] buildInternetRollString(RollSet mr);
/*
* Each implemented die server must provide this routine to interpret the
* html output generated by the site in response to the
* {@link #buildInternetRollString} call.
*/
public abstract void parseInternetRollString(RollSet rollSet, Vector<String> results);
/*
* Internet Die Servers should always implement roll by calling back to
* {@link #doInternetRoll}
*/
public abstract void roll(RollSet mr, FormattedString format);
public DieServer() {
ran = GameModule.getGameModule().getRNG();
}
/*
* Some Internet servers can only roll specific numbers of dice or
* dice with specific sides. These are the default settings.
*/
public int[] getnDiceList() {
return new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
}
public int[] getnSideList() {
return new int[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 20, 30, 50, 100, 1000};
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public boolean isPasswdRequired() {
return passwdRequired;
}
public String getPasswd() {
return password;
}
public void setPasswd(String s) {
password = s;
}
public void setPrimaryEmail(String e) {
primaryEmail = e;
}
public String getPrimaryEmail() {
return primaryEmail;
}
public void setSecondaryEmail(String e) {
secondaryEmail = e;
}
public String getSecondaryEmail() {
return secondaryEmail;
}
public void setUseEmail(boolean use) {
useEmail = use;
}
public boolean getUseEmail() {
return useEmail;
}
public int getMaxEmails() {
return maxEmails;
}
/**
* The text reported before the results of the roll
*/
protected String getReportPrefix(String d) {
return " *** " + d + " = ";
}
/**
* The text reported after the results of the roll;
* @deprecated
*/
@Deprecated
protected String getReportSuffix() {
return " *** <" + GameModule.getGameModule().getChatter().getHandle() + ">";
}
/*
* Called by the Inbuilt server - Basically the same as the code
* in the original DiceButton
*/
public void doInbuiltRoll(RollSet mroll) {
DieRoll[] rolls = mroll.getDieRolls();
for (int i = 0; i < rolls.length; i++) {
DieRoll roll = rolls[i];
String desc = roll.getDescription();
int nSides = roll.getNumSides();
int nDice = roll.getNumDice();
int plus = roll.getPlus();
boolean reportTotal = roll.isReportTotal();
String val = getReportPrefix(desc);
int total = 0;
for (int j = 0; j < nDice; ++j) {
int result = (int) (ran.nextFloat() * nSides + 1) + plus;
if (reportTotal) {
total += result;
}
else {
val += result;
if (j < nDice - 1)
val += ",";
}
if (reportTotal)
val += total;
val += getReportSuffix();
GameModule.getGameModule().getChatter().send(val);
}
}
}
/*
* Internet Servers will call this routine to do their dirty work.
*/
public void doInternetRoll(final RollSet mroll, final FormattedString format) {
// FIXME: refactor so that doInBackground can return something useful
new SwingWorker<Void,Void>() {
@Override
public Void doInBackground() throws Exception {
doIRoll(mroll);
return null;
}
@Override
protected void done() {
try {
get();
reportResult(mroll, format);
}
catch (InterruptedException e) {
ErrorDialog.bug(e);
}
// FIXME: review error message
catch (ExecutionException e) {
logger.error("", e);
final String s = "- Internet dice roll attempt " +
mroll.getDescription() + " failed.";
GameModule.getGameModule().getChatter().send(s);
}
}
}.execute();
}
/**
* Use the configured FormattedString to format the result of a roll
* @param result
* @return
*/
protected String formatResult(String description, String result, FormattedString format) {
format.setProperty(DiceButton.RESULT, result);
format.setProperty(InternetDiceButton.DETAILS, description);
final String text = format.getText();
return text.startsWith("*") ? "*" + text : "* " + text;
}
public void reportResult(RollSet mroll, FormattedString format) {
DieRoll[] rolls = mroll.getDieRolls();
for (int i = 0; i < rolls.length; i++) {
DieRoll roll = rolls[i];
int nDice = roll.getNumDice();
boolean reportTotal = roll.isReportTotal();
String val = "";
int total = 0;
for (int j = 0; j < nDice; j++) {
int result = roll.getResult(j);
if (reportTotal) {
total += result;
}
else {
val += result;
if (j < nDice - 1)
val += ",";
}
}
if (reportTotal)
val += total;
val = formatResult(rolls[i].getDescription(), val, format);
GameModule.getGameModule().getChatter().send(val);
}
}
public void doIRoll(RollSet toss) throws IOException {
final String[] rollString = buildInternetRollString(toss);
final ArrayList<String> returnString = new ArrayList<String>();
// rollString[0] =
// "number1=2&type1=6&number2=2&type2=30&number3=2&type3=30"
// + "&number4=0&type4=2&number5=0&type5=2&number6=0&type6=2&number7=0&type7=2"
// + "&number8=0&type8=2&number9=0&type9=2&number10=0&type10=2"
// + "&emails=&email=b.easton@uws.edu.au&password=IG42506&Submit=Throw+Dice";
final URL url = new URL(serverURL);
final URLConnection connection = url.openConnection();
connection.setDoOutput(true);
final PrintWriter out = new PrintWriter(connection.getOutputStream());
try {
for (String s : rollString) out.println(s);
out.close();
}
finally {
IOUtils.closeQuietly(out);
}
BufferedReader in = null;
try {
in = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) returnString.add(inputLine);
in.close();
}
finally {
IOUtils.closeQuietly(in);
}
parseInternetRollString(toss, new Vector<String>(returnString));
}
/**
*
* Extract the portion of the email address withing the angle brackets.
* Allows Email addresses like 'Joe Blow <j.blow@somewhere.com>'
*/
public String extractEmail(String email) {
int start = email.indexOf('<');
int end = email.indexOf('>');
if (start >= 0 && end >= 0 && end > start) {
return email.substring(start + 1, end);
}
else {
return email;
}
}
}