#include "Pgsql_Result.h"

using namespace Pgsql;


Result::Result(PGresult *res)
	: result(res)
{
	if (res == nullptr) {
		throw std::runtime_error("Passing nullptr to Result::Result is not allowed");
	}
}

Result::~Result()
{
	PQclear(result);
}


Result::Result(Result &&rhs)
	: result(rhs.result)
{
	rhs.result = nullptr;
}

Result& Result::operator=(Result &&rhs)
{
	if (result) {
		PQclear(result);
	}
	result = rhs.result;
	rhs.result = nullptr;
	return *this;
}

Result::operator bool() const
{
	return result != nullptr;
}

ExecStatusType Result::resultStatus()
{
	return PQresultStatus(result);
}

std::string Result::getResStatus()
{
//    return PQresStatus(result);
		return "";
}

std::string Result::diagSqlState()
{
	std::string s(PQresultErrorField(result, PG_DIAG_SQLSTATE));
	return s;
}

ErrorDetails Result::diagDetails()
{
	return ErrorDetails::createErrorDetailsFromPGresult(result);
}

int Result::tuplesAffected() const
{
	int i;
	char * res = PQcmdTuples(result);
	if (res && res[0] != '\0') {
		try {
			i = std::stoi(res);
		}
		catch (std::invalid_argument& ) {
			i = -1;
		}
		catch (std::out_of_range& ) {
			i = -1;
		}
	}
	else {
		i = -1;
	}
	return i;
}

int Result::rows() const
{
	return PQntuples(result);
}

int Result::cols() const
{
	return PQnfields(result);
}

const char * Result::getColName(int idx) const
{
	return PQfname(result, idx);
}

inline void Result::colRangeCheck(int col) const
{
	if (col < 0 || col >= cols())
		throw std::range_error("column index out of range");
}

inline void Result::rowRangeCheck(int row) const
{
	if (row < 0 || row >= rows())
		throw std::range_error("row index out of range");
}

const char * Result::val(int col, int row) const
{
	colRangeCheck(col);
	rowRangeCheck(row);
	return PQgetvalue(result, row, col);
}

Value Result::get(int col, int row) const
{
	colRangeCheck(col);
	rowRangeCheck(row);

	bool is_null = PQgetisnull(result, row, col);
	char *ptr = is_null ? nullptr : PQgetvalue(result, row, col);
	return Value(
		ptr,
		PQftype(result, col)
		);
}

Oid Result::type(int col) const
{
	colRangeCheck(col);

	return PQftype(result, col);
}

bool Result::null(int col, int row) const
{
	colRangeCheck(col);
	rowRangeCheck(row);

	return PQgetisnull(result, row, col);
}

Oid Result::ftable(int col) const
{
	colRangeCheck(col);
	return PQftable(result, col);
}

int Result::ftableCol(int col) const
{
	colRangeCheck(col);
	return PQftablecol(result, col);
}
