#pragma once

#include "parser.h"
#include "table.h"

#include <string>
#include <list>

namespace usql {

class USql {

public:
    USql() = default;


    std::unique_ptr<Table> execute(const std::string &command);

private:
    std::unique_ptr<Table> execute(Node &node);

    std::unique_ptr<Table> execute_create_table(CreateTableNode &node);
    std::unique_ptr<Table> execute_create_table_as_table(CreateTableAsSelectNode &node);
    std::unique_ptr<Table> execute_insert_into_table(InsertIntoTableNode &node);
    std::unique_ptr<Table> execute_select(SelectFromTableNode &node);
    std::unique_ptr<Table> execute_delete(DeleteFromTableNode &node);
    std::unique_ptr<Table> execute_update(UpdateTableNode &node);
    std::unique_ptr<Table> execute_load(LoadIntoTableNode &node);
    std::unique_ptr<Table> execute_save(SaveTableNode &node);


private:
    bool evalWhere(Node *where, Table *table, Row &row) const;

    static std::unique_ptr<ValueNode> evalValueNode(Table *table, Row &row, Node *node);
    static std::unique_ptr<ValueNode> evalDatabaseValueNode(Table *table, Row &row, Node *node);
    static std::unique_ptr<ValueNode> evalLiteralValueNode(Table *table, Row &row, Node *node);
    static std::unique_ptr<ValueNode> evalFunctionValueNode(Table *table, Row &row, Node *node);


    bool evalRelationalOperator(const RelationalOperatorNode &filter, Table *table, Row &row) const;
    bool evalLogicalOperator(LogicalOperatorNode &node, Table *pTable, Row &row) const;
    std::unique_ptr<ValueNode> evalArithmeticOperator(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, Row &row) const;


    static std::unique_ptr<Table> create_stmt_result_table(long code, const std::string& text);
    static std::tuple<int, ColDefNode> getColumnDefinition(Table *table, SelectColNode *select_col_node, int col_order) ;
    Table *find_table(const std::string &name);


private:
    Parser m_parser;
    std::list<Table> m_tables;
};

}	// namespace