#pragma once

#include "exception.h"
#include "parser.h"

#include <vector>

namespace usql {


    struct ColValue {

	virtual bool isNull() { return false; };
	virtual long getIntValue() { throw Exception("Not supported"); };
	virtual double getDoubleValue() { throw Exception("Not supported"); };
	virtual std::string getStringValue() { throw Exception("Not supported"); };
    };


    struct ColNullValue : ColValue {

	virtual bool isNull() { return true; };
	virtual std::string getStringValue() { return "null"; };
    };


    struct ColIntegerValue : ColValue {

	ColIntegerValue(long value) : m_integer(value) {};
	ColIntegerValue(const ColIntegerValue &other) : m_integer(other.m_integer) {};

	virtual long getIntValue() { return m_integer; };
	virtual double getDoubleValue() { return (double) m_integer; };
	virtual std::string getStringValue() { return std::to_string(m_integer); };

	int m_integer;
    };


    struct ColDoubleValue : ColValue {

	ColDoubleValue(double value) : m_double(value) {};
	ColDoubleValue(const ColDoubleValue &other) : m_double(other.m_double) {}

	virtual long getIntValue() { return (long) m_double; };
	virtual double getDoubleValue() { return m_double; };
	virtual std::string getStringValue() { return std::to_string(m_double); };

	double m_double;
    };


    struct ColStringValue : ColValue {

	ColStringValue(const std::string value) : m_string(value) {};
	ColStringValue(const ColStringValue &other) : m_string(other.m_string) {};

	virtual long getIntValue() { return std::stoi(m_string); };
	virtual double getDoubleValue() { return std::stod(m_string); };
	virtual std::string getStringValue() { return m_string; };

	std::string m_string;
    };


    class Row {

    public:
	Row(int cols_count);
	Row(const Row &other);

	Row &operator=(Row other);

	void setColumnNull(int col_index);
	void setColumnValue(int col_index, long value);
	void setColumnValue(int col_index, double value);
	void setColumnValue(int col_index, const std::string &value);
	void setColumnValue(ColDefNode *col_def, ColValue *col_value);
	void setColumnValue(ColDefNode *col_def, ValueNode *col_value);

	ColValue &operator[](int i) {
		return *m_columns[i];
	}

	ColValue * ithColumn(int i) const {
		return m_columns[i].get();
	}

	void print();

    private:
	std::vector<std::unique_ptr<ColValue>> m_columns;
    };

}	// namespace