From 4712d0c15819127615a9c6bc69c89b78487967e3 Mon Sep 17 00:00:00 2001
From: Nikolaus Krismer <niko@krismer.de>
Date: Wed, 19 Mar 2014 16:14:27 +0100
Subject: [PATCH] changed method order changed getAdjLinks method (a little)

---
 .../it/unibz/inf/isochrone/db/Database.java   | 846 +++++++++---------
 .../it/unibz/inf/isoga/db/DatabaseWeb.java    | 236 ++---
 2 files changed, 542 insertions(+), 540 deletions(-)

diff --git a/src/main/java/it/unibz/inf/isochrone/db/Database.java b/src/main/java/it/unibz/inf/isochrone/db/Database.java
index 6e901b89..36508592 100644
--- a/src/main/java/it/unibz/inf/isochrone/db/Database.java
+++ b/src/main/java/it/unibz/inf/isochrone/db/Database.java
@@ -65,6 +65,8 @@ public class Database<T extends ConfigDataset> {
 	protected boolean isIncoming;
 	protected Connection connection;
 
+	// Constructor
+
 	public Database(final T config, final Mode mode, final Direction direction) {
 		this.config = config;
 		this.isIncoming = (direction == Direction.INCOMING);
@@ -73,212 +75,265 @@ public class Database<T extends ConfigDataset> {
 		connection = ConfigIsochrone.getInstance().getConnection();
 		pstmtsCacheMap = new HashMap<String, PreparedStatement>();
 
+		final String configDatecodes = config.getTableDatecodes();
+		final String configEdges = config.getTableEdges();
+		final String configSchedule = config.getTableSchedule();
+		final String configVertex = config.getTableVertex();
+		final String configVertexDensity = config.getTableVertexDensity();
+
 		queryLatestDepartureTimeHomo = "SELECT TIME_D, TIME_A, ROUTE_ID FROM ("
 				+ " SELECT TIME_D,TIME_A,ROUTE_ID FROM "
-				+ config.getTableSchedule()
+				+ configSchedule
 				+ " WHERE SOURCE = ? AND  TARGET = ? AND ROUTE_ID IN (%S) AND TIME_A>=? AND TIME_A<=? AND SERVICE_ID IN (%S)) C WHERE TIME_D >= ?";
 
 		queryEarliestArrivalTimeHomo = "SELECT TIME_D, TIME_A, ROUTE_ID FROM ("
 				+ " SELECT TIME_D, TIME_A, ROUTE_ID FROM "
-				+ config.getTableSchedule()
+				+ configSchedule
 				+ " WHERE SOURCE = ? AND TARGET = ? AND ROUTE_ID IN (%S) AND TIME_D>=? AND TIME_D<=?"
 				+ " AND SERVICE_ID IN (%S)) C WHERE TIME_A <= ?";
 
-		queryGetAllEdges = "SELECT ID, SOURCE, TARGET, LENGTH, EDGE_MODE, ROUTE_ID FROM " + config.getTableEdges();
+		queryGetAllEdges = "SELECT ID, SOURCE, TARGET, LENGTH, EDGE_MODE, ROUTE_ID FROM " + configEdges;
 
-		queryGetContinuousEdges = "SELECT ID, SOURCE, TARGET, LENGTH, EDGE_MODE, ROUTE_ID FROM " + config.getTableEdges() + " WHERE EDGE_MODE=" + NW_MODE_CONTINUOUS;
+		queryGetContinuousEdges = "SELECT ID, SOURCE, TARGET, LENGTH, EDGE_MODE, ROUTE_ID FROM " + configEdges + " WHERE EDGE_MODE=" + NW_MODE_CONTINUOUS;
 
 		queryGetDateCodes = "SELECT DISTINCT SERVICE_ID "
 				+ " FROM "
-				+ config.getTableDaymarker()
+				+ configDatecodes
 				+ " WHERE (((MONDAY::int::bit || TUESDAY::int::bit || WEDNESDAY::int::bit || THURSDAY::int::bit"
 				+ " || FRIDAY::int::bit || SATURDAY::int::bit || SUNDAY::int::bit) & ?::bit(7))::int) > 0"
 				+ " AND START_DATE <= ? AND END_DATE >= ? "
 				+ " ORDER BY SERVICE_ID";
-		queryGetCoordinatesFromNode = "SELECT ID,ST_X(GEOMETRY) X, ST_Y(GEOMETRY) Y FROM " + config.getTableVertex() + " WHERE ID=?";
+		queryGetCoordinatesFromNode = "SELECT ID,ST_X(GEOMETRY) X, ST_Y(GEOMETRY) Y FROM " + configVertex + " WHERE ID=?";
 
 		queryGetRange = "select D0.DENSITY s0, D0.E_DISTANCE ed0, D1.DENSITY s1, D1.E_DISTANCE ed1 from "
 				+ "(SELECT ID,DENSITY,E_DISTANCE FROM "
-				+ config.getTableVertexDensity()
+				+ configVertexDensity
 				+ " WHERE ID=? AND DENSITY<? ORDER BY DENSITY DESC LIMIT 1) D0 FULL JOIN "
 				+ "(SELECT ID,DENSITY,E_DISTANCE FROM "
-				+ config.getTableVertexDensity()
+				+ configVertexDensity
 				+ " WHERE ID=? AND DENSITY>=? ORDER BY DENSITY ASC LIMIT 1) D1 ON D0.ID=D1.ID";
 
 		queryLoadLinksFromIER = "SELECT L.ID, L.SOURCE,L.SOURCE_MODE,L.TARGET,L.TARGET_MODE,L.LENGTH,L.EDGE_MODE,L.ROUTE_ID,"
 				+ (isIncoming ? "L.SOURCE_OUTDEGREE" : "L.TARGET_INDEGREE")
-				+ " DEGREE FROM " + config.getTableEdges() + " L, "
-				+ config.getTableVertex() + " N "
+				+ " DEGREE FROM " + configEdges + " L, "
+				+ configVertex + " N "
 				+ " WHERE L."
 				+ (isIncoming ? "TARGET" : "SOURCE")
 				+ "=N.ID" + " AND ST_DWITHIN(ST_PointFromText(?,?),N.GEOMETRY,?)='TRUE'";
 
 		queryGetLink = "SELECT SOURCE, TARGET, "
 				+ (isIncoming ? "SOURCE_OUTDEGREE" : "TARGET_INDEGREE")
-				+ " NODE_DEGREE, LENGTH FROM " + config.getTableEdges()
+				+ " NODE_DEGREE, LENGTH FROM " + configEdges
 				+ " WHERE ID = ? AND EDGE_MODE=" + NW_MODE_CONTINUOUS;
 
 		queryGetContinuousLink = "SELECT SOURCE, TARGET, "
 				+ (isIncoming ? "SOURCE_C_OUTDEGREE" : "TARGET_C_INDEGREE")
-				+ " NODE_DEGREE, LENGTH FROM " + config.getTableEdges()
+				+ " NODE_DEGREE, LENGTH FROM " + configEdges
 				+ " WHERE ID = ? AND EDGE_MODE=" + NW_MODE_CONTINUOUS;
 
 		queryGetContinuousNode = "SELECT "
 				+ (isIncoming ? "SOURCE_C_OUTDEGREE" : "TARGET_C_INDEGREE")
-				+ " NODE_DEGREE FROM " + config.getTableEdges()
+				+ " NODE_DEGREE FROM " + configEdges
 				+ (isIncoming ? "SOURCE=?" : "TARGET=?")
 				+ "AND EDGE_MODE=" + NW_MODE_CONTINUOUS;
 
 		queryGetMrneXNode = "SELECT "
 				+ (isIncoming ? "OUTDEGREE" : "INDEGREE")
-				+ " NODE_DEGREE, ST_X(GEOMETRY) X, ST_Y(GEOMETRY) Y FROM " + config.getTableVertex() + " WHERE ID=?";
+				+ " NODE_DEGREE, ST_X(GEOMETRY) X, ST_Y(GEOMETRY) Y FROM " + configVertex + " WHERE ID=?";
 
 		queryGetLinksInRange = "SELECT L.ID,L.SOURCE,L.SOURCE_MODE,L.TARGET,L.TARGET_MODE,L.LENGTH,L.EDGE_MODE,L.ROUTE_ID,"
-				+ (isIncoming ? "L.SOURCE_OUTDEGREE" : "L.TARGET_INDEGREE") + " DEGREE FROM " + config.getTableEdges()
-				+ " L, " + config.getTableVertex() + " N WHERE L." + (isIncoming ? "TARGET" : "SOURCE")
+				+ (isIncoming ? "L.SOURCE_OUTDEGREE" : "L.TARGET_INDEGREE") + " DEGREE FROM " + configEdges
+				+ " L, " + configVertex + " N WHERE L." + (isIncoming ? "TARGET" : "SOURCE")
 				+ "=N.ID AND st_intersects(N.GEOMETRY,%S)";
 
 		if (isIncoming) {
-			queryGetAdjLinks = "SELECT ID,SOURCE NODE_ID,SOURCE_OUTDEGREE NODE_DEGREE,LENGTH,EDGE_MODE,ROUTE_ID FROM " + config.getTableEdges() + " WHERE TARGET=?";
-			queryGetAdjContinuousLinks = "SELECT ID,SOURCE NODE_ID,SOURCE_C_OUTDEGREE NODE_DEGREE,LENGTH,EDGE_MODE,ROUTE_ID FROM " + config.getTableEdges()
-					+ " WHERE TARGET=? AND EDGE_MODE=" + NW_MODE_CONTINUOUS;
+			queryGetAdjLinks = "SELECT ID, SOURCE NODE_ID, SOURCE_OUTDEGREE NODE_DEGREE, LENGTH, EDGE_MODE, ROUTE_ID FROM "
+				+ configEdges + " WHERE TARGET=?";
+			queryGetAdjContinuousLinks = "SELECT ID, SOURCE NODE_ID, SOURCE_C_OUTDEGREE NODE_DEGREE, LENGTH, EDGE_MODE, ROUTE_ID FROM "
+				+ configEdges + " WHERE TARGET=? AND EDGE_MODE=" + NW_MODE_CONTINUOUS;
+		} else {
+			queryGetAdjLinks = "SELECT ID, TARGET NODE_ID, TARGET_INDEGREE NODE_DEGREE, LENGTH, EDGE_MODE, ROUTE_ID FROM "
+				+ configEdges + " WHERE SOURCE=?";
+			queryGetAdjContinuousLinks = "SELECT ID, TARGET NODE_ID, TARGET_C_INDEGREE NODE_DEGREE, LENGTH FROM "
+				+ configEdges + " WHERE TARGET=? AND EDGE_MODE=";
+		}
+	}
+
+	// Public methods
+
+	public void addLink(final Link link, final short degree, final Map<Integer, Node> nodes, final Map<Integer, List<Link>> adjList) {
+		int n1, n2;
+		if (isIncoming) {
+			n1 = link.getStartNode();
+			n2 = link.getEndNode();
 		} else {
-			queryGetAdjLinks = "SELECT ID,TARGET NODE_ID,TARGET_INDEGREE NODE_DEGREE, LENGTH,EDGE_MODE,ROUTE_ID FROM " + config.getTableEdges() + " WHERE SOURCE=?";
-			queryGetAdjContinuousLinks = "SELECT ID,TARGET NODE_ID, TARGET_C_INDEGREE NODE_DEGREE,LENGTH FROM " + config.getTableEdges() + " WHERE TARGET=? AND EDGE_MODE=";
+			n1 = link.getEndNode();
+			n2 = link.getStartNode();
+		}
+
+		addNode(n1, degree, nodes);
+		addNode(n2, nodes);
+		if (!adjList.containsKey(n2)) {
+			adjList.put(n2, new ArrayList<Link>());
 		}
+
+		adjList.get(n2).add(link);
 	}
 
 	/**
-	 * Gets a prepared statement and caches it in a map. This
-	 * is much more efficient than creating a new prepared statement
-	 * each time a query needs to be called, and recalculating the
-	 * queryplan each time.
+	 * Closes all the open prepared statements and the database connection.
+	 * This should be called once you're done with the database.
+	 */
+	public void close() {
+		for (final PreparedStatement pstmt : pstmtsCacheMap.values()) {
+			DbUtils.closeQuietly(pstmt);
+		}
+	}
+
+	/**
+	 * Gets all links adjacent to a given node.
 	 *
-	 * @param query The prepared statement that is needed
-	 * @return the cached prepared statement object
+	 * @param nodeId the node to which the links should be adjacent
+	 * @param nodes the nodes HashMap to which eventual new nodes should be added
+	 * @return a list of links adjacent to the given nodeId
 	 */
-	// FIXME: Find a fix for prepared statements with parameters
-	// (we should NOT set strings in preparedStatemens just because we want to cache something)
-	protected PreparedStatement getPstmt(final String query) {
+	public Collection<Link> getAdjLinks(final int nodeId, final Map<Integer, Node> nodes) {
+		final PreparedStatement stmt = getPstmt((mode == Mode.UNIMODAL) ? queryGetAdjContinuousLinks : queryGetAdjLinks);
+		final Collection<Link> adjLinks = new ArrayList<Link>();
+
+		ResultSet rs = null;
 		try {
-			if (pstmtsCacheMap.containsKey(query) && !pstmtsCacheMap.get(query).isClosed()) {
-				return pstmtsCacheMap.get(query);
+			stmt.setInt(1, nodeId);
+			rs = stmt.executeQuery();
+			while (rs.next()) {
+				final int adjNodeId = rs.getInt("NODE_ID");
+				final short degree = rs.getShort("NODE_DEGREE");
+				addNode(adjNodeId, degree, nodes);
+				adjLinks.add(createLinkFromResultSet(nodeId, adjNodeId, rs));
 			}
-
-			final PreparedStatement pstmt = connection.prepareStatement(query);
-			pstmtsCacheMap.put(query, pstmt);
-			return pstmt;
 		} catch (final SQLException e) {
 			e.printStackTrace();
+		} finally {
+			DbUtils.closeQuietly(rs);
 		}
 
-		return null;
+		return adjLinks;
 	}
 
 	/**
-	 * Reads the whole network for the MDijkstra Algorithm.
-	 * The given maps have to be initialized and will be filled up with
-	 * the nodes and links in the network.
+	 * Gets the cost to go from one node to another node.
 	 *
-	 * @param nodes A map in which all the nodes should be stored.
-	 * @param links A map in which all the links should be stored.
+	 * @param node the node from which we should start calculating
+	 * @param adjNode the node to which we want to calculate the cost
+	 * @param routeIds the routeIds that should be taken into consideration
+	 * @param dateCodes the days that should be taken into the account
+	 * @param fromTime the earliest time for which we want to calculate the departure time
+	 * @param toTime the latest time for which we want to calculate the departure time
+	 * @return the cost of for traveling from the start node to the end node
 	 */
-	public void readNetwork(final Map<Integer, Node> nodes, final Map<Integer, Link> links) {
+	public double getAdjNodeCost(final Node node, final Node adjNode, final Set<Short> routeIds, final Set<Integer> dateCodes, final long fromTime, final long toTime) {
+		double minDistance = Double.POSITIVE_INFINITY;
+
 		ResultSet rs = null;
 		try {
-			PreparedStatement stmt;
-			if (mode == Mode.MULTIMODAL) {
-				stmt = getPstmt(queryGetAllEdges);
-			} else {
-				stmt = getPstmt(queryGetContinuousEdges);
-			}
-			rs = stmt.executeQuery();
-			while (rs.next()) {
-				final int linkId = rs.getInt("ID");
-				final int startNodeId = rs.getInt("SOURCE");
-				final int endNodeId = rs.getInt("TARGET");
-				final double length = rs.getDouble("LENGTH");
-				final short routeId = rs.getShort("ROUTE_ID");
-				final byte linkType = rs.getByte("EDGE_MODE");
-
-				int start, end;
-				if (isIncoming) {
-					start = startNodeId;
-					end = endNodeId;
-				} else {
-					start = endNodeId;
-					end = startNodeId;
-				}
-				Node node;
-				if (!nodes.containsKey(end)) {
-					node = new Node(end);
-					nodes.put(end, node);
-				} else {
-					node = nodes.get(end);
-				}
-				if (node.getAdjLinks() == null) {
-					node.setAdjLinks(new ArrayList<Link>());
-				}
-				Link link;
-
-				if (linkType == NW_MODE_CONTINUOUS) {
-					link = new Link(linkId, startNodeId, endNodeId, length);
-				} else {
-					link = new Link(linkId, startNodeId, endNodeId, routeId);
+			if (isIncoming) {
+				rs = getLatestDepartureTime(adjNode.getID(), node.getID(), routeIds, dateCodes, fromTime, Math.round(toTime - node.getDistance()));
+				while (rs.next()) {
+					final long departureTime = rs.getLong("TIME_D");
+					final long arrivalTime = rs.getLong("TIME_A");
+					final short routeId = rs.getShort("ROUTE_ID");
+					adjNode.setDepartureTime(routeId, departureTime);
+					node.setArrivalTime(routeId, arrivalTime);
+					final double distance = toTime - departureTime;
+					if (distance < minDistance) {
+						minDistance = distance;
+						adjNode.setCheapestReachedRouteId(routeId);
+					}
 				}
-				node.addAdjLink(link);
-				links.put(linkId, link);
-				if (!nodes.containsKey(start)) {
-					nodes.put(start, new Node(start));
+			} else {
+				rs = getEarliestArrivalTime(node.getID(), adjNode.getID(), routeIds, dateCodes, Math.round(fromTime + node.getDistance()), toTime);
+				while (rs.next()) {
+					final long departureTime = rs.getLong("TIME_D");
+					final long arrivalTime = rs.getLong("TIME_A");
+					final short routeId = rs.getShort("ROUTE_ID");
+					adjNode.setArrivalTime(routeId, arrivalTime);
+					node.setDepartureTime(routeId, departureTime);
+					final double distance = arrivalTime > 0 ? arrivalTime - fromTime : Double.POSITIVE_INFINITY;
+					if (distance < minDistance) {
+						minDistance = distance;
+						adjNode.setCheapestReachedRouteId(routeId);
+					}
 				}
 			}
 		} catch (final SQLException e) {
-			throw new RuntimeException("Error reading the Network: " + e);
+			e.printStackTrace();
 		} finally {
 			DbUtils.closeQuietly(rs);
 		}
+
+		return minDistance;
 	}
 
 	/**
-	 * Prepares a number of place holders for a prepared statement.
+	 * Gets the coordinates of a node.
 	 *
-	 * @param length The number of placeholders that is needed
-	 * @return a string with the placeholders plugged in to a
-	 *          statement.
+	 * @param nodeId the nodeId of the node for which we should find the coordinates
+	 * @return a point with the coordinates of the node
 	 */
-	protected final String preparePlaceHolders(final int length) {
-		final StringBuilder builder = new StringBuilder();
-		for (int i = 0; i < length; ++i) {
-			builder.append("?");
-			if ((i + 1) < length) {
-				builder.append(",");
+	public Point getCoordinates(final int nodeId) {
+		final PreparedStatement stmt = getPstmt(queryGetCoordinatesFromNode);
+
+		Point gp = null;
+		ResultSet rs = null;
+		try {
+			stmt.setInt(1, nodeId);
+			rs = stmt.executeQuery();
+			if (rs.next()) {
+				gp = new Point(rs.getDouble("X"), rs.getDouble("Y"));
 			}
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		} finally {
+			DbUtils.closeQuietly(rs);
 		}
 
-		return builder.toString();
+		return gp;
 	}
 
 	/**
-	 * Sets the values in the placeholders in a prepared statement, generated by
-	 * the {@link #preparePlaceHolders(int)} method.
+	 * Gets date codes for a given time.
 	 *
-	 * @see #preparePlaceHolders(int)
-	 * @param startIdx the start index where the first object should be placed in the prepared statement
-	 * @param preparedStatement the prepared statement in which the values should be inserted.
-	 * @param values the values that should be inserted into the prepared statement
-	 * @throws SQLException thrown if a parameter could not be set into the prepared statement
-	 * @return the index of the first position that was being left unfilled by the method
+	 * @param time the given
+	 * @return returns a set of date codes
 	 */
-	protected final int setValues(final int startIdx, final PreparedStatement preparedStatement, final Object... values) throws SQLException {
-		for (int i = 0; i < values.length; ++i) {
-			preparedStatement.setObject(startIdx + i, values[i]);
+	public Set<Integer> getDateCodes(final Calendar time) {
+		final PreparedStatement stmt = getPstmt(queryGetDateCodes);
+		final Set<Integer> codes = new HashSet<Integer>();
+
+		ResultSet rs = null;
+		try {
+			final Date date = new Date(time.getTimeInMillis());
+			// CHECKSTYLE:OFF MagicNumber
+			stmt.setString(1, getWeekDayMask(time));
+			stmt.setDate(2, date);
+			stmt.setDate(3, date);
+			// CHECKSTYLE:ON MagicNumber
+
+			rs = stmt.executeQuery();
+			while (rs.next()) {
+				codes.add(rs.getInt("SERVICE_ID"));
+			}
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		} finally {
+			DbUtils.closeQuietly(rs);
 		}
 
-		return startIdx + values.length;
+		return codes;
 	}
 
 	/**
-	 * Gets the latest departure time to start from source, to arrive at the target in time.
+	 * Gets the earliest arrival time at the target when traveled from the source.
 	 *
 	 * @param sourceId the id of the source node
 	 * @param targetId the id of the target node
@@ -289,8 +344,8 @@ public class Database<T extends ConfigDataset> {
 	 * @throws SQLException thrown is the DB update statement can not be executed (or the prepared statement parameters could not be set)
 	 * @return a resultSet with all the times that come into consideration
 	 */
-	public ResultSet getLatestDepartureTime(final int sourceId, final int targetId, final Set<Short> routeIds, final Set<Integer> dateCodes, final long from, final long to) throws SQLException {
-		final String sql = String.format(queryLatestDepartureTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dateCodes.size()));
+	public ResultSet getEarliestArrivalTime(final int sourceId, final int targetId, final Set<Short> routeIds, final Set<Integer> dateCodes, final long from, final long to) throws SQLException {
+		final String sql = String.format(queryEarliestArrivalTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dateCodes.size()));
 		final PreparedStatement statement = getPstmt(sql);
 
 		// CHECKSTYLE:OFF MagicNumber
@@ -300,14 +355,14 @@ public class Database<T extends ConfigDataset> {
 		statement.setLong(idx++, from);
 		statement.setLong(idx++, to);
 		idx = setValues(idx, statement, dateCodes.toArray());
-		statement.setLong(idx, from);
+		statement.setLong(idx, to);
 		// CHECKSTYLE:ON MagicNumber
 
 		return statement.executeQuery();
 	}
 
 	/**
-	 * Gets the earliest arrival time at the target when traveled from the source.
+	 * Gets the latest departure time to start from source, to arrive at the target in time.
 	 *
 	 * @param sourceId the id of the source node
 	 * @param targetId the id of the target node
@@ -318,8 +373,8 @@ public class Database<T extends ConfigDataset> {
 	 * @throws SQLException thrown is the DB update statement can not be executed (or the prepared statement parameters could not be set)
 	 * @return a resultSet with all the times that come into consideration
 	 */
-	public ResultSet getEarliestArrivalTime(final int sourceId, final int targetId, final Set<Short> routeIds, final Set<Integer> dateCodes, final long from, final long to) throws SQLException {
-		final String sql = String.format(queryEarliestArrivalTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dateCodes.size()));
+	public ResultSet getLatestDepartureTime(final int sourceId, final int targetId, final Set<Short> routeIds, final Set<Integer> dateCodes, final long from, final long to) throws SQLException {
+		final String sql = String.format(queryLatestDepartureTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dateCodes.size()));
 		final PreparedStatement statement = getPstmt(sql);
 
 		// CHECKSTYLE:OFF MagicNumber
@@ -329,117 +384,26 @@ public class Database<T extends ConfigDataset> {
 		statement.setLong(idx++, from);
 		statement.setLong(idx++, to);
 		idx = setValues(idx, statement, dateCodes.toArray());
-		statement.setLong(idx, to);
+		statement.setLong(idx, from);
 		// CHECKSTYLE:ON MagicNumber
 
 		return statement.executeQuery();
 	}
 
 	/**
-	 * Gets the cost to go from one node to another node.
+	 * Get a single link from the network and and add the source
+	 * node to the nodes table if necessary.
 	 *
-	 * @param node the node from which we should start calculating
-	 * @param adjNode the node to which we want to calculate the cost
-	 * @param routeIds the routeIds that should be taken into consideration
-	 * @param dateCodes the days that should be taken into the account
-	 * @param fromTime the earliest time for which we want to calculate the departure time
-	 * @param toTime the latest time for which we want to calculate the departure time
-	 * @return the cost of for traveling from the start node to the end node
+	 * @param linkId the id of the link that should be returned
+	 * @param nodes the nodes table to which the node should be added (can only be null if the link is needed)
+	 * @return the link with id linkId
 	 */
-	public double getAdjNodeCost(final Node node, final Node adjNode, final Set<Short> routeIds, final Set<Integer> dateCodes, final long fromTime, final long toTime) {
-		double minDistance = Double.POSITIVE_INFINITY;
+	public Link getLink(final int linkId, final Map<Integer, Node> nodes) {
+		final PreparedStatement stmt = getPstmt((mode == Mode.UNIMODAL) ? queryGetContinuousLink : queryGetLink);
+
+		Link link = null;
 		ResultSet rs = null;
 		try {
-			if (isIncoming) {
-				rs = getLatestDepartureTime(adjNode.getID(), node.getID(), routeIds, dateCodes, fromTime, Math.round(toTime - node.getDistance()));
-				while (rs.next()) {
-					final long departureTime = rs.getLong("TIME_D");
-					final long arrivalTime = rs.getLong("TIME_A");
-					final short routeId = rs.getShort("ROUTE_ID");
-					adjNode.setDepartureTime(routeId, departureTime);
-					node.setArrivalTime(routeId, arrivalTime);
-					final double distance = toTime - departureTime;
-					if (distance < minDistance) {
-						minDistance = distance;
-						adjNode.setCheapestReachedRouteId(routeId);
-					}
-				}
-			} else {
-				rs = getEarliestArrivalTime(node.getID(), adjNode.getID(), routeIds, dateCodes, Math.round(fromTime + node.getDistance()), toTime);
-				while (rs.next()) {
-					final long departureTime = rs.getLong("TIME_D");
-					final long arrivalTime = rs.getLong("TIME_A");
-					final short routeId = rs.getShort("ROUTE_ID");
-					adjNode.setArrivalTime(routeId, arrivalTime);
-					node.setDepartureTime(routeId, departureTime);
-					final double distance = arrivalTime > 0 ? arrivalTime - fromTime : Double.POSITIVE_INFINITY;
-					if (distance < minDistance) {
-						minDistance = distance;
-						adjNode.setCheapestReachedRouteId(routeId);
-					}
-				}
-			}
-		} catch (final SQLException e) {
-			e.printStackTrace();
-		} finally {
-			DbUtils.closeQuietly(rs);
-		}
-
-		return minDistance;
-	}
-
-	/**
-	 * Adds a node to the network.
-	 *
-	 * @param nodeId The nodeId of the node that should be added
-	 * @param nrAdjLinks The number of links adjacent to the node
-	 * @param nodes The nodes HashMap to which the node should be added
-	 */
-	private void addNode(final int nodeId, final short nrAdjLinks, final Map<Integer, Node> nodes) {
-		if (nodes == null) {
-			return; // Just for safety
-		}
-
-		final Node node = nodes.get(nodeId);
-		if (node == null) {
-			nodes.put(nodeId, new Node(nodeId, nrAdjLinks));
-		} else if (node.getNrAdjacentLinks() == -1) {
-			node.setNrAdjacentLinks(nrAdjLinks);
-		}
-	}
-
-	/**
-	 * Adds a node to the network.
-	 *
-	 * @param nodeId The nodeId of the node that should be added
-	 * @param nodes The HashMap to which the node should be added
-	 */
-	private void addNode(final int nodeId, final Map<Integer, Node> nodes) {
-		if (nodes != null && !nodes.containsKey(nodeId)) {
-			nodes.put(nodeId, new Node(nodeId));
-		}
-	}
-
-	/**
-	 * Get a single link from the network and and add the source
-	 * node to the nodes table if necessary.
-	 *
-	 * @param linkId The id of the link that should be returned
-	 * @param nodes The nodes table to which the node should be
-	 *              added. Can be null if only the link is needed.
-	 * @return The link with id linkId
-	 */
-	public Link getLink(final int linkId, final Map<Integer, Node> nodes) {
-		Link link = null;
-		PreparedStatement stmt = null;
-		ResultSet rs = null;
-		try {
-			if (mode == Mode.UNIMODAL) {
-				stmt = getPstmt(queryGetContinuousLink);
-			} else {
-				stmt = getPstmt(queryGetLink);
-			}
-
 			stmt.setInt(1, linkId);
 			rs = stmt.executeQuery();
 			if (rs.next()) {
@@ -447,12 +411,13 @@ public class Database<T extends ConfigDataset> {
 				final int targetId = rs.getInt("TARGET");
 				final short degree = rs.getShort("NODE_DEGREE");
 				final double length = rs.getDouble("LENGTH");
-				link = new Link(linkId, sourceId, targetId, length);
 				if (isIncoming) {
 					addNode(sourceId, degree, nodes);
 				} else {
 					addNode(targetId, degree, nodes);
 				}
+
+				link = new Link(linkId, sourceId, targetId, length);
 			}
 		} catch (final SQLException e) {
 			e.printStackTrace();
@@ -466,21 +431,15 @@ public class Database<T extends ConfigDataset> {
 	/**
 	 * Gets a node from the database.
 	 *
-	 * @param nodeId The id of the node that should be read from
-	 *                the database.
+	 * @param nodeId the id of the node that should be read from the database
 	 * @return the node from the database
 	 */
 	public Node getNode(final int nodeId) {
+		final PreparedStatement stmt = getPstmt((mode == Mode.UNIMODAL) ? queryGetContinuousNode : queryGetMrneXNode);
+
 		Node node = null;
 		ResultSet rs = null;
 		try {
-			PreparedStatement stmt;
-			if (mode == Mode.UNIMODAL) {
-				stmt = getPstmt(queryGetContinuousNode);
-			} else {
-				stmt = getPstmt(queryGetMrneXNode);
-			}
-
 			stmt.setInt(1, nodeId);
 			rs = stmt.executeQuery();
 			if (rs.next()) {
@@ -499,163 +458,160 @@ public class Database<T extends ConfigDataset> {
 	}
 
 	/**
-	 * Gets all links adjacent to a given node.
+	 * Returns the maximal range for the given vertex with a maximal number of specified vertices.
+	 * The database query used finds the last two tuples having a memory size smaller than the specified memorySize and then interpolates the range.
 	 *
-	 * @param nodeId The node to which the links should be
-	 *                adjacent.
-	 * @param nodes The nodes HashMap to which eventual new nodes
-	 *               should be added.
-	 * @return a list of links adjacent to the given nodeid
+	 * @param nodeId the vertex identifier
+	 * @param memorySize the maximal number of vertices
+	 * @return the available range as the euclidean distance
 	 */
-	public Collection<Link> getAdjLinks(final int nodeId, final Map<Integer, Node> nodes) {
-		final Collection<Link> adjLinks = new ArrayList<Link>();
+	public double getRange(final int nodeId, final int memorySize) {
+		final PreparedStatement stmt = getPstmt(queryGetRange);
+
 		ResultSet rs = null;
-		PreparedStatement stmt = null;
 		try {
-			if (mode == Mode.UNIMODAL) {
-				stmt = getPstmt(queryGetAdjContinuousLinks);
-			} else {
-				stmt = getPstmt(queryGetAdjLinks);
-			}
+			// CHECKSTYLE:OFF MagicNumber
 			stmt.setInt(1, nodeId);
+			stmt.setInt(2, memorySize);
+			stmt.setInt(3, nodeId);
+			stmt.setInt(4, memorySize);
+			// CHECKSTYLE:ON MagicNumber
 			rs = stmt.executeQuery();
-			while (rs.next()) {
-				Link link;
-				final int linkId = rs.getInt("ID");
-				final byte linkType = rs.getByte("EDGE_MODE");
-				final int adjNodeId = rs.getInt("NODE_ID");
-				final short degree = rs.getShort("NODE_DEGREE");
-				final double length = rs.getDouble("LENGTH");
-				final short routeId = rs.getShort("ROUTE_ID");
-				int start, end;
-				if (isIncoming) {
-					start = adjNodeId;
-					end = nodeId;
-				} else {
-					start = nodeId;
-					end = adjNodeId;
-				}
-
-				if (linkType == NW_MODE_CONTINUOUS) {
-					link = new Link(linkId, start, end, length);
-				} else {
-					link = new Link(linkId, start, end, routeId);
-				}
-				addNode(adjNodeId, degree, nodes);
-				adjLinks.add(link);
+			int s0 = 0, s1 = 0;
+			double ed0 = 0, ed1 = 0;
+			if (rs.next()) {
+				s0 = rs.getInt("s0");
+				ed0 = rs.getDouble("ed0");
+				s1 = rs.getInt("s1");
+				ed1 = rs.getDouble("ed1");
 			}
+			return ed0 + (ed1 - ed0) / (s1 - s0) * (memorySize - s0);
 		} catch (final SQLException e) {
 			e.printStackTrace();
 		} finally {
 			DbUtils.closeQuietly(rs);
 		}
 
-		return adjLinks;
+		return 0;
 	}
 
 	/**
-	 * Gets date codes for a given time.
-	 *
-	 * @param time the given
-	 * @return returns a set of date codes
+	 * Loads the links in a circle from the database (for better explanation see the MrneX algorithm).
 	 */
-	public Set<Integer> getDateCodes(final Calendar time) {
-		final Set<Integer> codes = new HashSet<Integer>();
-		final PreparedStatement stmt = getPstmt(queryGetDateCodes);
+	public void loadLinksFromIER(final Node node, final Collection<Node> intersections, final Map<Integer, Node> nodes, final Map<Integer, List<Link>> adjList) {
+		PreparedStatement stmt = null;
 		ResultSet rs = null;
 
+		final Point g = node.getCoordinates();
+		final String pointString = "POINT( " + g.getX() + " " + g.getY() + ")";
 		try {
-			final Date date = new Date(time.getTimeInMillis());
-			// CHECKSTYLE:OFF MagicNumber
-			stmt.setString(1, getWeekDayMask(time));
-			stmt.setDate(2, date);
-			stmt.setDate(3, date);
-			// CHECKSTYLE:ON MagicNumber
-
+			if (intersections.isEmpty()) {
+				stmt = getPstmt(queryLoadLinksFromIER);
+				// CHECKSTYLE:OFF MagicNumber
+				stmt.setString(1, pointString);
+				stmt.setInt(2, config.getServerSRID());
+				stmt.setDouble(3, node.getRadius());
+				// CHECKSTYLE:ON MagicNumber
+			} else {
+				final Node[] loadedAreas = intersections.toArray(new Node[0]);
+				final String disjunctAreaString = "st_difference(st_buffer(st_pointfromtext('" + pointString + "',"
+						+ config.getServerSRID() + ")," + node.getRadius() + ")," + subQuery(loadedAreas, loadedAreas.length - 1, config.getServerSRID()) + ")";
+				stmt = getPstmt(String.format(queryGetLinksInRange, disjunctAreaString));
+			}
 			rs = stmt.executeQuery();
+
 			while (rs.next()) {
-				codes.add(rs.getInt("SERVICE_ID"));
+				final int linkId = rs.getInt("ID");
+				final int sourceId = rs.getInt("SOURCE");
+				final short degree = rs.getShort("DEGREE");
+				final int targetId = rs.getInt("TARGET");
+				final byte edgeMode = rs.getByte("EDGE_MODE");
+				Link l = null;
+				if (edgeMode == NW_MODE_CONTINUOUS) {
+					final double length = rs.getDouble("LENGTH");
+					l = new Link(linkId, sourceId, targetId, length);
+				} else {
+					final short routeId = rs.getShort("ROUTE_ID");
+					l = new Link(linkId, sourceId, targetId, routeId);
+				}
+				addLink(l, degree, nodes, adjList);
 			}
 		} catch (final SQLException e) {
+			System.err.println("Problems with node:" + node);
 			e.printStackTrace();
 		} finally {
 			DbUtils.closeQuietly(rs);
 		}
-
-		return codes;
 	}
 
 	/**
-	 * Transforms the day into something machine-readable.
+	 * Reads the whole network for the MDijkstra Algorithm.
+	 * The given maps have to be initialized and will be filled up with
+	 * the nodes and links in the network.
 	 *
-	 * @param time the calendar object to get the machine-readable week day from
-	 * @return the machine-readable string (binary form)
+	 * @param nodes A map in which all the nodes should be stored.
+	 * @param links A map in which all the links should be stored.
 	 */
-	private String getWeekDayMask(final Calendar time) {
-		switch (time.get(Calendar.DAY_OF_WEEK)) {
-		case Calendar.MONDAY:
-			return "1000000";
-		case Calendar.TUESDAY:
-			return "0100000";
-		case Calendar.WEDNESDAY:
-			return "0010000";
-		case Calendar.THURSDAY:
-			return "0001000";
-		case Calendar.FRIDAY:
-			return "0000100";
-		case Calendar.SATURDAY:
-			return "0000010";
-		case Calendar.SUNDAY:
-			return "0000001";
-		default:
-			return "1000000";
-		}
-	}
+	public void readNetwork(final Map<Integer, Node> nodes, final Map<Integer, Link> links) {
+		final PreparedStatement stmt = getPstmt((mode == Mode.UNIMODAL) ? queryGetContinuousEdges : queryGetAllEdges);
 
-	/**
-	 * Gets the coordinates of a node.
-	 *
-	 * @param nodeId The nodeId of the node for which we should
-	 *                find the coordinates.
-	 * @return a point with the coordinates of the node
-	 */
-	public Point getCoordinates(final int nodeId) {
-		Point gp = null;
 		ResultSet rs = null;
 		try {
-			final PreparedStatement stmt = getPstmt(queryGetCoordinatesFromNode);
-			stmt.setInt(1, nodeId);
 			rs = stmt.executeQuery();
-			if (rs.next()) {
-				gp = new Point(rs.getDouble("X"), rs.getDouble("Y"));
+			while (rs.next()) {
+				final int linkId = rs.getInt("ID");
+				final int startNodeId = rs.getInt("SOURCE");
+				final int endNodeId = rs.getInt("TARGET");
+				final double length = rs.getDouble("LENGTH");
+				final short routeId = rs.getShort("ROUTE_ID");
+				final byte linkType = rs.getByte("EDGE_MODE");
+
+				int start, end;
+				if (isIncoming) {
+					start = startNodeId;
+					end = endNodeId;
+				} else {
+					start = endNodeId;
+					end = startNodeId;
+				}
+				Node node;
+				if (!nodes.containsKey(end)) {
+					node = new Node(end);
+					nodes.put(end, node);
+				} else {
+					node = nodes.get(end);
+				}
+				if (node.getAdjLinks() == null) {
+					node.setAdjLinks(new ArrayList<Link>());
+				}
+				Link link;
+
+				if (linkType == NW_MODE_CONTINUOUS) {
+					link = new Link(linkId, startNodeId, endNodeId, length);
+				} else {
+					link = new Link(linkId, startNodeId, endNodeId, routeId);
+				}
+				node.addAdjLink(link);
+				links.put(linkId, link);
+				if (!nodes.containsKey(start)) {
+					nodes.put(start, new Node(start));
+				}
 			}
 		} catch (final SQLException e) {
-			e.printStackTrace();
+			throw new RuntimeException("Error reading the Network: " + e);
 		} finally {
 			DbUtils.closeQuietly(rs);
 		}
-
-		return gp;
-	}
-
-	/**
-	 * Close all the open prepared statements and the database
-	 * connection. Call this method once you're done with the
-	 * database.
-	 */
-	public void close() {
-		for (final PreparedStatement pstmt : pstmtsCacheMap.values()) {
-			DbUtils.closeQuietly(pstmt);
-		}
 	}
 
 	/**
-	 * If close() is not called, make sure the database connections
+	 * If {@link #close()} is not called, make sure the database connections
 	 * are still closed.  This method is just a security guard and
 	 * should not be relied on and is not an excuse for a lazy
 	 * programmer not to call the close method.
 	 * This method is not guaranteed to be called!!
 	 *
+	 * @see #close()
 	 * @throws Throwable the {@code Exception} raised by this method
 	 */
 	@Override
@@ -664,121 +620,163 @@ public class Database<T extends ConfigDataset> {
 		close();
 	}
 
+	// Protected methods
+
 	/**
-	 * Method getRange returns the maximal range for the given
-	 * vertex with a maximal number of specified vertices. Query
-	 * find the last two tuples having a memory size smaller than
-	 * memorySize and then interpolates the range.
+	 * Gets a prepared statement and caches it in a map. This
+	 * is much more efficient than creating a new prepared statement
+	 * each time a query needs to be called, and recalculating the
+	 * queryplan each time.
 	 *
-	 * @param nodeId the vertex identifier
-	 * @param memorySize the maximal number of vertices
-	 * @return the available range as the euclidean distance
+	 * @param query The prepared statement that is needed
+	 * @return the cached prepared statement object
 	 */
-	public double getRange(final int nodeId, final int memorySize) {
-		ResultSet rs = null;
+	// FIXME: Find a fix for prepared statements with parameters
+	// (we should NOT set strings in preparedStatemens just because we want to cache something)
+	protected PreparedStatement getPstmt(final String query) {
 		try {
-			final PreparedStatement stmt = getPstmt(queryGetRange);
-			// CHECKSTYLE:OFF MagicNumber
-			stmt.setInt(1, nodeId);
-			stmt.setInt(2, memorySize);
-			stmt.setInt(3, nodeId);
-			stmt.setInt(4, memorySize);
-			// CHECKSTYLE:ON MagicNumber
-			rs = stmt.executeQuery();
-			int s0 = 0, s1 = 0;
-			double ed0 = 0, ed1 = 0;
-			if (rs.next()) {
-				s0 = rs.getInt("s0");
-				ed0 = rs.getDouble("ed0");
-				s1 = rs.getInt("s1");
-				ed1 = rs.getDouble("ed1");
+			if (pstmtsCacheMap.containsKey(query) && !pstmtsCacheMap.get(query).isClosed()) {
+				return pstmtsCacheMap.get(query);
 			}
-			return ed0 + (ed1 - ed0) / (s1 - s0) * (memorySize - s0);
+
+			final PreparedStatement pstmt = connection.prepareStatement(query);
+			pstmtsCacheMap.put(query, pstmt);
+			return pstmt;
 		} catch (final SQLException e) {
 			e.printStackTrace();
-		} finally {
-			DbUtils.closeQuietly(rs);
 		}
 
-		return 0;
+		return null;
 	}
 
-	public void addLink(final Link link, final short degree, final Map<Integer, Node> nodes, final Map<Integer, List<Link>> adjList) {
-		int n1, n2;
+	// Private methods
+
+	private Link createLinkFromResultSet(final int nodeId, final int adjNodeId, final ResultSet rs) throws SQLException {
+		int start, end;
 		if (isIncoming) {
-			n1 = link.getStartNode();
-			n2 = link.getEndNode();
+			start = adjNodeId;
+			end = nodeId;
 		} else {
-			n1 = link.getEndNode();
-			n2 = link.getStartNode();
+			start = nodeId;
+			end = adjNodeId;
 		}
 
-		addNode(n1, degree, nodes);
-		addNode(n2, nodes);
-		if (!adjList.containsKey(n2)) {
-			adjList.put(n2, new ArrayList<Link>());
+		final int linkId = rs.getInt("ID");
+		if (rs.getByte("EDGE_MODE") == NW_MODE_CONTINUOUS) {
+			final double length = rs.getDouble("LENGTH");
+			return new Link(linkId, start, end, length);
 		}
 
-		adjList.get(n2).add(link);
+		final short routeId = rs.getShort("ROUTE_ID");
+		return new Link(linkId, start, end, routeId);
 	}
 
-	private String subQuery(final Node[] loaded, final int idx, final int srid) {
-		if (idx == 0) {
-			return "st_buffer(st_pointfromtext('POINT(" + loaded[idx].getCoordinates().getX() + " "
-					+ loaded[idx].getCoordinates().getY() + ")'," + srid + ")," + loaded[idx].getRadius() + ")";
-		} else {
-			return "st_union(" + "st_buffer(st_pointfromtext('POINT(" + loaded[idx].getCoordinates().getX() + " "
-					+ loaded[idx].getCoordinates().getY() + ")'," + srid + ")," + loaded[idx].getRadius() + "),"
-					+ subQuery(loaded, idx - 1, srid) + ")";
+	// Private static methods
+
+	/**
+	 * Prepares a number of place holders for a prepared statement.
+	 *
+	 * @param length The number of placeholders that is needed
+	 * @return a string with the placeholders plugged in to a statement.
+	 */
+	private static String preparePlaceHolders(final int length) {
+		final StringBuilder builder = new StringBuilder();
+		for (int i = 0; i < length; ++i) {
+			builder.append("?");
+			if ((i + 1) < length) {
+				builder.append(",");
+			}
 		}
+
+		return builder.toString();
 	}
 
 	/**
-	 * Loads the links in a circle from the database (for better explanation see the MrneX algorithm).
+	 * Sets the values in the placeholders in a prepared statement, generated by
+	 * the {@link #preparePlaceHolders(int)} method.
+	 *
+	 * @see #preparePlaceHolders(int)
+	 * @param startIdx the start index where the first object should be placed in the prepared statement
+	 * @param preparedStatement the prepared statement in which the values should be inserted.
+	 * @param values the values that should be inserted into the prepared statement
+	 * @throws SQLException thrown if a parameter could not be set into the prepared statement
+	 * @return the index of the first position that was being left unfilled by the method
 	 */
-	public void loadLinksFromIER(final Node node, final Collection<Node> intersections, final Map<Integer, Node> nodes, final Map<Integer, List<Link>> adjList) {
-		ResultSet rs = null;
+	protected static final int setValues(final int startIdx, final PreparedStatement preparedStatement, final Object... values) throws SQLException {
+		for (int i = 0; i < values.length; ++i) {
+			preparedStatement.setObject(startIdx + i, values[i]);
+		}
 
-		final Point g = node.getCoordinates();
-		final String pointString = "POINT( " + g.getX() + " " + g.getY() + ")";
-		try {
-			PreparedStatement stmt = null;
-			if (intersections.isEmpty()) {
-				stmt = getPstmt(queryLoadLinksFromIER);
-				// CHECKSTYLE:OFF MagicNumber
-				stmt.setString(1, pointString);
-				stmt.setInt(2, config.getServerSRID());
-				stmt.setDouble(3, node.getRadius());
-				// CHECKSTYLE:ON MagicNumber
-			} else {
-				final Node[] loadedAreas = intersections.toArray(new Node[0]);
-				final String disjunctAreaString = "st_difference(st_buffer(st_pointfromtext('" + pointString + "',"
-						+ config.getServerSRID() + ")," + node.getRadius() + ")," + subQuery(loadedAreas, loadedAreas.length - 1, config.getServerSRID()) + ")";
-				stmt = getPstmt(String.format(queryGetLinksInRange, disjunctAreaString));
-			}
-			rs = stmt.executeQuery();
+		return startIdx + values.length;
+	}
 
-			while (rs.next()) {
-				final int linkId = rs.getInt("ID");
-				final int sourceId = rs.getInt("SOURCE");
-				final short degree = rs.getShort("DEGREE");
-				final int targetId = rs.getInt("TARGET");
-				final byte edgeMode = rs.getByte("EDGE_MODE");
-				Link l = null;
-				if (edgeMode == NW_MODE_CONTINUOUS) {
-					final double length = rs.getDouble("LENGTH");
-					l = new Link(linkId, sourceId, targetId, length);
-				} else {
-					final short routeId = rs.getShort("ROUTE_ID");
-					l = new Link(linkId, sourceId, targetId, routeId);
-				}
-				addLink(l, degree, nodes, adjList);
-			}
-		} catch (final SQLException e) {
-			System.err.println("Problems with node:" + node);
-			e.printStackTrace();
-		} finally {
-			DbUtils.closeQuietly(rs);
+	/**
+	 * Adds a node to the network.
+	 *
+	 * @param nodeId The nodeId of the node that should be added
+	 * @param nodes The HashMap to which the node should be added
+	 */
+	private static void addNode(final int nodeId, final Map<Integer, Node> nodes) {
+		if (nodes != null && !nodes.containsKey(nodeId)) {
+			nodes.put(nodeId, new Node(nodeId));
+		}
+	}
+
+	/**
+	 * Adds a node to the network.
+	 *
+	 * @param nodeId The nodeId of the node that should be added
+	 * @param nrAdjLinks The number of links adjacent to the node
+	 * @param nodes The nodes HashMap to which the node should be added
+	 */
+	private static void addNode(final int nodeId, final short nrAdjLinks, final Map<Integer, Node> nodes) {
+		if (nodes == null) {
+			return; // Just for safety
+		}
+
+		final Node node = nodes.get(nodeId);
+		if (node == null) {
+			nodes.put(nodeId, new Node(nodeId, nrAdjLinks));
+		} else if (node.getNrAdjacentLinks() == -1) {
+			node.setNrAdjacentLinks(nrAdjLinks);
+		}
+	}
+
+	/**
+	 * Transforms the day into something machine-readable.
+	 *
+	 * @param time the calendar object to get the machine-readable week day from
+	 * @return the machine-readable string (binary form)
+	 */
+	private static String getWeekDayMask(final Calendar time) {
+		switch (time.get(Calendar.DAY_OF_WEEK)) {
+		case Calendar.MONDAY:
+			return "1000000";
+		case Calendar.TUESDAY:
+			return "0100000";
+		case Calendar.WEDNESDAY:
+			return "0010000";
+		case Calendar.THURSDAY:
+			return "0001000";
+		case Calendar.FRIDAY:
+			return "0000100";
+		case Calendar.SATURDAY:
+			return "0000010";
+		case Calendar.SUNDAY:
+			return "0000001";
+		default:
+			return "1000000";
+		}
+	}
+
+	private static String subQuery(final Node[] loaded, final int idx, final int srid) {
+		if (idx == 0) {
+			return "st_buffer(st_pointfromtext('POINT(" + loaded[idx].getCoordinates().getX() + " "
+					+ loaded[idx].getCoordinates().getY() + ")'," + srid + ")," + loaded[idx].getRadius() + ")";
+		} else {
+			return "st_union(" + "st_buffer(st_pointfromtext('POINT(" + loaded[idx].getCoordinates().getX() + " "
+					+ loaded[idx].getCoordinates().getY() + ")'," + srid + ")," + loaded[idx].getRadius() + "),"
+					+ subQuery(loaded, idx - 1, srid) + ")";
 		}
 	}
 }
diff --git a/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java b/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java
index fecf7bd7..426e2431 100644
--- a/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java
+++ b/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java
@@ -49,12 +49,14 @@ public class DatabaseWeb extends Database<ConfigClient> {
 	private final String queryInsertVertexAnnotation;
 	private final String queryUpdateVertices;
 
+	// Constructor
+
 	public DatabaseWeb(final ConfigClient config, final Mode mode, final Direction direction) {
 		super(config, mode, direction);
 
-		final String cfgEdges = config.getTableEdges();
-		final String cfgRoutes = config.getTableRoutes();
-		final String cfgVertex = config.getTableVertex();
+		final String configEdges = config.getTableEdges();
+		final String configRoutes = config.getTableRoutes();
+		final String configVertex = config.getTableVertex();
 		final String edgeTableName = config.getEdgeTableEntry().getTableName();
 		final String vertexTableName = config.getVertexTableEntry().getTableName();
 		final String vertexAnnotationTableName = config.getVertexAnnotatedTableEntry().getTableName();
@@ -65,41 +67,33 @@ public class DatabaseWeb extends Database<ConfigClient> {
 
 		queryStoreLinks = "INSERT INTO " + edgeTableName
 				+ " (\"ID\",\"SOURCE\",\"TARGET\",\"OFFSET\",\"LENGTH\",\"GEOMETRY\") (SELECT ID, SOURCE, TARGET, ?, LENGTH,"
-				+ " GEOMETRY FROM " + cfgEdges + " WHERE ID=?)";
+				+ " GEOMETRY FROM " + configEdges + " WHERE ID=?)";
 
 		queryStorePartialLinks = "INSERT INTO " + edgeTableName
 				+ " (\"ID\",\"SOURCE\",\"TARGET\",\"OFFSET\",\"LENGTH\",\"GEOMETRY\") (SELECT ID,SOURCE,TARGET,?,LENGTH,"
-				+ " ST_LINE_SUBSTRING(GEOMETRY,?,?) FROM " + cfgEdges + " WHERE ID = ?)";
+				+ " ST_LINE_SUBSTRING(GEOMETRY,?,?) FROM " + configEdges + " WHERE ID = ?)";
 
 		queryInsertVertex = "INSERT INTO " + vertexTableName
-				+ " (\"ID\",\"DISTANCE\",\"ROUTE_ID\",\"STATE\",\"GEOMETRY\") (SELECT ?,?,?,?,GEOMETRY FROM " + cfgVertex
+				+ " (\"ID\",\"DISTANCE\",\"ROUTE_ID\",\"STATE\",\"GEOMETRY\") (SELECT ?,?,?,?,GEOMETRY FROM " + configVertex
 				+ " WHERE ID=?)";
 
 		queryInsertVertexAnnotation = "INSERT INTO " + vertexAnnotationTableName
 				+ " (\"ID\", \"ROUTE_ID\",\"TIME_A\",\"TIME_D\") VALUES (?,?,?,?)";
 
 		queryUpdateVertices = "UPDATE " + vertexTableName
-				+ " SET \"T_TYPE\"=R.ROUTE_TYPE FROM " + cfgRoutes + " R WHERE R.ROUTE_ID = "
+				+ " SET \"T_TYPE\"=R.ROUTE_TYPE FROM " + configRoutes + " R WHERE R.ROUTE_ID = "
 				+ vertexTableName + ".\"ROUTE_ID\" AND " + vertexTableName + ".\"ROUTE_ID\">=0";
 	}
 
-	public Point transform(final Point p) {
-		final String query = "SELECT ST_X(P.GEO) X, ST_Y(P.GEO) Y FROM (SELECT ST_Transform(ST_PointFromText(?,?),?) GEO ) P";
-		return DatabaseWeb.transform(config, p, getPstmt(query));
-	}
-
-	public Connection getConnection() {
-		return connection;
-	}
+	// Public methods
 
 	public void createBuffer(final String bufferTable, final String edgeTable, final double bufferSize) {
-		final String query = "INSERT INTO " + bufferTable + " "
-				+ "SELECT 1,ST_Multi(ST_UNION(ST_BUFFER(\"GEOMETRY\", "
-				+ bufferSize + "))) \"GEOMETRY\" FROM " + edgeTable;
+		final StringBuilder b = new StringBuilder("INSERT INTO ").append(bufferTable);
+		b.append(" SELECT 1,ST_Multi(ST_UNION(ST_BUFFER(\"GEOMETRY\", ").append(bufferSize).append("))) \"GEOMETRY\" FROM ").append(edgeTable);
 
 		PreparedStatement statement = null;
 		try {
-			statement = getPstmt(query);
+			statement = getPstmt(b.toString());
 			statement.executeUpdate();
 			connection.commit();
 		} catch (final SQLException e) {
@@ -114,6 +108,36 @@ public class DatabaseWeb extends Database<ConfigClient> {
 		}
 	}
 
+	public List<Integer> edgesInArea(final int areaId) {
+		final List<Integer> edges = new ArrayList<Integer>();
+		final StringBuilder b = new StringBuilder("SELECT L.\"ID\" FROM ");
+		b.append(config.getEdgeTableEntry().getTableName()).append(" L, ");
+		b.append(config.getAreaBufferTableEntry().getTableName()).append(" A ");
+		b.append("WHERE A.\"ID\"=? AND ST_Within(L.\"GEOMETRY\",A.\"GEOMETRY\")=TRUE");
+
+		PreparedStatement statement = null;
+		ResultSet rs = null;
+		try {
+			statement = getPstmt(b.toString());
+			statement.setInt(1, areaId);
+			rs = statement.executeQuery();
+			while (rs.next()) {
+				edges.add(rs.getInt(1));
+			}
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		} finally {
+			DbUtils.closeQuietly(rs);
+			DbUtils.closeQuietly(statement);
+		}
+
+		return edges;
+	}
+
+	public Connection getConnection() {
+		return connection;
+	}
+
 	@SuppressFBWarnings(
 		value = "DLS_DEAD_LOCAL_STORE",
 		justification = "False positiv in DLS_DEAD_LOCAL_STORE check"
@@ -179,58 +203,64 @@ public class DatabaseWeb extends Database<ConfigClient> {
 		return isoEdges;
 	}
 
-	public void storeArea(final int areaId, final List<Point> points, final double bufferSize) {
-		final Geometry geometry = PgHelper.asPgGeometry(points);
-		final String geometryString = geometry.getTypeString() + geometry.getValue();
+	public Set<Location> projectOnLinks(final QueryNode qNode) {
+		Set<Location> locations = QueryNodeCache.getCachedQueryPoint(qNode);
+		if (locations != null) {
+			return locations;
+		}
 
-		final StringBuilder b = new StringBuilder();
-		b.append("INSERT INTO ").append(config.getAreaBufferTableEntry().getTableName());
-		b.append("(\"ID\",\"GEOMETRY\") VALUES(?,ST_MULTI(ST_Buffer(ST_MakeValid(ST_GeomFromText(?," + config.getServerSRID() + ")),?,'endcap=round join=round')))");
-		PreparedStatement statement = null;
+		final int clientSRID = ConfigIsochrone.getInstance().getClientSRID();
+		final String point = "POINT(" + qNode.getX() + " " + qNode.getY() + ")";
+		final StringBuilder sb = new StringBuilder();
+		sb.append("SELECT L.ID, ST_Line_Locate_Point(L.EDGE_GEO,L.POINT_GEO)*L.LENGTH AS OFFSET ");
+		sb.append("FROM (SELECT E.ID, E.GEOMETRY EDGE_GEO, E.LENGTH, P.GEOMETRY POINT_GEO FROM ");
+		sb.append(config.getTableEdges()).append(" E, ");
+		sb.append(" (SELECT ");
+		if (clientSRID == config.getServerSRID()) {
+			sb.append("ST_PointFromText(?,?) ");
+		} else {
+			sb.append("ST_Transform(ST_PointFromText(?,?),?)");
+		}
+		sb.append(" GEOMETRY) P");
+		sb.append(" WHERE E.EDGE_MODE=").append(NW_MODE_CONTINUOUS).append(" AND st_dwithin(E.GEOMETRY,P.GEOMETRY, ?)"); // tolerance
+		sb.append(" ORDER BY st_distance(E.GEOMETRY,P.GEOMETRY) LIMIT 2) L");
+
+		PreparedStatement statement	 = null;
+		ResultSet rSet = null;
 		try {
-			statement = getPstmt(b.toString());
+			statement = getPstmt(sb.toString());
+			statement.setString(1, point);
+			statement.setInt(2, clientSRID);
+
 			// CHECKSTYLE:OFF MagicNumber
-			statement.setInt(1, areaId);
-			statement.setString(2, geometryString);
-			statement.setDouble(3, bufferSize);
+			final int tolerance = config.getDistanceTolerance();
+			if (clientSRID != config.getServerSRID()) {
+				statement.setInt(3, config.getServerSRID());
+				statement.setInt(4, tolerance);
+			} else {
+				statement.setInt(3, tolerance);
+			}
 			// CHECKSTYLE:ON MagicNumber
-			statement.executeUpdate();
-			connection.commit();
-		} catch (final SQLException e) {
-			e.printStackTrace();
-		} finally {
-			DbUtils.closeQuietly(statement);
-		}
-	}
-
-	public List<Integer> edgesInArea(final int areaId) {
-		final List<Integer> edges = new ArrayList<Integer>();
-		final StringBuilder b1 = new StringBuilder();
-		b1.append("SELECT L.\"ID\" FROM ");
-		b1.append(config.getEdgeTableEntry().getTableName()).append(" L, ");
-		b1.append(config.getAreaBufferTableEntry().getTableName()).append(" A ");
-		b1.append("WHERE A.\"ID\"=? AND ST_Within(L.\"GEOMETRY\",A.\"GEOMETRY\")=TRUE");
 
-		PreparedStatement statement = null;
-		ResultSet rs = null;
-		try {
-			statement = getPstmt(b1.toString());
-			statement.setInt(1, areaId);
-			rs = statement.executeQuery();
-			while (rs.next()) {
-				edges.add(rs.getInt(1));
+			rSet = statement.executeQuery();
+			locations = new HashSet<Location>();
+			while (rSet.next()) {
+				final int link = rSet.getInt("ID");
+				final double offset = rSet.getDouble("OFFSET");
+				locations.add(new Location(link, offset));
 			}
+			QueryNodeCache.addQueryNode(qNode, locations);
 		} catch (final SQLException e) {
 			e.printStackTrace();
 		} finally {
-			DbUtils.closeQuietly(rs);
+			DbUtils.closeQuietly(rSet);
 			DbUtils.closeQuietly(statement);
 		}
 
-		return edges;
+		return locations;
 	}
 
-/*
+	/*
 	public int reachedInhabitants() {
 		int reachedInhabitants = 0;
 		final StringBuilder b = new StringBuilder();
@@ -278,7 +308,32 @@ public class DatabaseWeb extends Database<ConfigClient> {
 
 		return totalInhabitants;
 	}
-*/
+	*/
+
+	public void storeArea(final int areaId, final List<Point> points, final double bufferSize) {
+		final Geometry geometry = PgHelper.asPgGeometry(points);
+		final String geometryString = geometry.getTypeString() + geometry.getValue();
+
+		final StringBuilder b = new StringBuilder();
+		b.append("INSERT INTO ").append(config.getAreaBufferTableEntry().getTableName());
+		b.append("(\"ID\",\"GEOMETRY\") VALUES(?,ST_MULTI(ST_Buffer(ST_MakeValid(ST_GeomFromText(?," + config.getServerSRID() + ")),?,'endcap=round join=round')))");
+		PreparedStatement statement = null;
+		try {
+			statement = getPstmt(b.toString());
+			// CHECKSTYLE:OFF MagicNumber
+			statement.setInt(1, areaId);
+			statement.setString(2, geometryString);
+			statement.setDouble(3, bufferSize);
+			// CHECKSTYLE:ON MagicNumber
+			statement.executeUpdate();
+			connection.commit();
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		} finally {
+			DbUtils.closeQuietly(statement);
+		}
+	}
+
 	public final void storeLinks(final Collection<Link> links, final Direction direction) {
 		final boolean isIncoming = direction == Direction.INCOMING;
 		PreparedStatement statementPartial = null;
@@ -330,63 +385,6 @@ public class DatabaseWeb extends Database<ConfigClient> {
 		}
 	}
 
-	public Set<Location> projectOnLinks(final QueryNode qNode) {
-		Set<Location> locations = QueryNodeCache.getCachedQueryPoint(qNode);
-		if (locations != null) {
-			return locations;
-		}
-
-		final int clientSRID = ConfigIsochrone.getInstance().getClientSRID();
-		final String point = "POINT(" + qNode.getX() + " " + qNode.getY() + ")";
-		final StringBuilder sb = new StringBuilder();
-		sb.append("SELECT L.ID, ST_Line_Locate_Point(L.EDGE_GEO,L.POINT_GEO)*L.LENGTH AS OFFSET ");
-		sb.append("FROM (SELECT E.ID, E.GEOMETRY EDGE_GEO, E.LENGTH, P.GEOMETRY POINT_GEO FROM ");
-		sb.append(config.getTableEdges()).append(" E, ");
-		sb.append(" (SELECT ");
-		if (clientSRID == config.getServerSRID()) {
-			sb.append("ST_PointFromText(?,?) ");
-		} else {
-			sb.append("ST_Transform(ST_PointFromText(?,?),?)");
-		}
-		sb.append(" GEOMETRY) P");
-		sb.append(" WHERE E.EDGE_MODE=").append(NW_MODE_CONTINUOUS).append(" AND st_dwithin(E.GEOMETRY,P.GEOMETRY, ?)"); // tolerance
-		sb.append(" ORDER BY st_distance(E.GEOMETRY,P.GEOMETRY) LIMIT 2) L");
-
-		PreparedStatement statement	 = null;
-		ResultSet rSet = null;
-		try {
-			statement = getPstmt(sb.toString());
-			statement.setString(1, point);
-			statement.setInt(2, clientSRID);
-
-			// CHECKSTYLE:OFF MagicNumber
-			final int tolerance = config.getDistanceTolerance();
-			if (clientSRID != config.getServerSRID()) {
-				statement.setInt(3, config.getServerSRID());
-				statement.setInt(4, tolerance);
-			} else {
-				statement.setInt(3, tolerance);
-			}
-			// CHECKSTYLE:ON MagicNumber
-
-			rSet = statement.executeQuery();
-			locations = new HashSet<Location>();
-			while (rSet.next()) {
-				final int link = rSet.getInt("ID");
-				final double offset = rSet.getDouble("OFFSET");
-				locations.add(new Location(link, offset));
-			}
-			QueryNodeCache.addQueryNode(qNode, locations);
-		} catch (final SQLException e) {
-			e.printStackTrace();
-		} finally {
-			DbUtils.closeQuietly(rSet);
-			DbUtils.closeQuietly(statement);
-		}
-
-		return locations;
-	}
-
 	public void storeVertices(final Set<Node> nodes) {
 		PreparedStatement insertVerticesStatement = null;
 		PreparedStatement insertVertexAnnotationStatement = null;
@@ -425,6 +423,11 @@ public class DatabaseWeb extends Database<ConfigClient> {
 		}
 	}
 
+	public Point transform(final Point p) {
+		final String query = "SELECT ST_X(P.GEO) X, ST_Y(P.GEO) Y FROM (SELECT ST_Transform(ST_PointFromText(?,?),?) GEO ) P";
+		return DatabaseWeb.transform(config, p, getPstmt(query));
+	}
+
 	public void updateVertexTable() {
 		PreparedStatement statement = null;
 		try {
@@ -438,13 +441,14 @@ public class DatabaseWeb extends Database<ConfigClient> {
 		}
 	}
 
-
 	// Public static methods
 
 	public static Point transform(final ConfigDataset config, final Point p) {
 		return transform(config, p, null);
 	}
 
+	// Private static methods
+
 	private static Point transform(final ConfigDataset config, final Point p, final PreparedStatement preparedStatement) {
 		final ConfigIsochrone configIso = ConfigIsochrone.getInstance();
 		final boolean openNewStatement = (preparedStatement == null);
-- 
GitLab