#include "Pgsql_Params.h"
#include <cstring>

using namespace Pgsql;

Params::Params()
{}

Params::Params(const Params& rhs)
	: m_paramTypes(rhs.m_paramTypes)
	, m_paramLengths(rhs.m_paramLengths)
	, m_paramFormats(rhs.m_paramFormats)
{
	//std::vector<const char *> m_paramValues;
    appendValues(rhs.m_paramValues);
}

Params& Params::operator=(const Params& rhs)
{
	if (&rhs != this) {
		m_paramTypes = rhs.m_paramTypes;
		m_paramLengths = rhs.m_paramLengths;
		m_paramFormats = rhs.m_paramFormats;
        appendValues(rhs.m_paramValues);
	}
	return *this;
}

Params::Params(Params&& rhs)
	: m_paramTypes(std::move(rhs.m_paramTypes))
	, m_paramValues(std::move(rhs.m_paramValues))
	, m_paramLengths(std::move(rhs.m_paramLengths))
	, m_paramFormats(std::move(rhs.m_paramFormats))
{
	rhs.m_paramValues.clear(); // just in case it was copied instead of moved
}

Params& Params::operator=(Params&& rhs)
{
	if (&rhs != this) {
		m_paramTypes   = std::move(rhs.m_paramTypes);
		m_paramValues  = std::move(rhs.m_paramValues);
		rhs.m_paramValues.clear(); // just in case it was copied instead of moved
		m_paramLengths = std::move(rhs.m_paramLengths);
		m_paramFormats = std::move(rhs.m_paramFormats);
	}
	return *this;
}

Params::~Params()
{
	deleteValues();
}

Param Params::addText(const char *data, Oid oid)
{
	m_paramTypes.push_back(oid);
	m_paramValues.push_back(data);
    m_paramLengths.push_back(data ? static_cast<int>(strlen(data)) + 1 : 0);
	m_paramFormats.push_back(0);
    return Param(*this, static_cast<int>(m_paramValues.size()) - 1);
}

Param Params::add(const QString &s, Oid oid)
{
	auto ba = s.toUtf8();
	const int len = ba.size();
	char * p = new char[len+1];
	std::memcpy(p, ba.data(), len);
	p[len] = 0;
	return addText(p, oid);
}

Param Params::add(const char *data, Oid oid)
{
	char * p = nullptr;
	int len = 0;
	if (data) {
        len = static_cast<int>(std::strlen(data));
		p = new char[len+1];
		std::memcpy(p, data, len);
		p[len] = 0;
	}
	return addText(p, oid);
}

Param Params::add(int v, Oid oid)
{
    std::string s = std::format("{:d}", v);
    return add(s.c_str(), oid);
}

template <typename T, typename U>
void concatContainers(T &d, const U& s)
{
    d.insert(d.end(), s.begin(), s.end());
}

void Params::addParams(const Params &params)
{
    concatContainers(m_paramTypes, params.m_paramTypes);
    concatContainers(m_paramLengths, params.m_paramLengths);
    concatContainers(m_paramFormats, params.m_paramFormats);
    appendValues(params.m_paramValues);
}

void Params::clear()
{
	m_paramTypes.clear();
	deleteValues();
	m_paramValues.clear();
	m_paramLengths.clear();
	m_paramFormats.clear();
}

void Params::appendValues(const t_paramValues &r)
{
    const int n = static_cast<int>(r.size());
    const size_t ofs = m_paramValues.size();
    m_paramValues.reserve(ofs + n);
	for (int i = 0; i < n; ++i) {
		if (r[i]) {
            const int len = m_paramLengths[ofs + i];
			char * p = new char[len+1];
			std::memcpy(p, r[i], len+1);
			m_paramValues.push_back(p);
		}
		else {
			m_paramValues.push_back(nullptr);
		}
	}
}
