/*
 *
 */

#include <networkit/community/IntrapartitionDensity.hpp>
#include <networkit/auxiliary/SignalHandling.hpp>

void NetworKit::IntrapartitionDensity::run() {
    hasRun = false;

    Aux::SignalHandler handler;

    minimumValue = std::numeric_limits< double >::max();
    maximumValue  = std::numeric_limits< double >::lowest();
    unweightedAverage = 0;
    weightedAverage = 0;
    values.clear();

    std::vector<count> clusterSizes(P.upperBound(), 0);
    std::vector<count> intraEdges(P.upperBound(), 0);

    handler.assureRunning();

    G.forEdges([&](node u, node v) {
        if (P[u] == P[v]) {
            ++intraEdges[P[u]];
        }
    });

    handler.assureRunning();

    G.forNodes([&](node u) {
        ++clusterSizes[P[u]];
    });

    handler.assureRunning();

    count numClusters = 0;
    count intraEdgesSum = 0;
    count possibleIntraEdgesSum = 0;

    values.resize(P.upperBound(), 0);

    for (index i = 0; i < clusterSizes.size(); ++i) {
        if (clusterSizes[i] > 0) {
            double id = 1;
            count possibleEdges = clusterSizes[i] * (clusterSizes[i]-1) / 2;
            if (possibleEdges > 0) {
                id = intraEdges[i] * 1.0 / possibleEdges;
            }

            values[i] = id;

            unweightedAverage += id;
            weightedAverage += id * clusterSizes[i];
            minimumValue = std::min(id, minimumValue);
            maximumValue = std::max(id, maximumValue);

            possibleIntraEdgesSum += possibleEdges;
            intraEdgesSum += intraEdges[i];
            ++numClusters;
        } else {
            clusterSizes[i] = none;
        }
    }

    handler.assureRunning();

    unweightedAverage /= numClusters;
    weightedAverage /= G.numberOfNodes();

    globalValue = intraEdgesSum * 1.0 / possibleIntraEdgesSum;
    hasRun = true;
}
