// Cuánto se usa cada casilla con cada función hash, sin construir ninguna tabla.
// Uso: hash_compare archivo_de_palabras
#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <iostream>
#include <set>
#include <string>
#include <vector>

#include "hash_functions.h"
#include "word_file.h"

void report(const char* name, const std::vector<std::string>& words, std::size_t m, HashFunction hash) {
    std::vector<std::size_t> lengths(m, 0);
    for (const std::string& word : words) {
        lengths[hash(word) % m]++;
    }
    std::size_t used = 0;
    std::size_t longest = 0;
    double comparisons = 0;
    for (std::size_t length : lengths) {
        used += length > 0 ? 1 : 0;
        longest = std::max(longest, length);
        // En una cadena de c claves, buscar cada una cuesta 1, 2, ..., c comparaciones.
        comparisons += static_cast<double>(length) * static_cast<double>(length + 1) / 2;
    }
    std::printf("%-6s %9zu %6.2f %9zu %9zu %11.1f\n", name, m, static_cast<double>(words.size()) / static_cast<double>(m),
                used, longest, comparisons / static_cast<double>(words.size()));
}

int main(int argc, char** argv) {
    if (argc != 2) {
        std::cerr << "uso: hash_compare archivo_de_palabras\n";
        return 1;
    }
    std::vector<std::string> words = read_words(argv[1]);
    std::set<std::uint64_t> sums;
    for (const std::string& word : words) {
        sums.insert(sum_hash(word));
    }
    std::printf("%zu palabras; la suma da %zu valores distintos, de %llu a %llu\n", words.size(), sums.size(),
                static_cast<unsigned long long>(*sums.begin()), static_cast<unsigned long long>(*sums.rbegin()));
    std::printf("%-6s %9s %6s %9s %9s %11s\n", "hash", "m", "alfa", "usadas", "la_mayor", "comp_acierto");
    for (std::size_t m : {1024u, 32768u, 1048576u}) {
        report("suma", words, m, sum_hash);
        report("fnv1a", words, m, fnv1a);
    }
}
