package com.papagiannis.tuberun.fetchers;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.http.impl.client.BasicCookieStore;
public class OysterFetcher extends Fetcher {
private static final long serialVersionUID = 1L;
private String username="";
private String password="";
private String oyster_no="";
private String oyster_balance="";
private HashMap<String,String> cards=new HashMap<String,String>();
@SuppressWarnings("deprecation")
private Date update_time=new Date(2000,1,1);
private transient RequestTask task=null;
private static HashMap<String,OysterFetcher> instances =new HashMap<String, OysterFetcher>();
public static synchronized OysterFetcher getInstance(String username, String password) {
if (!instances.containsKey(username+password)) {
instances.put(username+password,new OysterFetcher(username, password));
}
return instances.get(username+password);
}
private OysterFetcher(String username, String password) {
super();
this.username=(username==null)?"":username.trim();
this.password=(password==null)?"":password.trim();
}
@Override
public Date getUpdateTime() {
return update_time;
}
BasicCookieStore cookies;
StringBuilder postData;
private String errors="";
public String getErrors() {
return errors;
}
protected AtomicBoolean isFirst = new AtomicBoolean(true);
@Override
public void update() {
boolean first = isFirst.compareAndSet(true, false);
if (!first) return; // only one at a time
errors="";
cards.clear();
cardsReturned.set(0);
postData = new StringBuilder();
cookies = new BasicCookieStore();
String q1 = "https://oyster.tfl.gov.uk/oyster/security_check";
postData.append("j_username="+username+"&j_password="+password+"&Sign+in=Sign+in");
PostRequestTask r = new PostRequestTask(new HttpCallback() {
public void onReturn(String s) {
getCallBack1(s);
}
});
r.setPostData(postData);
r.setCookies(cookies);
task=r;
r.execute(q1);
}
String param = "";
private int totalCards=0;
private AtomicInteger cardsReturned=new AtomicInteger(0);
private static final String mark1="Choose card number";
private static final String mark2="Balance: £";
private static final String mark3="<span class=\"label\">Balance:</span>\r\n\t<span class=\"content\">£";
private void getCallBack1(String response) {
try {
if (response==null || response.equals(""))
throw new Exception("The server oyster.tfl.gov.uk did not respond to your request (1)");
if (response.contains("Login failed")) {
throw new Exception("Login failed, please check your credentials.");
}
int i=response.indexOf(mark1);
int j=response.indexOf(mark2);
int k=response.indexOf(mark3);
if (i>0) {
totalCards=0;
response=response.substring(i);
while (true) {
String mark="<option value=\"";
int ni=response.indexOf(mark);
if (ni==-1) {
if (totalCards==0) throw new Exception("No cards detected");
break;
}
response=response.substring(ni+mark.length());
int end=response.indexOf("\"");
oyster_no=response.substring(0, end);
response=response.substring(end);
postData = new StringBuilder();
String q = "https://oyster.tfl.gov.uk/oyster/selectCard.do";
postData.append("method=input&cardId="+oyster_no);
PostRequestTask r = new PostRequestTask(new HttpCallback() {
public void onReturn(String s) {
getCallBack2(s);
}
});
r.setPostData(postData);
r.setCookies(cookies);
task=r;
r.execute(q);
totalCards++;
}
//multiple cards parsing
}
else if (j>0 || k>0) {
totalCards=1;
//single card parsing
getCallBack2(response);
}
else {
errors+="Failed to locate card number";
isFirst.set(true);
notifyClients();
}
return;
} catch (Exception e) {
errors+=e.getMessage();
isFirst.set(true);
notifyClients();
}
}
private void getCallBack2(String response) {
try {
if (response==null || response.equals(""))
throw new Exception("The server tfl.gov.uk did not respond to your request (3)");
String mark="<h2>Card No: ";
int i=response.indexOf(mark);
if (i<0) throw new Exception("Cannot parse server response");
response=response.substring(i+mark.length());
String number=response.substring(0,response.indexOf("</h2>"));
response=response.substring(response.indexOf("</h2>"));
mark="Balance: £";
i=response.indexOf(mark);
if (i<0) {
mark="£";
i=response.indexOf(mark);
}
if (i<0) throw new Exception("Cannot parse server response");
response=response.substring(i+mark.length());
oyster_balance="£"+response.substring(0,response.indexOf("</span>"));
cards.put(number, oyster_balance);
update_time=new Date();
cardsReturned.incrementAndGet();
} catch (Exception e) {
errors+=e.getMessage();
} finally {
isFirst.set(true);
if (totalCards==cardsReturned.get()) notifyClients();
}
}
public Boolean hasResult() {
Date now=new Date();
Boolean isFresh = (now.getTime() - update_time.getTime()) / 1000 < 5 * 60;
return isFresh && !isErrorResult() && !oyster_balance.equals("");
}
public CharSequence getResult() {
if (!errors.equals("")) return "ERROR";
else return oyster_balance;
}
public boolean isErrorResult() {
return !errors.equals("");
}
@Override
public void abort() {
isFirst.set(true);
if (task!=null) task.cancel(true);
}
public HashMap<String,String> getCards() {
return cards;
}
}