// El caso de la semana 10: palabras.txt viene ordenado. Con AVL ya no importa.
// Los tiempos dependen de la máquina. -O2, mediana de 3.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <random>
#include <set>
#include <string>
#include <vector>

#include "avl_set.h"
#include "bench.h"
#include "plain_tree.h"

int main(int argc, char** argv) {
    if (argc != 2) {
        std::cerr << "uso: dictionary_avl palabras.txt\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::cout << "orden de bytes: " << (std::is_sorted(words.begin(), words.end()) ? "si" : "no") << "\n";
    std::vector<std::string> shuffled = words;
    std::mt19937 random(11);
    std::shuffle(shuffled.begin(), shuffled.end(), random);

    auto report_avl = [](const char* name, const std::vector<std::string>& keys) {
        int height = 0;
        long rotations = 0;
        double seconds = median_seconds(3, [&] {
            AvlSet<std::string> tree;
            for (const std::string& key : keys) {
                tree.insert(key);
            }
            height = tree.height();
            rotations = tree.rotations();
        });
        std::cout << name << ": " << keys.size() << " palabras, altura " << height << ", rotaciones " << rotations
                  << ", " << seconds << " s\n";
    };
    auto report_set = [](const char* name, const std::vector<std::string>& keys) {
        double seconds = median_seconds(3, [&] {
            std::set<std::string> tree(std::less<std::string>{});
            for (const std::string& key : keys) {
                tree.insert(key);
            }
            keep(tree.size());
        });
        std::cout << name << ": " << keys.size() << " palabras, " << seconds << " s\n";
    };

    report_avl("AVL, tal como vienen", words);
    report_set("std::set, tal como vienen", words);
    report_avl("AVL, barajadas", shuffled);
    report_set("std::set, barajadas", shuffled);
    int plain_height = 0;
    double plain_seconds = median_seconds(3, [&] {
        PlainTree<std::string> tree;
        for (const std::string& key : shuffled) {
            tree.insert(key);
        }
        plain_height = tree.height();
    });
    std::cout << "sin balance, barajadas: " << shuffled.size() << " palabras, altura " << plain_height << ", "
              << plain_seconds << " s\n";
    return 0;
}
