// Distancia de edición: la tabla, el camino hacia atrás y el alineamiento.
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

#include "sequences.h"

namespace {

void print_table(const std::string& a, const std::string& b, const Table& table) {
    std::cout << "    ";
    for (char c : b) std::cout << std::setw(2) << c;
    std::cout << '\n';
    for (std::size_t i = 0; i <= a.size(); i++) {
        std::cout << (i == 0 ? ' ' : a[i - 1]) << " ";
        for (std::size_t j = 0; j <= b.size(); j++) std::cout << std::setw(2) << table[i][j];
        std::cout << '\n';
    }
}

void show(const std::string& a, const std::string& b) {
    const Table dist = edit_table(a, b);
    std::cout << a << " -> " << b << '\n';
    print_table(a, b, dist);
    std::cout << "Distancia: " << dist[a.size()][b.size()] << '\n';
    const std::vector<EditStep> steps = edit_walk(a, b, dist);

    std::string top;
    std::string bottom;
    std::string mark;
    for (const EditStep& s : steps) {
        top.push_back(s.kind == EditStep::Kind::insert ? '-' : a[s.i]);
        bottom.push_back(s.kind == EditStep::Kind::erase ? '-' : b[s.j]);
        mark.push_back(s.kind == EditStep::Kind::keep ? ' ' : '*');
    }
    std::cout << "Alineamiento:\n  " << top << "\n  " << bottom << "\n  " << mark << '\n';
    std::cout << "Operaciones:\n";
    for (const EditStep& s : steps) {
        if (s.kind == EditStep::Kind::change) {
            std::cout << "  cambiar " << a[s.i] << " por " << b[s.j] << '\n';
        } else if (s.kind == EditStep::Kind::erase) {
            std::cout << "  borrar " << a[s.i] << '\n';
        } else if (s.kind == EditStep::Kind::insert) {
            std::cout << "  insertar " << b[s.j] << '\n';
        }
    }
    std::cout << "Con solo borrar e insertar: " << static_cast<int>(a.size() + b.size()) - 2 * lcs_table(a, b)[a.size()][b.size()]
              << "\n\n";
}

}  // namespace

int main() {
    show("casa", "cosas");
    show("algoritmo", "logaritmo");
}
