#include <functional>
#include <initializer_list>
#include <stdint.h>
#include <string>
#include "tabulate.hpp"
typedef std::function<bool(uint64_t, char)> FUNC;
typedef std::function<bool(std::vector<bool>)> BINARY_EXPRESSION;
inline bool ImplicationForm(bool var1, bool var2)
{
    return (!var1 || var2);
}
inline bool XNOR(bool var1, bool var2)
{
    return !(var1 ^ var2);
}
inline bool EquivalentForm(bool var1, bool var2)
{
    // 相当于同或
    return XNOR(var1, var2);
}
inline bool NAND(bool var1, bool var2)
{
    // 与非联结词
    return !(var1 && var2);
}
inline bool NOR(bool var1, bool var2)
{
    // 或非联结词
    return !(var1 || var2);
}
tabulate::Table func_to_truth_table(const std::initializer_list<FUNC>& func_list, const std::initializer_list<std::string>& vars)
{
    const auto var_size = vars.end() - vars.begin();
    if (var_size > 63) {
        std::cerr << "无法处理超过63个变量!" << std::endl;
        return tabulate::Table();
    }
    tabulate::Table table;
    // 插入头部
    tabulate::Table::Row_t header;
    header.insert(header.end(), vars.begin(), vars.end());
    for (int i = 0; i < func_list.end() - func_list.begin(); i++) {
        header.push_back("Result" + std::to_string(i));
    }
    table.add_row(header);
    for (auto& cell : table[0]) {
        cell.format()
            .font_color(tabulate::Color::blue)
            .font_style({ tabulate::FontStyle::bold, tabulate::FontStyle::underline })
            .font_align(tabulate::FontAlign::center);
    }
    uint64_t var_truth = 0;
    uint64_t max_size = (uint64_t)0x1 << var_size;
    for (uint64_t i = 0; i < max_size; i++) {
        tabulate::Table::Row_t onerow;
        for (char j = (var_size - 1); j >= 0; j--) {
            onerow.push_back(std::to_string((var_truth >> j) & 0x1));
        }
        for (auto& f : func_list) {
            onerow.push_back(std::to_string((int)f(var_truth, (char)var_size)));
        }
        ++var_truth;
        table.add_row(onerow);
        for (auto& cell : table[i + 1]) {
            cell.format()
                .font_align(tabulate::FontAlign::center);
        }
    }
    for (int i = 0; i < func_list.end() - func_list.begin(); i++) {
        for (auto& cell : table.column(var_size + i)) {
            cell.format()
                .font_style({ tabulate::FontStyle::bold });
        }
    }
    return table;
}
tabulate::Table func_to_truth_table(const FUNC f, const std::initializer_list<std::string>& vars)
{
    return func_to_truth_table({ f }, vars);
}
FUNC make_basic_func(BINARY_EXPRESSION f)
{
    std::function<bool(uint64_t, char)> ret = [f](uint64_t truth, char length) -> bool {
        bool val = truth & 0x1;
        std::vector<bool> val_list;
        for (int i = length - 1; i >= 1; i--) {
            val_list.push_back((truth >> i) & 0x1);
        }
        val_list.push_back(val);
        return f(val_list);
    };
    return ret;
}
int main(int argc, char const* argv[])
{
    // ∨∧→↔┐
    std::cout << "p ∧ r ∧ ┐(q → p):" << std::endl;
    std::cout << func_to_truth_table(make_basic_func([](std::vector<bool> val_list) -> bool {
        return val_list[0] && val_list[2] && (!ImplicationForm(val_list[1], val_list[0]));
    }),
        { "p", "q", "r" })
              << std::endl;
    std::initializer_list<FUNC> func_list {
        make_basic_func([](std::vector<bool> val_list) -> bool {
            return val_list[0] && val_list[2] && (!ImplicationForm(val_list[1], val_list[0]));
        }),
        make_basic_func([](std::vector<bool> val_list) -> bool {
            return ImplicationForm(ImplicationForm(val_list[0], val_list[1]), ImplicationForm(!val_list[1], !val_list[0])) || val_list[2];
        }),
        make_basic_func([](std::vector<bool> val_list) -> bool {
            return EquivalentForm(ImplicationForm(val_list[0], val_list[1]), ImplicationForm(val_list[0], val_list[2]));
        })
    };
    func_to_truth_table(func_list, { "p", "q", "r" }).print(std::cout);
    return 0;
}