@Override
    public void propagateQueries() {
        Set<Node> currentNodesSetTemp; // stores the new set of current nodes
        // while the "old" set of current nodes are being added to the
        // set of visited nodes
        
        Set<Node> visitedNodesSetTemp; // stores the set of current nodes
        // that become "visited" once they propagate the query to all their
        // neighbours
        
        /* Does the following for each search query. */
        for (int iQuery = 0; iQuery < searchQueriesMap.size(); iQuery++) {
            final Query currentQuery = searchQueriesMap.get(iQuery);
            
            currentNodesSetTemp = new HashSet<Node>();  // uses a temporary
            // set as changing a set while iterating over it can cause
            // problems
            visitedNodesSetTemp = new HashSet<Node>();  // uses a temporary
            // set so that all the neighbours can be marked as visited only 
            // after one time step has passed, instead of incrementally within
            // one time step, which would cause problems
            
            final HashMap<Integer, ArrayList<Integer>> currentNodesPrevHopMapTemp =
                    new HashMap<Integer, ArrayList<Integer>>();
            
            ArrayList<Integer> prevHopArrayListOfNeighbour;
            
            /* Iterates over each node in the set of current nodes. */
            final Iterator<Node> itCurrentNodes =
                    currentQuery.getCurrentNodesSet().iterator();
            Node aCurrentNode;
            
            while (itCurrentNodes.hasNext()) {
                aCurrentNode = itCurrentNodes.next();
                
                final ArrayList<Integer> prevHopArrayListOfCurrentNode =
                        currentQuery.getCurrentNodesPrevHopMap().get(
                                aCurrentNode.getNodeID());
                
                /* 
                 * Checks that the current node has not already propagated 
                 * the query.
                 */
                if (!hasPropagatedQuery.containsKey(aCurrentNode.getNodeID())) {
                    /*
                     * Iterates over the links of the current node to find
                     * all of the node's neighbours.
                     */
                    final Iterator<Link> itLinksSet =
                            aCurrentNode.getLinksSet().iterator();
                    Link aLink;
                    
                    while (itLinksSet.hasNext()) {
                        aLink = itLinksSet.next();
                        final Node aNeighbour = aLink.connectedBy(aCurrentNode);
                        
                        /*
                         * The reason for checking if the query is doing its
                         * first hop is that the source node will not have
                         * any previous hops and thus returns a "null" value
                         * for "prevHopArrayListOfCurrentNode."
                         *
                         * Also checks that the current neighbour has not been
                         * previously visited. This covers both the case where the
                         * neighbour was the node that sent the query during the
                         * previous hop, as well as the case where the neighbour was
                         * visited by the query during any of the other hops. The
                         * latter is the equivalent of marking a node as visited
                         * only once it sends the query and then only having
                         * the neighbour propagate the query once it has verified
                         * that it had not previously received the same query.
                         */
                        if ((currentQuery.isFirstHop()) ||
                                (!prevHopArrayListOfCurrentNode
                                        .contains(aNeighbour.getNodeID()))) {
                            /*
                             * Forwards the query (i.e. the selected neighbour
                             * becomes a current node).
                             */
                            currentNodesSetTemp.add(aNeighbour);
                            
                            /* Adds the current neighbour to the set of visited nodes. */
                            visitedNodesSetTemp.add(aNeighbour);
                            
                            /* Marks the current node as having propagated the query. */
                            hasPropagatedQuery.put(aCurrentNode.getNodeID(), 1);
                            
                            /*
                             * Stores previous hop information.
                             *
                             * As the implementation of "currentNodesPrevHopMap"
                             * differs for each search type, the following search
                             * uses the following:
                             *
                             * The node ID of the current node can be used to
                             * loop up the list of node IDs that make up the last
                             * hop of this current node.
                             *
                             * As a node can receive the same query multiple
                             * times in the same time step, it is possible
                             * there to be multiple "last hops" associated with
                             * a given node.
                             */
                            if (currentNodesPrevHopMapTemp
                                    .containsKey(aNeighbour.getNodeID())) {
                                prevHopArrayListOfNeighbour =
                                        currentNodesPrevHopMapTemp
                                                .get(aNeighbour.getNodeID());
                            }
                            else {
                                prevHopArrayListOfNeighbour =
                                        new ArrayList<Integer>();
                            }
                            
                            prevHopArrayListOfNeighbour.add(aCurrentNode
                                    .getNodeID());
                            currentNodesPrevHopMapTemp.put(aNeighbour
                                    .getNodeID(), prevHopArrayListOfNeighbour);
                            
                            /*
                             * Increments the total number of messages send since the
                             * beginning of the search.
                             */
                            nTotalMessages++;
                        }
                    }
                }
            }
            
            /*
             * Updates the query's structures with the temporary ones created
             * locally.
             */
            currentQuery.setCurrentNodesSet(currentNodesSetTemp);
            currentQuery.getVisitedNodesSet().addAll(visitedNodesSetTemp);
            currentQuery.getCurrentNodesPrevHopMap().putAll(
                    currentNodesPrevHopMapTemp);
            
            /*  Decrements TTL. */
            ttlMap.put(iQuery, ttlMap.get(iQuery) - 1);
            
            /* Updates the query after it has made its first hop. */
            if (currentQuery.isFirstHop()) {
                currentQuery.setFirstHop(false);
            }
        }
        
        /*
         * Increments the number of elapsed time steps since
         * the beginning of the search.
         */
        nTotalTime++;
        
        /* Updates the network panel and information display. */
        searchCoordinator.getNetworkPanel().repaint();
        searchCoordinator.getControlPanel().getInformationNumberOfTimeLabel()
                .setText(Integer.toString(nTotalTime));
        searchCoordinator.getControlPanel()
                .getInformationNumberOfMessagesLabel().setText(
                        Integer.toString(nTotalMessages));
    }