package net.traviangui.hostInterface;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.MissingResourceException;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.traviangui.hostInterface.HttpServer.Pair.IntPair;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.cookie.CookieSpec;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
/**
* In VilloNanny, there is one instance of Util per Server.
*
*/
public class HttpServer
{
private static final Logger log = Logger.getLogger( HttpServer.class.toString());
public static final String USERAGENT_DEFAULT = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
private static final String PATTERN_UTIL_SRC = "src=\"([^\"\\\\?]*)[^\"]*\"";
private static final String PATTERN_IS_LOGIN_PAGE = "<input\\\\s*type\\\\s*=\\\\s*\"image\"\\\\s*value\\\\s*=\\\\s*\"login\"";
private static final String SERVER_URL = "http://s3.travian.net";
private static final String SERVER_LOGIN = "magius";
private static final String SERVER_PASSWORD = "3antonio";
private HttpClient client;
public String httpGetPage(String urlString) throws Exception
{
int remaningTries = 3;
String page = "";
while( remaningTries > 0) {
remaningTries--;
try {
page = httpGetPage( urlString, false);
} catch ( Exception e) {
log.warning( "Error getting html page...");
}
}
return page;
}
public String httpGetPage( String urlString, boolean quick) throws Exception
{
log.finest( "Getting " + urlString + " (with login check) ...");
if (urlString==null) {
log.warning( "Nothing to get");
return "";
}
String page = httpGetPageNoLogin( urlString, quick);
// Check if login page returned, and perform login
if( isLoginPage( page)) {
String s = "Login page returned; performing login for " + urlString;
// log.debug(s);
//EventLog.log(s);
page = loginWithPage( page, urlString, quick);
if (isLoginPage(page)) {
throw new ConversationException("Can't login");
}
// Now fetch original page again because we might get the wrong village otherwise
page = httpGetPageNoLogin( urlString, quick);
}
log.finest( "Got (with login check) " + urlString);
return page;
}
public String httpGetPageNoLogin(String urlString, boolean quick) throws ConversationException, InterruptedException
{
// console.checkFlags();
// GAC modify to run from local files for decoupled debug
testMode = 0; //configManager.getInt("testMode/@httpGet", 0);
if ((testMode & 1) == 1) {
// log.debug("GAC Getting " + urlString + " from DiskFile " + fname);
String page = null;
try {
page = readFromFile(urlString);
// return the page
return page;
} catch (IOException e) {
// GAC - check if in read/write mode, in which case ignore the error and carry on to access page
if ((testMode & 2) == 2) {
// Warn what we are doing
// EventLog.log("Cannot Find Page on Disk " + urlString + " ***** Getting from Server");
log.info( "Cannot Find Page on Disk " + urlString + " ***** Getting from Server");
} else {
// TODO Auto-generated catch block
e.printStackTrace();
// GAC just exit for now - create missing file manually and restart!
System.exit(-1);
}
}
} // else { // GAC added for test mode, returns above so just continue rather than make second change
GetMethod get = new GetMethod(urlString);
addHeaders(get);
try {
log.finest("Getting " + urlString + " ...");
client.executeMethod(get);
// Save the url for reference header
lastVisitPage = urlString;
String page = get.getResponseBodyAsString();
// Find src fields and load them to simulate real browser
// Pattern p = Pattern.compile(" src=\"([^\"\\?]*)[^\"]*\"");
Pattern p = getPattern( PATTERN_UTIL_SRC);
Matcher m = p.matcher(page);
try {
while (m.find()) {
String src = m.group(1);
getIfNotCachedAndDrop(urlString, src);
}
} catch (IndexOutOfBoundsException e) {
saveTestPattern("util.src", p, page);
throw new ConversationException(e);
}
// GAC add mode to write file to disk
if ((testMode & 2) == 2) {
writeToFile(urlString, page);
}
return page;
} catch (java.net.ConnectException e) {
throw new ConversationException("Connection to \"" + urlString + "\" failed (check network/proxy setup).", e);
} catch (IOException e) {
throw new ConversationException("Can't read page " + urlString, e);
} finally {
get.releaseConnection();
Thread.sleep( 2*1000);
log.finest("Got " + urlString);
}
}
/**
* Force login
* @throws Exception
*/
public void login(boolean sharp) throws Exception {
int counter = 2; // retries
while (true) {
try {
String loginUrlString = SERVER_URL;
// Get login form. The method will detect the login page and perform login for us
httpGetPage(loginUrlString);
break;
} catch (ConversationException e) {
log.finest("Login failed: " + e.getMessage());
log.severe( e.toString());
if (counter-- > 0) {
log.finest("Retrying...");
Thread.sleep( 2*1000);
} else {
log.severe("Login error ");
throw e;
}
}
}
}
/**
*
* @throws Exception
* @loginForm the html page containing the login form
* @urlString the url that returned the login form
*/
private String loginWithPage(String loginForm, String urlString, boolean quick) throws Exception {
Pattern p;
Matcher m;
fillLoginParameters( loginForm, urlString);
String loginPostString = baseUrl + "dorf1.php";
Calendar localTime = new GregorianCalendar();
localTime.set(Calendar.YEAR, 1970);
localTime.set(Calendar.MONTH, Calendar.JANUARY);
localTime.set(Calendar.DAY_OF_MONTH, 1);
String pageAfterLogin = httpPostPage(loginPostString, loginPostNames, loginPostValues, quick);
// See if we got any cookies
CookieSpec cookiespec = CookiePolicy.getDefaultSpec();
Cookie[] logoncookies = cookiespec.match(serverHost, serverPort, "/", false, client.getState().getCookies());
if (logoncookies.length==0) {
this.loginPassword=null;
throw new ConversationException("Authentication failed");
}
log.info("Authentication ok");
// Find server time
p = Pattern.compile("(?s)id=\"tp1\"[^>]*>(.*?)</span>");
// p = getPattern("util.serverTime");
m = p.matcher(pageAfterLogin);
if (m.find()) {
String serverTimeString = m.group(1);
Date serverDate;
try {
serverDate = timeFormat.parse(serverTimeString); // TODO timezone del server
} catch (ParseException e) {
throw new ConversationException("Can't parse server time: " + serverTimeString);
}
this.serverTimeMillisDelta = localTime.getTimeInMillis() - serverDate.getTime();
} else {
if (isSurveyPage(pageAfterLogin)) {
log.finest("Survey page or broadcast msg detected, see logs for more details!");
log.fine(pageAfterLogin);
// survey or broadcast message is present
httpGetPage(HttpServer.getFullUrl(urlString, "dorf1.php?ok=1"));
}
throw new ConversationException("Can't find server time");
}
return pageAfterLogin;
}
private static final String ERROR_MESSAGE_BUNDLE_NAME = "Messages";
private static boolean utf8;
public static final long MILLI_SECOND = 1000;
public static final long MILLI_MINUTE = 60 * MILLI_SECOND;
public static final long MILLI_HOUR = 60 * MILLI_MINUTE;
private String serverHost;
private int serverPort;
private List<String> loginPostNames;
private List<String> loginPostValues;
private String loginPassword = null; // Remember password when typed by user
private long serverTimeMillisDelta=0; // Difference between PC time and server time in milliseconds (>0 if server lower)
private String baseUrl; // http://s1.travian3.it/
private SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");;
// private SimpleDateFormat completionTimeFormat = new SimpleDateFormat("HH:mm");
// private int redirectCounter = 0;
private String lastVisitPage = "";
public static final String P_FLAGS = "(?s)(?i)(?u)"; // dotall, case insensitive, unicode case match
private static int screenx = 1280;
private static int screeny = 1024;
private static int uidCounter = 0;
private static int testMode = 0; // GAC add mode to run from saved pages on disk
private static String TEST_DIR = "logs" + File.separator + "TestPages-"; // and the root of a location for them
private static HttpServer instance;
/*
* GAC added for test mode
* Fetch entire contents of a text file and return as a string, use to load pages from disk if doing repeated testing
* controlled by global config variable <testMode httpGet="1" />
* the files are stored in a sub directory specified by TEST_DIR with the language appended to seperate them
*
* Based on PatternDebugger routine but without header so can save source pages as files from browser using view source
* mode 1 - read from disk, currently does a hard exit if cannot find a page to support simple debug strategy
* mode 2 - write all pages to disk, coverts . and ? characters to _ and appends .txt for easy access from text editors
* TODO mode 3, read from disk until cannot find a page then fetch it and write it
* - does not always work because of cookies error
*/
private String readFromFile(String urlString) throws IOException {
// build directory from base + language specific so store identical named pages in different location
String inputDir = TEST_DIR + "es";
String filePath = null;
// extend to include server as a sub directory - control via config variable?
filePath = urlString.substring(urlString.indexOf('/', 1)+2, urlString.indexOf('.', 1) );
inputDir = inputDir + File.separator + filePath;
// EventLog.log("Getting URL from Disk " + urlString + " Translator " + getTranslator().getLanguage() );
// log.debug("GAC Getting URL from Disk " + urlString);
if ( urlString.indexOf('/', 8) > 0) {
filePath = inputDir + File.separator + urlString.substring(1+urlString.indexOf('/', 8)); // GAC get name at end of string after first http://
} else {
// no substring
filePath = inputDir + File.separator + "dorf1.php";
}
// store base Url as not calling login
baseUrl = urlString.substring(0, urlString.indexOf("/", "http://".length()) + 1);
// check for characters that are not valid in filenames and then add .txt to make into safe windows file
filePath = filePath.replace('?', '_');
filePath = filePath.replace('.', '_');
filePath = filePath.concat(".txt");
// default the map look ups so dont have to do all of them
if (filePath.indexOf("&c=") !=-1) {
// check if have this one
File f = new File(filePath);
if (f.exists()) {
// all ok use it
} else {
// default to an unoccupied valley - needs to be saved manually
filePath = TEST_DIR + "es" + File.separator + "karte_php_unoccupied.txt";
}
}
log.finest("Getting " + urlString + " from DiskFile \"" + filePath + "\"");
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
/*
String line = in.readLine(); // date
if (line==null) {
throw new IOException("Empty file");
}
this.desc = in.readLine();
if (this.desc == null) {
throw new IOException("File too short: missing description on second line");
}
log.info("Description: " + desc);
String patternString = in.readLine();
if (patternString==null) {
throw new IOException("File too short: missing pattern on third line");
}
log.info("patternString: " + patternString);
this.pattern = Pattern.compile(patternString);
*/
StringBuffer pageBuffer = new StringBuffer();
String line = in.readLine();
while (line!=null) {
pageBuffer.append(line + "\n");
line = in.readLine();
}
in.close();
return pageBuffer.toString();
}
public void writeToFile(String urlString, String page) {
String outputDir = TEST_DIR + "es";
String outputFilename = null;
// GAC add server as subdirectory
outputFilename = urlString.substring(urlString.indexOf('/', 1)+2, urlString.indexOf('.', 1) );
outputDir = outputDir + File.separator + outputFilename;
// EventLog.log("Getting URL from Disk " + urlString);
log.fine( "Write URL to Disk " + urlString);
if ( urlString.indexOf('/', 8) > 0) {
outputFilename = urlString.substring(urlString.indexOf('/', 8) + 1); // GAC get name at end of string after first http://
} else {
// no substring
outputFilename = "dorf1.php";
}
// store base Url as not calling login
baseUrl = urlString.substring(0, urlString.indexOf("/", "http://".length()) + 1);
// check for characters that are not valid in filenames and then add .txt to make into safe windows file
outputFilename = outputFilename.replace('?', '_');
outputFilename = outputFilename.replace('.', '_');
outputFilename = outputFilename.concat(".txt");
// GAC dont default the map look ups so one day may have all of them
// String outputFilename = "match" + pattern.toString().hashCode() + ".txt";
// Globally synchronized to avoid file corruption when writing concurrently from different "servers"
// GAC Performance may be an issue if used a lot
// TODO - add server name into directory structure
synchronized (HttpServer.class) {
try {
File outDirFile = new File(outputDir);
if (!outDirFile.exists()) {
log.fine("Creating directory " + outDirFile.getAbsolutePath());
outDirFile.mkdirs();
}
String fullPath = outputDir + File.separator + outputFilename;
PrintWriter out = new PrintWriter(new File(fullPath), "utf8");
// out.println(new Date());
// out.println(desc);
// out.println(pattern.toString());
out.println(page);
out.close();
log.fine("Page saved to file " + fullPath);
} catch (IOException e) {
log.severe("Cannot output page to file" + e.toString());
}
}
}
// Used by AutoConfigurator only to create a minimal Util
public HttpServer() {
this.client = getHttpClient();
}
/**
* Return a unique identifier
* @param prefix
* @return
*/
public static synchronized String getNewUid(String prefix) {
uidCounter++;
// This is reasonably unique and short
return prefix + String.valueOf(System.currentTimeMillis()/1000 % 10000000) + uidCounter;
}
public static void log(String message, Exception e) {
log.severe( message + ": " + e.toString());
}
private boolean isSurveyPage(String page) {
// Pattern p = Pattern.compile("dorf1.php\\?ok=1");
Pattern p = getPattern("util.isSurveyPage");
Matcher m = p.matcher(page);
return m.find();
}
private void fillLoginParameters(String loginForm, String urlString) throws Exception
{
URL loginUrl;
if (!urlString.endsWith("/")) {
urlString += "/";
}
try {
loginUrl = new URL(urlString);
} catch (MalformedURLException e) {
throw new Exception( "loginUrl for server is invalid. " + e.toString());
}
baseUrl = urlString.substring(0, urlString.indexOf("/", "http://".length()) + 1);
serverHost = loginUrl.getHost();
serverPort = loginUrl.getPort();
if (serverPort==-1) {
serverPort = loginUrl.getDefaultPort();
if (serverPort==-1) {
serverPort = 80;
}
}
loginPostNames = new ArrayList<String>();
loginPostValues = new ArrayList<String>();
// Find username field
String userNameField;
// Pattern p = Pattern.compile("<input .* type=\"text\".*name=\"(.*?)\"");
Pattern p = getPattern("<input .* type=\"text\" name=\"(.*?)\"");
Matcher m = p.matcher(loginForm);
if (m.find()) {
userNameField = m.group(1);
} else {
saveTestPattern("util.userNameField", p, loginForm);
throw new ConversationException("Can't find username input field");
}
if (m.find()) {
log.warning( "Too many username input fields; ignoring...");
}
loginPostNames.add(userNameField);
String user = SERVER_LOGIN;
loginPostValues.add(user);
// Find password field
String pwdField;
p = Pattern.compile("<input .*type=\"password\".*name=\"(.*?)\"");
// p = getPattern("util.pwdField");
m = p.matcher(loginForm);
if (m.find()) {
pwdField = m.group(1);
} else {
saveTestPattern("util.pwdField", p, loginForm);
throw new ConversationException("Can't find password input field");
}
if (m.find()) {
log.warning("Too many password input fields; ignoring...");
}
loginPostNames.add(pwdField);
String pwd = SERVER_PASSWORD;
if (pwd==null) {
pwd = this.loginPassword;
if (pwd==null) {
log.finest("Waiting for password input");
pwd = inputLine("Type the password for " + user + " on " + ": ");
this.loginPassword = pwd;
}
}
loginPostValues.add(pwd);
// Find all hidden fields
addHiddenPostFields(loginForm, "<form method=\"post\" name=\"snd\" action=\"dorf1.php\">", loginPostNames, loginPostValues);
// addHiddenPostFields(loginForm, "util.hiddenPostFields", loginPostNames, loginPostValues);
// Add button params
addButtonCoordinates("s1", "login", 80, 20, loginPostNames, loginPostValues);
try {
int pos = loginPostNames.indexOf("w");
loginPostValues.set(pos, screenx + ":" + screeny); // %3A = ":"
} catch (Exception e) {
log.warning("Can't find login parameter 'w' (ignoring)");
}
// Other params
// loginPostNames.add("autologin");
// loginPostValues.add("ja");
}
public static void addButtonCoordinates(String prefix, String value, int x, int y, List<String> names, List<String> values)
{
names.add( prefix);
values.add( value);
int vx = (int) (Math.random() * x);
int vy = (int) (Math.random() * y);
names.add(prefix + ".x");
values.add(Integer.toString(vx));
names.add(prefix + ".y");
values.add(Integer.toString(vy));
}
/**
* @return the start position of the form
*/
public int addHiddenPostFields(String page, String patternKey, List<String> names, List<String> values) throws ConversationException {
Pattern p;
Matcher m;
// Find start of form
// p = Pattern.compile(startFromPattern);
p = getPattern(patternKey);
m = p.matcher(page);
if (!m.find()) {
saveTestPattern(patternKey, p, page);
throw new ConversationException("Can't find start of form with pattern \"" + p.pattern() + "\"");
}
int startPos = m.start();
// Find end of form
p = Pattern.compile("</form>");
// p = getPattern("util.formEnd");
m = p.matcher(page);
m.region(startPos, page.length());
// Confirm send resource does not have "</form>"
int endPos = page.length();
if (m.find()) {
endPos = m.end();
}
// Test for JamVM problem
if (endPos < startPos ) {
log.fine(String.format("endPos=%s is before startPos=%s. Setting endPos to end of file", endPos, startPos));
endPos = page.length();
// log.debug("endPos pattern = " + getPattern("util.formEnd"));
// log.debug("Page dump\n"+page);
}
// Find hidden fields
p = Pattern.compile("<input +type=\"hidden\" +name=\"(.*?)\" +value=\"(.*?)\"");
// p = getPattern("util.hiddenField");
m = p.matcher(page);
m.region(startPos, endPos);
while (m.find()) {
String name = m.group(1);
String value = m.group(2);
names.add(name);
values.add(value);
}
return startPos;
}
public boolean isLoginPage(String page) {
Pattern p;
Matcher m;
p = Pattern.compile("(?s)(?i)<input type=\"image\" value=\"login\"");
// p = getPattern( PATTERN_IS_LOGIN_PAGE);
m = p.matcher(page);
return m.find();
}
private void addHeaders( HttpMethod m) {
m.setRequestHeader(
"Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
m.addRequestHeader("Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
m.addRequestHeader("Accept-Language", "en,it;q=0.5");
m.addRequestHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
// Use the lastVisitPage
if (!lastVisitPage.equals("")) {
m.addRequestHeader("Referer", lastVisitPage);
}
}
public String httpPostPage(String url, List<String> postNames, List<String> postValues, boolean quick) throws ConversationException, Exception {
log.fine("Posting " + url + " ...");
// GAC modify to run from local files for decoupled debug
if ((testMode & 1) == 1) {
String page = null;
try {
page = readFromFile(url+postNames);
return page;
} catch (IOException e) {
// GAC - check if in read/write mode, in which case ignore the error and carry on to access page
if ((testMode & 2) == 2) {
// Warn what we are doing
log.finest("Cannot Find Page on Disk " + url + " ***** Getting from Server");
} else {
// TODO Auto-generated catch block
e.printStackTrace();
// GAC just exit for now - create missing file manually and restart!
System.exit(-1);
}
}
} // else { // GAC added for test mode
// continue with original code
PostMethod httpPost = new PostMethod(url);
addHeaders(httpPost);
NameValuePair[] postData = new NameValuePair[postNames.size()];
for (int i = 0; i < postData.length; i++) {
postData[i] = new NameValuePair(postNames.get(i), postValues.get(i));
}
httpPost.setRequestBody(postData);
String page;
try {
client.executeMethod(httpPost);
// Save the url for reference header
lastVisitPage = url;
page = httpPost.getResponseBodyAsString();
} catch (IOException e) {
throw new ConversationException("Can't read page " + url, e);
} finally {
httpPost.releaseConnection();
}
// Follow any redirects
int statuscode = httpPost.getStatusCode();
if ((statuscode == HttpStatus.SC_MOVED_TEMPORARILY) ||
(statuscode == HttpStatus.SC_MOVED_PERMANENTLY) ||
(statuscode == HttpStatus.SC_SEE_OTHER) ||
(statuscode == HttpStatus.SC_TEMPORARY_REDIRECT)) {
Header header = httpPost.getResponseHeader("location");
if (header != null) {
String newuri = header.getValue();
if ((newuri == null) || (newuri.equals(""))) {
newuri = "/";
}
log.fine("Redirect target: " + newuri);
page = httpGetPageNoLogin(newuri, quick);
} else {
throw new ConversationException("Invalid redirect (location=null)");
}
}
log.fine("Posted " + url);
// GAC add mode to write file to disk
if ((testMode & 2) == 2) {
writeToFile(url+postNames, page);
}
return page;
}
private void getIfNotCachedAndDrop(String pageUrl, String src) {
// GAC modify to run from local files for decoupled debug
if (testMode == 1) {
// GAC TODO - consider how handle in mode 3, at the moment only ignoring for mode 1
// hoping it was cached previously!
log.finest("Ignoring Cache Request: " + pageUrl);
return ;
} // else { // GAC added for test mode
try {
// src can be relative or absolute
// - when relative, ok
// - when absolute, remove start
String relative = src;
if (src.startsWith("http://")) { // Not relative
int pos = relative.indexOf("/", "http://".length());
relative = relative.substring(pos);
} else {
// Make full url
int pos = pageUrl.indexOf("/", "http://".length());
if (pos==-1) {
src = pageUrl + "/" + src;
} else {
src = pageUrl.substring(0, pos + 1) + src;
}
}
String cachePath = "imageCache";
File file = new File(cachePath, relative);
if (!file.canRead()) {
log.fine("Caching resource : " + src);
GetMethod getObj = new GetMethod(src);
try {
addHeaders(getObj);
client.executeMethod(getObj);
// Non need to save it, just create a placeholder
file.getParentFile().mkdirs();
file.createNewFile();
// Save in cache
// FileOutputStream output = new FileOutputStream(file);
// InputStream input = getObj.getResponseBodyAsStream();
// int data;
// while ((data=input.read()) > -1) {
// output.write(data);
// }
// output.close();
} catch (Exception e) {
log.severe("Error while caching resource " + src + " (ignored)" + e.toString());
// ignored
} finally {
getObj.releaseConnection();
}
}
// else {
// log.debug("Skipping cached resource: " + src);
// }
} catch (Exception e) {
log.warning("Error while checking cache for resource " + src + " (ignored):" + e.getMessage());
// ignored
}
}
// public static void sleep(long milli) {
// if (milli<0) {
// log.fine("Not sleeping: negative value " + milli);
// return;
// }
// Date awake = new Date(System.currentTimeMillis() + milli);
// String s = String.format("Sleeping %s minutes until %s ...", milli / MILLI_MINUTE, format(awake));
//// log.info(s);
// log.finest(s);
// try {
// Thread.sleep(milli);
// } catch (InterruptedException e) {
// log.fine("Sleep interrputed");
// // Nothing
// }
//// log.debug("Resuming after pause");
// }
public static String getFullUrl(String currentPageUrlString, String newUrlEnd) {
return currentPageUrlString.substring(0, currentPageUrlString.lastIndexOf("/") + 1) + newUrlEnd;
}
public static String getFullUrl( String newUrlEnd) {
return SERVER_URL + "/" + newUrlEnd;
}
/**
* Convert "HH:mm:ss" into seconds
* @param timeString
* @return
*/
public static int timeToSeconds(String timeString) {
int value = 0;
String[] parts = timeString.trim().split(":");
for (int i = 0; i < parts.length; i++) {
String elem = parts[i];
int elemVal = Integer.parseInt(elem);
value = value*60 + elemVal;
}
return value;
}
/**
* Transforms "HH:mm:ss" into date
* @param timeNeeded
* @return
*/
// public Date getCompletionTime(String timeNeeded) {
// int seconds = timeToSeconds(timeNeeded);
// Calendar time = new GregorianCalendar();
// time.add(Calendar.SECOND, seconds);
// return time.getTime();
// }
// public Date calcWhenAvailable(ResourceTypeMap production, ResourceTypeMap availableResources, ResourceTypeMap neededResources) {
// float hoursNeeded = 0;
// for (ResourceType res : ResourceType.values()) {
// if (res==ResourceType.FOOD) {
// continue;
// }
// int missing = neededResources.get(res) - availableResources.get(res);
// float time = missing / (float)production.get(res);
// if (time>hoursNeeded) {
// hoursNeeded = time;
// }
// }
// int seconds = (int) (hoursNeeded * 3600);
// Calendar cal = new GregorianCalendar();
// cal.add(Calendar.SECOND, seconds);
// return cal.getTime();
// }
/**
* Convert milliseconds into "HH:mm:ss"
* @param milliPause
* @return
*/
public String milliToTimeString(long milliPause) {
long hours = milliPause / 3600000;
long min = (milliPause - hours*3600000) / 60000;
long sec = (milliPause % 60000) / 1000;
return hours + ":" + min + ":" + sec; // TODO aggiungere lo zero iniziale se una cifra
}
public static String inputLine(String prompt) throws Exception {
return inputLine(prompt, null);
}
public static String inputLine(String prompt, String defaultValue) throws Exception {
// TODO hide typing or at least clear password at the end
System.out.println(prompt);
BufferedReader readIn = new BufferedReader(new InputStreamReader(System.in));
try {
String result = readIn.readLine();
// Failed attempt to clear password (doesn't work): System.out.println((char)27 + "A ");
if (defaultValue!=null && (result==null || result.trim().length()==0)) {
System.out.println(defaultValue);
return defaultValue;
}
return result;
} catch (IOException e) {
throw new Exception("Can't read user input", e);
}
}
public Date serverTimeToLocalTime(Date serverTime) {
return new Date(serverTime.getTime() + serverTimeMillisDelta);
}
/**
* Returns a localised message, loaded from a message bundle.
* @param key the key to the message
* @param caller the class of the caller, needed to retrieve the bundle file from the same package of the caller
* @return
*/
// public static String getLocalMessage(String key, Class caller) {
// try {
// ResourceBundle bundle = getResourceBundle(ERROR_MESSAGE_BUNDLE_NAME, caller);
// return bundle.getString(key);
// } catch (MissingResourceException e) {
// return key;
// }
// }
/**
* Ottiene un bundle caricando il file che si trova nello stesso package della classe indicata
* @param bundleName nomeBundle
* @param callerClass chiamante
* @return ResourceBundle
* @throws MissingResourceException bundle non esiste
*/
// public static ResourceBundle getResourceBundle(String bundleName, Class caller) throws MissingResourceException {
// StringBuffer fullBundleName = new StringBuffer(caller.getPackage().getName()).append(".").append(bundleName);
// return ResourceBundle.getBundle(fullBundleName.toString());
// }
private HttpClient getHttpClient() {
HttpClient client = new HttpClient();
// Timeout
client.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, (int) (MILLI_SECOND * 30)); // milliseconds
client.getParams().setParameter(HttpConnectionParams.CONNECTION_TIMEOUT, (int) (MILLI_SECOND * 30));
client.getParams().setParameter(HttpConnectionParams.STALE_CONNECTION_CHECK, true);
// User agent
String userAgent = USERAGENT_DEFAULT;
client.getParams().setParameter(HttpMethodParams.USER_AGENT, userAgent);
// Proxy
// if (configManager.getBoolean("proxy/@enabled", false)) {
// String host = configManager.getString("proxy/hostName", null);
// int port = configManager.getInt("proxy/hostPort", 0);
// client.getHostConfiguration().setProxy(host, port);
// String user = configManager.getString("proxy/proxyUser", null);
// String pwd = configManager.getString("proxy/proxyPassword", null);
// if (user != null) {
// Credentials credentials = null;
// String ntHost = configManager.getString("proxy/NTHost", null);
// String ntDomain = configManager.getString("proxy/NTDomain", null);
// if ((ntHost != null) && (ntDomain != null)) {
// credentials = new NTCredentials(user, pwd, ntHost, ntDomain);
// } else {
// credentials = new UsernamePasswordCredentials(user, pwd);
// }
// AuthScope authScope = new AuthScope(host, port);
// client.getState().setProxyCredentials(authScope, credentials);
// }
// }
return client;
}
public Pattern getPattern(String patternString, Object ... params)
{
patternString = String.format( patternString, params);
return Pattern.compile(P_FLAGS + patternString);
}
public void saveTestPattern(String desc, Pattern pattern, String page) {
String outputDir = "logs/patterns";
PatternDebugger patternDebugger = new PatternDebugger(desc, pattern, page);
patternDebugger.toFile(outputDir);
}
// /**
// * Convert map id to a coordinate
// * @param id the map id
// * @return coorinate
// */
// public static IntPair id2coord(int id) {
// int x = id % 801;
// x -= 401;
// int y = id / 801;
// y = 400 - y;
// return new IntPair(x, y);
// }
// /**
// * Convert a coordinate into map id
// * @param coord the coordinate
// * @return the map id.
// */
// public static int coord2id(IntPair coord) {
// int id = (400 - coord.second) * 801 + coord.first + 401;
// return id;
// }
/**
*
* @author biminus
* A class for holding 2 elements.
* @param <T1> first
* @param <T2> second
*/
// TODO I would put this in the misc package [xtian]
public static class Pair<T1, T2> {
public T1 first;
public T2 second;
public Pair(T1 t1, T2 t2) {
first = t1;
second = t2;
}
public String toString() {
return "(" + first + "," + second + ")";
}
/**
* Pair<Integer, Integer> class for convenience.
* @author biminus
*
*/
public static class IntPair extends Pair<Integer, Integer> {
public IntPair(Integer first, Integer second) {
super(first, second);
}
}
}
public static HttpServer getHttpServer( )
{
if( instance == null ) {
instance = new HttpServer( );
}
return instance;
}
public String getMapPage( int coordX, int coordY) throws ConversationException, Exception
{
String page = HttpServer.getHttpServer().httpGetPage( SERVER_URL + "/karte.php");
Thread.sleep( (long) (2000 + 1000*Math.random()));
// now need to call Post to move to Specified Coordinates
List<String> postNames = new ArrayList<String>();
List<String> postValues = new ArrayList<String>();
// Util.addHiddenPostFields(page, "<form method=\"POST\" name=\"snd\" action=\"build.php\">", postNames, postValues);
// Util.addButtonCoordinates("s1", 80, 20, postNames, postValues);
// Map Form does not appear to have hidden fields
// post it and get the page back
postNames.add( "xp");
postValues.add( Integer.toString( coordX));
postNames.add( "yp");
postValues.add( Integer.toString( coordY));
addButtonCoordinates("s1", "ok", 0, 0, postNames, postValues);
page = httpPostPage( SERVER_URL + "/karte.php", postNames, postValues, false);
return page;
}
}