/*
 * File:   AffectedNodes.hpp
 * Author: paddya
 *
 * Created on 17. Dezember 2016, 16:35
 */

#ifndef NETWORKIT_DISTANCE_AFFECTED_NODES_HPP_
#define NETWORKIT_DISTANCE_AFFECTED_NODES_HPP_

#include <networkit/base/Algorithm.hpp>
#include <networkit/dynamics/GraphEvent.hpp>
#include <networkit/graph/Graph.hpp>

namespace NetworKit {

class AffectedNodes : public Algorithm {
public:
    /**
     * Constructs the AffectedNodes class for a given graph @a G and a graph event
     * @a event. The run() method computes the set of affected nodes,
     * their distance to the edge modification and, in the case of an edge insertion,
     * an upper bound for the improvement of the harmonic closeness centrality
     * of each affected node.
     *
     * @param G The graph.
     * @param event The graph event.
     */
    AffectedNodes(const Graph &G, const GraphEvent &event);
    /**
     * Computes the set of affected nodes.
     */
    void run() override;
    /**
     * Returns the set of affected nodes.
     *
     * @return The set of affected nodes
     */
    std::vector<node> getNodes();
    /**
     * Returns the distances to the edge modification for each node.
     *
     * @return The distances to the edge modification for each node
     */
    std::vector<edgeweight> getDistances();
    /**
     * Returns the level-based improvement bounds for each affected node.
     *
     * @return The improvement upper bound for each affected node, indexed by node ID
     */
    std::vector<edgeweight> getImprovements();

    edgeweight closenessU = 0;
    edgeweight closenessV = 0;
    edgeweight improvementU = 0;
    edgeweight improvementV = 0;

private:
    /**
     * Handles an edge insertion.
     */
    void addedEdge();
    /**
     * Handles an edge removal.
     */
    void removedEdge();
    /**
     * Runs a complete BFS from @a source while ignoring the edge between
     * @a source and @a startNeighbor. This is equivalent to running a
     * BFS in G $\\setminus$ (source, startNeighbor).
     *
     * @param source The source node.
     * @param startNeighbor The neighbor node to be ignored on level 1.
     * @return The distances of each node to @a source.
     */
    std::vector<edgeweight> bfsWithoutStartNeighbor(node source, node startNeighbor);

    /**
     * Runs a complete reverse BFS from @a source while ignoring the edge between
     * @a startNeighbor and @a source. This is equivalent to running a
     * BFS in G - (source, startNeighbor).
     *
     * @param source The source node.
     * @param startNeighbor The neighbor node to be ignored on level 1.
     * @return The distances of each node to @a source.
     */
    std::vector<edgeweight> reverseBfsWithoutStartNeighbor(node source, node startNeighbor);

    /**
     * Runs a BFS from @a source while optionally including an edge between
     * @a source and @a additionalStartNeighbor. This is equivalent to running
     * a BFS from @a source in  G + (source, additionalStartNeighbor).
     *
     * The algorithm prunes a subtree if it encounters a node @a w for which
     * the new distance is not smaller than the distance in @a distances.
     *
     * @param source The source node.
     * @param distances The distances without the additional edge.
     * @param additionalStartNeighbor The additional start neighbor.
     * @return The distances of each node to @a source.
     */
    std::pair<std::vector<node>, std::vector<edgeweight>>
    getAffectedNodes(node source, std::vector<edgeweight> &distances,
                     node additionalStartNeighbor = none);

    /**
     * Runs a reverse BFS from @a source while optionally including an edge between
     * @a additionalStartNeighbor and @a source. This is equivalent to running
     * a BFS from @a source in  G + (source, additionalStartNeighbor).
     *
     * The algorithm prunes a subtree if it encounters a node @a w for which
     * the new distance is not smaller than the distance in @a distances.
     *
     * @param source The source node.
     * @param distances The distances without the additional edge.
     * @param additionalStartNeighbor The additional start neighbor.
     * @return The distances of each node to @a source.
     */
    std::pair<std::vector<node>, std::vector<edgeweight>>
    getAffectedNodesBackwards(node source, std::vector<edgeweight> &distances,
                              node additionalStartNeighbor = none);
    const Graph &G;
    const GraphEvent &event;
    std::vector<node> nodes;
    std::vector<edgeweight> distances;
    std::vector<edgeweight> improvements;
};
} // namespace NetworKit

#endif // NETWORKIT_DISTANCE_AFFECTED_NODES_HPP_
