#include <networkit/edgescores/EdgeScoreNormalizer.hpp>

namespace NetworKit {

template <typename A>
EdgeScoreNormalizer<A>::EdgeScoreNormalizer(const Graph &G, const std::vector<A> &score,
                                            bool invert, double lower, double upper)
    : EdgeScore<double>(G), input(&score), invert(invert), lower(lower), upper(upper) {}

template <typename A>
void EdgeScoreNormalizer<A>::run() {
    A minValue = std::numeric_limits<A>::max();
    A maxValue = std::numeric_limits<A>::lowest();

    G->forEdges([&](node, node, edgeid eid) {
        if ((*input)[eid] < minValue) {
            minValue = (*input)[eid];
        }

        if ((*input)[eid] > maxValue) {
            maxValue = (*input)[eid];
        }
    });

    double factor = (upper - lower) / (maxValue - minValue), offset = lower - minValue * factor;

    if (invert) {
        factor *= -1.0;
        offset = upper - minValue * factor;
    }

    scoreData.resize(G->upperEdgeIdBound(), std::numeric_limits<double>::quiet_NaN());

    G->parallelForEdges(
        [&](node, node, edgeid eid) { scoreData[eid] = factor * (*input)[eid] + offset; });

    hasRun = true;
}

template <typename A>
double EdgeScoreNormalizer<A>::score(node, node) {
    throw std::runtime_error("Not implemented: Use scores() instead.");
}

template <typename A>
double EdgeScoreNormalizer<A>::score(edgeid) {
    throw std::runtime_error("Not implemented: Use scores() instead.");
}

template class EdgeScoreNormalizer<double>;
template class EdgeScoreNormalizer<count>;

} /* namespace NetworKit */
