// palabras.txt, otra vez: viene ordenado. Se inserta tal como viene y barajado.
// Se elige el mapa con un argumento, para que cada uno corra en su propio proceso.
// Los tiempos dependen de la máquina. Compilar con -O2 y sin sanitizers.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <map>
#include <random>
#include <string>
#include <vector>

#include "avl_map.h"
#include "bench.h"
#include "red_black_map.h"

namespace {

template <typename Map>
void report(const char* name, const std::vector<std::string>& keys) {
    int height = 0;
    long rotations = 0;
    double seconds = median_seconds(3, [&] {
        Map map;
        for (const std::string& key : keys) {
            map.insert(key, 1);
        }
        height = map.height();
        rotations = map.rotations();
    });
    std::cout << name << ": altura " << height << ", rotaciones " << rotations << ", " << seconds << " s\n";
}

void report_standard(const char* name, const std::vector<std::string>& keys) {
    double seconds = median_seconds(3, [&] {
        std::map<std::string, int> map;
        for (const std::string& key : keys) {
            map.insert({key, 1});
        }
        keep(map.size());
    });
    std::cout << name << ": " << seconds << " s\n";
}

}  // namespace

int main(int argc, char** argv) {
    std::string which = argc == 3 ? argv[2] : "";
    if (which != "avl" && which != "rn" && which != "std") {
        std::cerr << "uso: bench_words palabras.txt avl|rn|std\n";
        return 2;
    }
    std::ifstream file(argv[1]);
    std::vector<std::string> words;
    std::string word;
    while (std::getline(file, word)) {
        words.push_back(word);
    }
    if (words.empty()) {
        std::cerr << "no pude leer " << argv[1] << "\n";
        return 1;
    }
    std::vector<std::string> shuffled = words;
    std::mt19937 random(11);
    std::shuffle(shuffled.begin(), shuffled.end(), random);
    if (which == "avl") {
        report<AvlMap<std::string, int>>("AVL, tal como vienen", words);
        report<AvlMap<std::string, int>>("AVL, barajadas", shuffled);
    } else if (which == "rn") {
        report<RedBlackMap<std::string, int>>("rojinegro, tal como vienen", words);
        report<RedBlackMap<std::string, int>>("rojinegro, barajadas", shuffled);
    } else {
        report_standard("std::map, tal como vienen", words);
        report_standard("std::map, barajadas", shuffled);
    }
    return 0;
}
