package com.papagiannis.tuberun.fetchers;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import android.os.AsyncTask;
import android.util.Log;
import com.papagiannis.tuberun.plan.PartialRoute;
import com.papagiannis.tuberun.plan.PartialRouteType;
import com.papagiannis.tuberun.plan.Plan;
import com.papagiannis.tuberun.plan.Route;
public class PlanFetcher extends Fetcher {
final String q = "http://yia.nnis.gr/tuberun/getPlan.php";
// final String q = "http://tuberun.dyndns.org:55559/getPlan.php";
private Plan plan;
private transient RequestTask task=null;
private static final long serialVersionUID = 1L;
public PlanFetcher(Plan plan) {
super();
this.plan = plan;
}
@Override
public Date getUpdateTime() {
return new Date();
}
BasicCookieStore cookies;
StringBuilder postData;
private String errors = "";
public String getErrors() {
return errors;
}
@Override
public void update() {
errors = "";
postData = new StringBuilder();
cookies = new BasicCookieStore();
RequestTask r = new RequestTask(new HttpCallback() {
public void onReturn(String s) {
getCallBack1(s);
}
});
r.setDesktopUserAgent();
r.setCookies(cookies);
task=r;
String query = q + "?" + plan.getRequestString();
r.execute(query);
}
String param = "";
private transient AsyncTask<String, Integer, Plan> aTask=null;
private void getCallBack1(String response) {
try {
if (response == null || response.equals(""))
throw new Exception(
"The server did not respond to your request (2)");
aTask = new AsyncTask<String, Integer, Plan>() {
@Override
protected Plan doInBackground(String... params) {
try {
return parseXMLResponse(params[0]);
} catch (Exception e) {
return new Plan();
}
}
protected void onPostExecute(Plan result) {
plan.copyRoutesFrom(result);
plan.copyAlterativeDestinationsFrom(result);
plan.copyAlterativeOriginsFrom(result);
plan.copyAcquiredStareFrom(result);
notifyClients();
}
};
aTask.execute(response);
} catch (Exception e) {
errors += e.getMessage();
notifyClients();
}
}
public Plan getResult() {
return plan;
}
public boolean isErrorResult() {
return !errors.equals("");
}
private Plan parseXMLResponse(String response) throws Exception {
Plan plan = new Plan();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document dom = builder
.parse(new InputSource(new StringReader(response)));
NodeList ilist = dom.getElementsByTagName("itdItinerary");
Node itinerary= ilist.item(0);
if (itinerary!=null && itinerary.getChildNodes().getLength()>0) {
//A plan has been calculated
NodeList routesList = dom.getElementsByTagName("itdRouteList");
for (int i = 0; i < routesList.getLength(); i++) {
Node routeList = routesList.item(i);
NodeList routes = routeList.getChildNodes();
for (int j = 0; j < routes.getLength(); j++) {
Node route = routes.item(j);
plan.addRoute(getRouteFromNode(route));
}
}
}
else {
//Need more details about options
plan.setRequestId(getRequestId(dom));
plan.setSessionId(getSessionId(dom));
NodeList odvlist = dom.getElementsByTagName("itdOdv");
LinkedHashMap<String,String> alternatives=getAlternatives(odvlist,"destination");
for (Entry<String, String> s:alternatives.entrySet()) plan.addAlternativeDestination(s.getKey(), s.getValue());
alternatives=getAlternatives(odvlist,"origin");
for (Entry<String, String> s:alternatives.entrySet()) plan.addAlternativeOrigin(s.getKey(), s.getValue());
}
return plan;
}
private String getSessionId(Document dom) {
NodeList requestlist = dom.getElementsByTagName("itdRequest");
if (requestlist.getLength()==0) return "";
return requestlist.item(0).getAttributes().getNamedItem("sessionID").getNodeValue();
}
private String getRequestId(Document dom) {
NodeList requestlist = dom.getElementsByTagName("itdTripRequest");
if (requestlist.getLength()==0) return "";
return requestlist.item(0).getAttributes().getNamedItem("requestID").getNodeValue();
}
private LinkedHashMap<String,String> getAlternatives(NodeList odvList, String type) {
LinkedHashMap<String,String> result=new LinkedHashMap<String,String>();
for (int i = 0; i < odvList.getLength(); i++) {
Node odvNode = odvList.item(i);
Node odvNodeUsage=odvNode.getAttributes().getNamedItem("usage");
if (!type.equalsIgnoreCase(odvNodeUsage.getNodeValue())) continue;
Boolean isIdentified=false;
NodeList odvChildren= odvNode.getChildNodes();
for (int j = 0; j < odvChildren.getLength(); j++) {
Node child = odvChildren.item(j);
if (child.getNodeName().equalsIgnoreCase("itdOdvName")) {
Node state=child.getAttributes().getNamedItem("state");
isIdentified=state.getNodeValue().equalsIgnoreCase("identified");
if (isIdentified) break;
NodeList nameChildren=child.getChildNodes();
for (int k = 0; k < nameChildren.getLength(); k++) {
Node nameChild = nameChildren.item(k);
if (nameChild.getNodeName().equalsIgnoreCase("odvNameElem")) {
Node n = nameChild.getChildNodes().item(0);
String value = nameChild.getAttributes().getNamedItem("value").getNodeValue();
result.put(n.getNodeValue(), value);
}
}
}
}
}
return result;
}
@SuppressWarnings("deprecation")
private Route getRouteFromNode(Node route) {
Route result = new Route();
NamedNodeMap attributes = route.getAttributes();
Node duration = attributes.getNamedItem("publicDuration");
String dur = duration.getNodeValue();
String[] tokens = dur.split(":");
Date ddur = new Date();
ddur.setHours(Integer.parseInt(tokens[0]));
ddur.setMinutes(Integer.parseInt(tokens[1]));
result.setDuration(ddur);
Node name = attributes.getNamedItem("changes");
result.setChanges(Integer.parseInt(name.getNodeValue()));
Node distance = attributes.getNamedItem("distance");
result.setDistance(Integer.parseInt(distance.getNodeValue()));
NodeList children = route.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node c = children.item(i);
if (!c.getNodeName().equals("itdPartialRouteList"))
continue;
NodeList partials = c.getChildNodes();
for (int j = 0; j < partials.getLength(); j++) {
result.addPartialRoute(getPartialRouteFromNode(partials.item(j)));
}
break;
}
return result;
}
private PartialRoute getPartialRouteFromNode(Node node) {
PartialRoute result = new PartialRoute();
NamedNodeMap attributes = node.getAttributes();
Node distance = attributes.getNamedItem("distance");
if (distance != null)
result.setDistance(Integer.parseInt(distance.getNodeValue()));
Node minutes = attributes.getNamedItem("minutes");
if (minutes != null)
result.setMinutes(Integer.parseInt(minutes.getNodeValue()));
else {
minutes = attributes.getNamedItem("timeMinute");
if (minutes != null)
result.setMinutes(Integer.parseInt(minutes.getNodeValue()));
}
NodeList clist = node.getChildNodes();
for (int i = 0; i < clist.getLength(); i++) {
Node child = clist.item(i);
if (child.getNodeName().equals("itdPoint")) {
NamedNodeMap pointAttributes = child.getAttributes();
Node id = pointAttributes.getNamedItem("stopID");
Node name = pointAttributes.getNamedItem("name");
Node type = pointAttributes.getNamedItem("usage");
Date time = getTimeFromPoint(child);
if (type.getNodeValue().equals("departure")) {
// from
if (id != null)
result.setFromId(id.getNodeValue());
if (name != null)
result.setFromName(name.getNodeValue());
result.setFromTime(time);
} else {
// to
if (id != null)
result.setToId(id.getNodeValue());
if (name != null)
result.setToName(name.getNodeValue());
result.setToTime(time);
}
} else if (child.getNodeName().equals("itdMeansOfTransport")) {
NamedNodeMap pointAttributes = child.getAttributes();
Node motType = pointAttributes.getNamedItem("motType");
if (motType != null)
result.setMeansOfTransportType(motType.getNodeValue());
else
result.setMeansOfTransportType(PartialRouteType.WALK);
Node name = pointAttributes.getNamedItem("name");
if (name != null)
result.setMeansOfTransportName(name.getNodeValue());
Node shortname = pointAttributes.getNamedItem("shortname");
if (shortname != null)
result.setMeansOfTransportShortName(shortname
.getNodeValue());
} else if (child.getNodeName().equalsIgnoreCase("itdPathCoordinates")) {
ArrayList<Integer> coordinates=getCoordinatesFromPartialNode(child);
for (Integer j:coordinates) result.addCoordinate(j);
}
}
return result;
}
private ArrayList<Integer> getCoordinatesFromPartialNode(Node coordNode) {
ArrayList<Integer> result=new ArrayList<Integer>();
NodeList clist = coordNode.getChildNodes();
for (int i = 0; i < clist.getLength(); i++) {
Node child = clist.item(i);
if (child.getNodeName().equalsIgnoreCase("itdcoordinatebaseelemlist")) {
NodeList coordList = child.getChildNodes();
for (int j = 0; j < coordList.getLength(); j++) {
Node baseElem = coordList.item(j);
if (baseElem.getNodeName().equalsIgnoreCase("itdcoordinatebaseelem")) {
NodeList xyList = baseElem.getChildNodes();
if (xyList.getLength()!=2) break;
Node x=xyList.item(0);
Node y=xyList.item(1);
if (x==null || y==null) break;
if (x.getNodeName().equalsIgnoreCase("x") && y.getNodeName().equalsIgnoreCase("y")) {
try {
String s=x.getChildNodes().item(0).getNodeValue();
int f=s.indexOf(".");
int xi=Integer.parseInt(s.substring(0,f));
s=y.getChildNodes().item(0).getNodeValue();
f=s.indexOf(".");
int yi=Integer.parseInt(s.substring(0,f));
result.add(xi);
result.add(yi);
}
catch (Exception e) {
continue;
}
}
else break;
}
else break;
}
}
}
return result;
}
@SuppressWarnings("deprecation")
private Date getTimeFromPoint(Node point) {
Date result = new Date();
try {
NodeList clist = point.getChildNodes();
for (int i = 0; i < clist.getLength(); i++) {
Node child = clist.item(i);
if (child.getNodeName().equals("itdDateTime")) {
Node timeNode = child.getLastChild();
NamedNodeMap attributes = timeNode.getAttributes();
Node hour = attributes.getNamedItem("hour");
Node minute = attributes.getNamedItem("minute");
if (hour != null) {
result.setHours(Integer.parseInt(hour.getNodeValue()));
}
if (minute != null) {
result.setMinutes(Integer.parseInt(minute
.getNodeValue()));
}
break;
}
}
} catch (Exception e) {
Log.v("TubeRun", "Failed to get time from point");
}
return result;
}
@Override
public void abort() {
if (task!=null) task.cancel(true);
if (aTask!=null) task.cancel(true);
}
}