/*
 * Copyright (C) 2014-2024 CZ.NIC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>
#include <QString>
#include <QStringList>
#include <utility> /* ::std::swap */

#include "src/datovka_shared/compat/compiler.h" /* macroStdMove */
#include "src/datovka_shared/json/basic.h"
#include "src/datovka_shared/json/helper.h"
#include "src/datovka_shared/records_management/conversion.h"
#include "src/datovka_shared/records_management/json/entry_error.h"
#include "src/datovka_shared/records_management/json/stored_files.h"

/* Null objects - for convenience. */
static const Json::Int64StringList nullInt64StringList;
#define NULL_DMID -1
static const QStringList nullStringList;
static const RecMgmt::DmEntryList nullDms;
static const RecMgmt::DiEntryList nullDis;
#define NULL_LIMIT -1
static const RecMgmt::ErrorEntry nullErrorEntry;

static
const QString keyDmIds("dm_ids");
static
const QString keyDiIds("di_ids");

static
const QString keyDmId("dm_id");
static
const QString keyDiId("di_id");
static
const QString keyLocations("locations");

static
const QString keyDms("dms");
static
const QString keyDis("dis");
static
const QString keyLimit("limit");
static
const QString keyError("error");

class RecMgmt::StoredFilesReqPrivate {
public:
	StoredFilesReqPrivate(void)
	    : m_dmIds(), m_diIds()
	{ }

	StoredFilesReqPrivate &operator=(const StoredFilesReqPrivate &other) Q_DECL_NOTHROW
	{
		m_dmIds = other.m_dmIds;
		m_diIds = other.m_diIds;

		return *this;
	}

	bool operator==(const StoredFilesReqPrivate &other) const
	{
		return (m_dmIds == other.m_dmIds) &&
		    (m_diIds == other.m_diIds);
	}

	Json::Int64StringList m_dmIds; /*!< Data message identifiers. */
	Json::Int64StringList m_diIds; /*!< Delivery info identifiers. */
};

RecMgmt::StoredFilesReq::StoredFilesReq(void)
    : Json::Object(),
    d_ptr(Q_NULLPTR)
{
}

RecMgmt::StoredFilesReq::StoredFilesReq(const StoredFilesReq &other)
    : Json::Object(),
    d_ptr((other.d_func() != Q_NULLPTR) ? (new (::std::nothrow) StoredFilesReqPrivate) : Q_NULLPTR)
{
	Q_D(StoredFilesReq);
	if (d == Q_NULLPTR) {
		return;
	}

	*d = *other.d_func();
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::StoredFilesReq::StoredFilesReq(StoredFilesReq &&other) Q_DECL_NOEXCEPT
    : Json::Object(),
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
    d_ptr(other.d_ptr.release()) //d_ptr(::std::move(other.d_ptr))
#else /* < Qt-5.12 */
    d_ptr(other.d_ptr.take())
#endif /* >= Qt-5.12 */
{
}
#endif /* Q_COMPILER_RVALUE_REFS */

RecMgmt::StoredFilesReq::~StoredFilesReq(void)
{
}

RecMgmt::StoredFilesReq::StoredFilesReq(const Json::Int64StringList &dmIds,
    const Json::Int64StringList &diIds)
    : Json::Object(),
    d_ptr(new (::std::nothrow) StoredFilesReqPrivate)
{
	Q_D(StoredFilesReq);
	d->m_dmIds = dmIds;
	d->m_diIds = diIds;
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::StoredFilesReq::StoredFilesReq(Json::Int64StringList &&dmIds,
    Json::Int64StringList &&diIds)
    : Json::Object(),
    d_ptr(new (::std::nothrow) StoredFilesReqPrivate)
{
	Q_D(StoredFilesReq);
	d->m_dmIds = ::std::move(dmIds);
	d->m_diIds = ::std::move(diIds);
}
#endif /* Q_COMPILER_RVALUE_REFS */

/*!
 * @brief Ensures StoredFilesReqPrivate presence.
 *
 * @note Returns if StoredFilesReqPrivate could not be allocated.
 */
#define ensureStoredFilesReqPrivate(_x_) \
	do { \
		if (Q_UNLIKELY(d_ptr == Q_NULLPTR)) { \
			StoredFilesReqPrivate *p = new (::std::nothrow) StoredFilesReqPrivate; \
			if (Q_UNLIKELY(p == Q_NULLPTR)) { \
				Q_ASSERT(0); \
				return _x_; \
			} \
			d_ptr.reset(p); \
		} \
	} while (0)

RecMgmt::StoredFilesReq &RecMgmt::StoredFilesReq::operator=(const StoredFilesReq &other) Q_DECL_NOTHROW
{
	if (other.d_func() == Q_NULLPTR) {
		d_ptr.reset(Q_NULLPTR);
		return *this;
	}
	ensureStoredFilesReqPrivate(*this);
	Q_D(StoredFilesReq);

	*d = *other.d_func();

	return *this;
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::StoredFilesReq &RecMgmt::StoredFilesReq::operator=(StoredFilesReq &&other) Q_DECL_NOTHROW
{
	swap(*this, other);
	return *this;
}
#endif /* Q_COMPILER_RVALUE_REFS */

bool RecMgmt::StoredFilesReq::operator==(const StoredFilesReq &other) const
{
	Q_D(const StoredFilesReq);
	if ((d == Q_NULLPTR) && ((other.d_func() == Q_NULLPTR))) {
		return true;
	} else if ((d == Q_NULLPTR) || ((other.d_func() == Q_NULLPTR))) {
		return false;
	}

	return *d == *other.d_func();
}

bool RecMgmt::StoredFilesReq::operator!=(const StoredFilesReq &other) const
{
	return !operator==(other);
}

void RecMgmt::StoredFilesReq::swap(StoredFilesReq &first, StoredFilesReq &second) Q_DECL_NOTHROW
{
	using ::std::swap;
	swap(first.d_ptr, second.d_ptr);
}

bool RecMgmt::StoredFilesReq::isNull(void) const
{
	Q_D(const StoredFilesReq);
	return d == Q_NULLPTR;
}

bool RecMgmt::StoredFilesReq::isValid(void) const
{
	Q_D(const StoredFilesReq);
	return (!isNull()) &&
	    ((!d->m_dmIds.isEmpty()) || (!d->m_diIds.isEmpty()));
}

const Json::Int64StringList &RecMgmt::StoredFilesReq::dmIds(void) const
{
	Q_D(const StoredFilesReq);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullInt64StringList;
	}

	return d->m_dmIds;
}

void RecMgmt::StoredFilesReq::setDmIds(const Json::Int64StringList &dms)
{
	ensureStoredFilesReqPrivate();
	Q_D(StoredFilesReq);
	d->m_dmIds = dms;
}

#ifdef Q_COMPILER_RVALUE_REFS
void RecMgmt::StoredFilesReq::setDmIds(Json::Int64StringList &&dms)
{
	ensureStoredFilesReqPrivate();
	Q_D(StoredFilesReq);
	d->m_dmIds = ::std::move(dms);
}
#endif /* Q_COMPILER_RVALUE_REFS */

const Json::Int64StringList &RecMgmt::StoredFilesReq::diIds(void) const
{
	Q_D(const StoredFilesReq);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullInt64StringList;
	}

	return d->m_diIds;
}

void RecMgmt::StoredFilesReq::setDiIds(const Json::Int64StringList &dis)
{
	ensureStoredFilesReqPrivate();
	Q_D(StoredFilesReq);
	d->m_diIds = dis;
}

#ifdef Q_COMPILER_RVALUE_REFS
void RecMgmt::StoredFilesReq::setDiIds(Json::Int64StringList &&dis)
{
	{
	ensureStoredFilesReqPrivate();
	Q_D(StoredFilesReq);
	d->m_diIds = ::std::move(dis);
}
}
#endif /* Q_COMPILER_RVALUE_REFS */

RecMgmt::StoredFilesReq RecMgmt::StoredFilesReq::fromJson(
    const QByteArray &json, bool *ok)
{
	QJsonObject jsonObj;
	if (Q_UNLIKELY(!Json::Helper::readRootObject(json, jsonObj))) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return StoredFilesReq();
	}

	return fromJsonVal(jsonObj, ok);
}

RecMgmt::StoredFilesReq RecMgmt::StoredFilesReq::fromJsonVal(
    const QJsonValue &jsonVal, bool *ok)
{
	StoredFilesReq sfr;

	if (Q_UNLIKELY(!jsonVal.isObject())) {
		goto fail;
	}

	{
		const QJsonObject jsonObj = jsonVal.toObject();
		{
			QJsonArray jsonArr;
			if (Json::Helper::readArray(jsonObj, keyDmIds, jsonArr,
			        Json::Helper::ACCEPT_VALID)) {
				bool iOk = false;
				sfr.setDmIds(Json::Int64StringList::fromJsonVal(jsonArr, &iOk));
				if (Q_UNLIKELY(!iOk)) {
					goto fail;
				}
			} else {
				goto fail;
			}
		}
		{
			QJsonArray jsonArr;
			if (Json::Helper::readArray(jsonObj, keyDiIds, jsonArr,
			        Json::Helper::ACCEPT_VALID)) {
				bool iOk = false;
				sfr.setDiIds(Json::Int64StringList::fromJsonVal(jsonArr, &iOk));
				if (Q_UNLIKELY(!iOk)) {
					goto fail;
				}
			} else {
				goto fail;
			}
		}

		if (ok != Q_NULLPTR) {
			*ok = true;
		}
		return sfr;
	}

fail:
	if (ok != Q_NULLPTR) {
		*ok = false;
	}
	return StoredFilesReq();
}

bool RecMgmt::StoredFilesReq::toJsonVal(QJsonValue &jsonVal) const
{
	QJsonObject jsonObj;

	{
		QJsonValue jsonVal;
		if (dmIds().toJsonVal(jsonVal)) {
			jsonObj.insert(keyDmIds, jsonVal);
		} else {
			goto fail;
		}
	}
	{
		QJsonValue jsonVal;
		if (diIds().toJsonVal(jsonVal)) {
			jsonObj.insert(keyDiIds, jsonVal);
		} else {
			goto fail;
		}
	}

	jsonVal = jsonObj;
	return true;

fail:
	jsonVal = QJsonObject();
	return false;
}

class RecMgmt::DmEntryPrivate {
public:
	DmEntryPrivate(void)
	    : m_dmId(NULL_DMID), m_locations()
	{ }

	DmEntryPrivate &operator=(const DmEntryPrivate &other) Q_DECL_NOTHROW
	{
		m_dmId = other.m_dmId;
		m_locations = other.m_locations;

		return *this;
	}

	bool operator==(const DmEntryPrivate &other) const
	{
		return (m_dmId == other.m_dmId) &&
		    (m_locations == other.m_locations);
	}

	qint64 m_dmId; /*!< Data message identifier. */
	QStringList m_locations; /*!< Where the uploaded file is located in the service. */
};

RecMgmt::DmEntry::DmEntry(void)
    : Json::Object(),
    d_ptr(Q_NULLPTR)
{
}

RecMgmt::DmEntry::DmEntry(const DmEntry &other)
    : Json::Object(),
    d_ptr((other.d_func() != Q_NULLPTR) ? (new (::std::nothrow) DmEntryPrivate) : Q_NULLPTR)
{
	Q_D(DmEntry);
	if (d == Q_NULLPTR) {
		return;
	}

	*d = *other.d_func();
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::DmEntry::DmEntry(DmEntry &&other) Q_DECL_NOEXCEPT
    : Json::Object(),
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
    d_ptr(other.d_ptr.release()) //d_ptr(::std::move(other.d_ptr))
#else /* < Qt-5.12 */
    d_ptr(other.d_ptr.take())
#endif /* >= Qt-5.12 */
{
}
#endif /* Q_COMPILER_RVALUE_REFS */

RecMgmt::DmEntry::~DmEntry(void)
{
}

RecMgmt::DmEntry::DmEntry(qint64 dmId, const QStringList &locations)
    : Json::Object(),
    d_ptr(new (::std::nothrow) DmEntryPrivate)
{
	Q_D(DmEntry);
	d->m_dmId = dmId;
	d->m_locations = locations;
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::DmEntry::DmEntry(qint64 dmId, QStringList &&locations)
    : Json::Object(),
    d_ptr(new (::std::nothrow) DmEntryPrivate)
{
	Q_D(DmEntry);
	d->m_dmId = dmId;
	d->m_locations = ::std::move(locations);
}
#endif /* Q_COMPILER_RVALUE_REFS */

/*!
 * @brief Ensures DmEntryPrivate presence.
 *
 * @note Returns if DmEntryPrivate could not be allocated.
 */
#define ensureDmEntryPrivate(_x_) \
	do { \
		if (Q_UNLIKELY(d_ptr == Q_NULLPTR)) { \
			DmEntryPrivate *p = new (::std::nothrow) DmEntryPrivate; \
			if (Q_UNLIKELY(p == Q_NULLPTR)) { \
				Q_ASSERT(0); \
				return _x_; \
			} \
			d_ptr.reset(p); \
		} \
	} while (0)

RecMgmt::DmEntry &RecMgmt::DmEntry::operator=(const DmEntry &other) Q_DECL_NOTHROW
{
	if (other.d_func() == Q_NULLPTR) {
		d_ptr.reset(Q_NULLPTR);
		return *this;
	}
	ensureDmEntryPrivate(*this);
	Q_D(DmEntry);

	*d = *other.d_func();

	return *this;
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::DmEntry &RecMgmt::DmEntry::operator=(DmEntry &&other) Q_DECL_NOTHROW
{
	swap(*this, other);
	return *this;
}
#endif /* Q_COMPILER_RVALUE_REFS */

bool RecMgmt::DmEntry::operator==(const DmEntry &other) const
{
	Q_D(const DmEntry);
	if ((d == Q_NULLPTR) && ((other.d_func() == Q_NULLPTR))) {
		return true;
	} else if ((d == Q_NULLPTR) || ((other.d_func() == Q_NULLPTR))) {
		return false;
	}

	return *d == *other.d_func();
}

bool RecMgmt::DmEntry::operator!=(const DmEntry &other) const
{
	return !operator==(other);
}

void RecMgmt::DmEntry::swap(DmEntry &first, DmEntry &second) Q_DECL_NOTHROW
{
	using ::std::swap;
	swap(first.d_ptr, second.d_ptr);
}

bool RecMgmt::DmEntry::isNull(void) const
{
	Q_D(const DmEntry);
	return d == Q_NULLPTR;
}

bool RecMgmt::DmEntry::isValid(void) const
{
	Q_D(const DmEntry);
	return (!isNull()) && (d->m_dmId >= 0);
}

qint64 RecMgmt::DmEntry::dmId(void) const
{
	Q_D(const DmEntry);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return NULL_DMID;
	}

	return d->m_dmId;
}

void RecMgmt::DmEntry::setDmId(qint64 id)
{
	ensureDmEntryPrivate();
	Q_D(DmEntry);
	d->m_dmId = id;
}

const QStringList &RecMgmt::DmEntry::locations(void) const
{
	Q_D(const DmEntry);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullStringList;
	}

	return d->m_locations;
}

void RecMgmt::DmEntry::setLocations(const QStringList &l)
{
	ensureDmEntryPrivate();
	Q_D(DmEntry);
	d->m_locations = l;
}

#ifdef Q_COMPILER_RVALUE_REFS
void RecMgmt::DmEntry::setLocations(QStringList &&l)
{
	ensureDmEntryPrivate();
	Q_D(DmEntry);
	d->m_locations = ::std::move(l);
}
#endif /* Q_COMPILER_RVALUE_REFS */

RecMgmt::DmEntry RecMgmt::DmEntry::fromJson(
    const QByteArray &json, bool *ok)
{
	QJsonObject jsonObj;
	if (Q_UNLIKELY(!Json::Helper::readRootObject(json, jsonObj))) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return DmEntry();
	}

	return fromJsonVal(jsonObj, ok);
}

RecMgmt::DmEntry RecMgmt::DmEntry::fromJsonVal(
    const QJsonValue &jsonVal, bool *ok)
{
	DmEntry e;

	if (Q_UNLIKELY(!jsonVal.isObject())) {
		goto fail;
	}

	{
		const QJsonObject jsonObj = jsonVal.toObject();
		{
			qint64 valQint64;
			if (Json::Helper::readQint64String(jsonObj, keyDmId, valQint64,
			        Json::Helper::ACCEPT_VALID)) {
				e.setDmId(valQint64);
			} else {
				goto fail;
			}
		}
		{
			QStringList valStrList;
			if (Json::Helper::readStringList(jsonObj, keyLocations, valStrList,
			        Json::Helper::ACCEPT_VALID)) {
				e.setLocations(macroStdMove(valStrList));
			} else {
				goto fail;
			}
		}

		if (ok != Q_NULLPTR) {
			*ok = true;
		}
		return e;
	}

fail:
	if (ok != Q_NULLPTR) {
		*ok = false;
	}
	return DmEntry();
}

bool RecMgmt::DmEntry::toJsonVal(QJsonValue &jsonVal) const
{
	QJsonObject jsonObj;

	jsonObj.insert(keyDmId, QString::number(dmId()));
	jsonObj.insert(keyLocations, QJsonArray::fromStringList(locations()));

	jsonVal = jsonObj;
	return true;
}

RecMgmt::DmEntryList::DmEntryList(void)
    : Json::Object(),
    QList<DmEntry>()
{
}

RecMgmt::DmEntryList RecMgmt::DmEntryList::fromJson(const QByteArray &json,
    bool *ok)
{
	QJsonArray jsonArr;
	if (Q_UNLIKELY(!Json::Helper::readRootArray(json, jsonArr))) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return DmEntryList();
	}
	return fromJsonVal(jsonArr, ok);
}

RecMgmt::DmEntryList RecMgmt::DmEntryList::fromJsonVal(
    const QJsonValue &jsonVal, bool *ok)
{
	DmEntryList l;

	if (Q_UNLIKELY(!jsonVal.isArray())) {
		goto fail;
	}

	{
		const QJsonArray jsonArr = jsonVal.toArray();
		for (const QJsonValue &v : jsonArr) {
			bool iOk = false;
			l.append(DmEntry::fromJsonVal(v, &iOk));
			if (Q_UNLIKELY(!iOk)) {
				goto fail;
			}
		}
	}

	if (ok != Q_NULLPTR) {
		*ok = true;
	}
	return l;

fail:
	if (ok != Q_NULLPTR) {
		*ok = false;
	}
	return DmEntryList();
}

bool RecMgmt::DmEntryList::toJsonVal(QJsonValue &jsonVal) const
{
	QJsonArray arr;

	for (const DmEntry &e : *this) {
		QJsonValue v;
		if (Q_UNLIKELY(!e.toJsonVal(v))) {
			goto fail;
		}
		arr.append(v);
	}

	jsonVal = arr;
	return true;

fail:
	jsonVal = QJsonArray();
	return false;
}

class RecMgmt::DiEntryPrivate {
public:
	DiEntryPrivate(void)
	    : m_diId(NULL_DMID), m_locations()
	{ }

	DiEntryPrivate &operator=(const DiEntryPrivate &other) Q_DECL_NOTHROW
	{
		m_diId = other.m_diId;
		m_locations = other.m_locations;

		return *this;
	}

	bool operator==(const DiEntryPrivate &other) const
	{
		return (m_diId == other.m_diId) &&
		    (m_locations == other.m_locations);
	}

	qint64 m_diId; /*!< Delivery info identifier. */
	QStringList m_locations; /*!< Where the uploaded file is located in the service. */
};

RecMgmt::DiEntry::DiEntry(void)
    : Json::Object(),
    d_ptr(Q_NULLPTR)
{
}

RecMgmt::DiEntry::DiEntry(const DiEntry &other)
    : Json::Object(),
    d_ptr((other.d_func() != Q_NULLPTR) ? (new (::std::nothrow) DiEntryPrivate) : Q_NULLPTR)
{
	Q_D(DiEntry);
	if (d == Q_NULLPTR) {
		return;
	}

	*d = *other.d_func();
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::DiEntry::DiEntry(DiEntry &&other) Q_DECL_NOEXCEPT
    : Json::Object(),
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
    d_ptr(other.d_ptr.release()) //d_ptr(::std::move(other.d_ptr))
#else /* < Qt-5.12 */
    d_ptr(other.d_ptr.take())
#endif /* >= Qt-5.12 */
{
}
#endif /* Q_COMPILER_RVALUE_REFS */

RecMgmt::DiEntry::~DiEntry(void)
{
}

RecMgmt::DiEntry::DiEntry(qint64 diId, const QStringList &locations)
    : Json::Object(),
    d_ptr(new (::std::nothrow) DiEntryPrivate)
{
	Q_D(DiEntry);
	d->m_diId = diId;
	d->m_locations = locations;
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::DiEntry::DiEntry(qint64 diId, QStringList &&locations)
    : Json::Object(),
    d_ptr(new (::std::nothrow) DiEntryPrivate)
{
	Q_D(DiEntry);
	d->m_diId = diId;
	d->m_locations = ::std::move(locations);
}
#endif /* Q_COMPILER_RVALUE_REFS */

/*!
 * @brief Ensures DiEntryPrivate presence.
 *
 * @note Returns if DiEntryPrivate could not be allocated.
 */
#define ensureDiEntryPrivate(_x_) \
	do { \
		if (Q_UNLIKELY(d_ptr == Q_NULLPTR)) { \
			DiEntryPrivate *p = new (::std::nothrow) DiEntryPrivate; \
			if (Q_UNLIKELY(p == Q_NULLPTR)) { \
				Q_ASSERT(0); \
				return _x_; \
			} \
			d_ptr.reset(p); \
		} \
	} while (0)

RecMgmt::DiEntry &RecMgmt::DiEntry::operator=(const DiEntry &other) Q_DECL_NOTHROW
{
	if (other.d_func() == Q_NULLPTR) {
		d_ptr.reset(Q_NULLPTR);
		return *this;
	}
	ensureDiEntryPrivate(*this);
	Q_D(DiEntry);

	*d = *other.d_func();

	return *this;
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::DiEntry &RecMgmt::DiEntry::operator=(DiEntry &&other) Q_DECL_NOTHROW
{
	swap(*this, other);
	return *this;
}
#endif /* Q_COMPILER_RVALUE_REFS */

bool RecMgmt::DiEntry::operator==(const DiEntry &other) const
{
	Q_D(const DiEntry);
	if ((d == Q_NULLPTR) && ((other.d_func() == Q_NULLPTR))) {
		return true;
	} else if ((d == Q_NULLPTR) || ((other.d_func() == Q_NULLPTR))) {
		return false;
	}

	return *d == *other.d_func();
}

bool RecMgmt::DiEntry::operator!=(const DiEntry &other) const
{
	return !operator==(other);
}

void RecMgmt::DiEntry::swap(DiEntry &first, DiEntry &second) Q_DECL_NOTHROW
{
	using ::std::swap;
	swap(first.d_ptr, second.d_ptr);
}

bool RecMgmt::DiEntry::isNull(void) const
{
	Q_D(const DiEntry);
	return d == Q_NULLPTR;
}

bool RecMgmt::DiEntry::isValid(void) const
{
	Q_D(const DiEntry);
	return (!isNull()) && (d->m_diId >= 0);
}

qint64 RecMgmt::DiEntry::diId(void) const
{
	Q_D(const DiEntry);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return NULL_DMID;
	}

	return d->m_diId;
}

void RecMgmt::DiEntry::setDiId(qint64 id)
{
	ensureDiEntryPrivate();
	Q_D(DiEntry);
	d->m_diId = id;
}

const QStringList &RecMgmt::DiEntry::locations(void) const
{
	Q_D(const DiEntry);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullStringList;
	}

	return d->m_locations;
}

void RecMgmt::DiEntry::setLocations(const QStringList &l)
{
	ensureDiEntryPrivate();
	Q_D(DiEntry);
	d->m_locations = l;
}

#ifdef Q_COMPILER_RVALUE_REFS
void RecMgmt::DiEntry::setLocations(QStringList &&l)
{
	ensureDiEntryPrivate();
	Q_D(DiEntry);
	d->m_locations = ::std::move(l);
}
#endif /* Q_COMPILER_RVALUE_REFS */

RecMgmt::DiEntry RecMgmt::DiEntry::fromJson(
    const QByteArray &json, bool *ok)
{
	QJsonObject jsonObj;
	if (Q_UNLIKELY(!Json::Helper::readRootObject(json, jsonObj))) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return DiEntry();
	}

	return fromJsonVal(jsonObj, ok);
}

RecMgmt::DiEntry RecMgmt::DiEntry::fromJsonVal(
    const QJsonValue &jsonVal, bool *ok)
{
	DiEntry e;

	if (Q_UNLIKELY(!jsonVal.isObject())) {
		goto fail;
	}

	{
		const QJsonObject jsonObj = jsonVal.toObject();
		{
			qint64 valQint64;
			if (Json::Helper::readQint64String(jsonObj, keyDiId, valQint64,
			        Json::Helper::ACCEPT_VALID)) {
				e.setDiId(valQint64);
			} else {
				goto fail;
			}
		}
		{
			QStringList valStrList;
			if (Json::Helper::readStringList(jsonObj, keyLocations, valStrList,
			        Json::Helper::ACCEPT_VALID)) {
				e.setLocations(macroStdMove(valStrList));
			} else {
				goto fail;
			}
		}

		if (ok != Q_NULLPTR) {
			*ok = true;
		}
		return e;
	}

fail:
	if (ok != Q_NULLPTR) {
		*ok = false;
	}
	return DiEntry();
}

bool RecMgmt::DiEntry::toJsonVal(QJsonValue &jsonVal) const
{
	QJsonObject jsonObj;

	jsonObj.insert(keyDiId, QString::number(diId()));
	jsonObj.insert(keyLocations, QJsonArray::fromStringList(locations()));

	jsonVal = jsonObj;
	return true;
}

RecMgmt::DiEntryList::DiEntryList(void)
    : Json::Object(),
    QList<DiEntry>()
{
}

RecMgmt::DiEntryList RecMgmt::DiEntryList::fromJson(const QByteArray &json,
    bool *ok)
{
	QJsonArray jsonArr;
	if (Q_UNLIKELY(!Json::Helper::readRootArray(json, jsonArr))) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return DiEntryList();
	}
	return fromJsonVal(jsonArr, ok);
}

RecMgmt::DiEntryList RecMgmt::DiEntryList::fromJsonVal(
    const QJsonValue &jsonVal, bool *ok)
{
	DiEntryList l;

	if (Q_UNLIKELY(!jsonVal.isArray())) {
		goto fail;
	}

	{
		const QJsonArray jsonArr = jsonVal.toArray();
		for (const QJsonValue &v : jsonArr) {
			bool iOk = false;
			l.append(DiEntry::fromJsonVal(v, &iOk));
			if (Q_UNLIKELY(!iOk)) {
				goto fail;
			}
		}
	}

	if (ok != Q_NULLPTR) {
		*ok = true;
	}
	return l;

fail:
	if (ok != Q_NULLPTR) {
		*ok = false;
	}
	return DiEntryList();
}

bool RecMgmt::DiEntryList::toJsonVal(QJsonValue &jsonVal) const
{
	QJsonArray arr;

	for (const DiEntry &e : *this) {
		QJsonValue v;
		if (Q_UNLIKELY(!e.toJsonVal(v))) {
			goto fail;
		}
		arr.append(v);
	}

	jsonVal = arr;
	return true;

fail:
	jsonVal = QJsonArray();
	return false;
}

class RecMgmt::StoredFilesRespPrivate {
public:
	StoredFilesRespPrivate(void)
	    : m_dms(), m_dis(), m_limit(NULL_LIMIT), m_error()
	{ }

	StoredFilesRespPrivate &operator=(const StoredFilesRespPrivate &other) Q_DECL_NOTHROW
	{
		m_dms = other.m_dms;
		m_dis = other.m_dis;
		m_limit = other.m_limit;
		m_error = other.m_error;

		return *this;
	}

	bool operator==(const StoredFilesRespPrivate &other) const
	{
		return (m_dms == other.m_dms) &&
		    (m_dis == other.m_dis) &&
		    (m_limit == other.m_limit) &&
		    (m_error == other.m_error);
	}

	DmEntryList m_dms; /*!< List of received data message entries. */
	DiEntryList m_dis; /*!< List of received delivery info entries. */
	int m_limit; /*!< Request limit, must be greater than zero. */
	ErrorEntry m_error; /*!< Encountered error. */
};

RecMgmt::StoredFilesResp::StoredFilesResp(void)
    : Json::Object(),
    d_ptr(Q_NULLPTR)
{
}

RecMgmt::StoredFilesResp::StoredFilesResp(const StoredFilesResp &other)
    : Json::Object(),
    d_ptr((other.d_func() != Q_NULLPTR) ? (new (::std::nothrow) StoredFilesRespPrivate) : Q_NULLPTR)
{
	Q_D(StoredFilesResp);
	if (d == Q_NULLPTR) {
		return;
	}

	*d = *other.d_func();
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::StoredFilesResp::StoredFilesResp(StoredFilesResp &&other) Q_DECL_NOEXCEPT
    : Json::Object(),
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
    d_ptr(other.d_ptr.release()) //d_ptr(::std::move(other.d_ptr))
#else /* < Qt-5.12 */
    d_ptr(other.d_ptr.take())
#endif /* >= Qt-5.12 */
{
}
#endif /* Q_COMPILER_RVALUE_REFS */

RecMgmt::StoredFilesResp::~StoredFilesResp(void)
{
}

RecMgmt::StoredFilesResp::StoredFilesResp(const DmEntryList &dms,
    const DiEntryList &dis, int limit, const ErrorEntry &error)
    : Json::Object(),
    d_ptr(new (::std::nothrow) StoredFilesRespPrivate)
{
	Q_D(StoredFilesResp);
	d->m_dms = dms;
	d->m_dis = dis;
	d->m_limit = limit;
	d->m_error = error;
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::StoredFilesResp::StoredFilesResp(DmEntryList &&dms, DiEntryList &&dis,
    int limit, ErrorEntry &&error)
    : Json::Object(),
    d_ptr(new (::std::nothrow) StoredFilesRespPrivate)
{
	Q_D(StoredFilesResp);
	d->m_dms = ::std::move(dms);
	d->m_dis = ::std::move(dis);
	d->m_limit = limit;
	d->m_error = ::std::move(error);
}
#endif /* Q_COMPILER_RVALUE_REFS */

/*!
 * @brief Ensures StoredFilesRespPrivate presence.
 *
 * @note Returns if StoredFilesRespPrivate could not be allocated.
 */
#define ensureStoredFilesRespPrivate(_x_) \
	do { \
		if (Q_UNLIKELY(d_ptr == Q_NULLPTR)) { \
			StoredFilesRespPrivate *p = new (::std::nothrow) StoredFilesRespPrivate; \
			if (Q_UNLIKELY(p == Q_NULLPTR)) { \
				Q_ASSERT(0); \
				return _x_; \
			} \
			d_ptr.reset(p); \
		} \
	} while (0)

RecMgmt::StoredFilesResp &RecMgmt::StoredFilesResp::operator=(const StoredFilesResp &other) Q_DECL_NOTHROW
{
	if (other.d_func() == Q_NULLPTR) {
		d_ptr.reset(Q_NULLPTR);
		return *this;
	}
	ensureStoredFilesRespPrivate(*this);
	Q_D(StoredFilesResp);

	*d = *other.d_func();

	return *this;
}

#ifdef Q_COMPILER_RVALUE_REFS
RecMgmt::StoredFilesResp &RecMgmt::StoredFilesResp::operator=(StoredFilesResp &&other) Q_DECL_NOTHROW
{
	swap(*this, other);
	return *this;
}
#endif /* Q_COMPILER_RVALUE_REFS */

bool RecMgmt::StoredFilesResp::operator==(const StoredFilesResp &other) const
{
	Q_D(const StoredFilesResp);
	if ((d == Q_NULLPTR) && ((other.d_func() == Q_NULLPTR))) {
		return true;
	} else if ((d == Q_NULLPTR) || ((other.d_func() == Q_NULLPTR))) {
		return false;
	}

	return *d == *other.d_func();
}

bool RecMgmt::StoredFilesResp::operator!=(const StoredFilesResp &other) const
{
	return !operator==(other);
}

void RecMgmt::StoredFilesResp::swap(StoredFilesResp &first, StoredFilesResp &second) Q_DECL_NOTHROW
{
	using ::std::swap;
	swap(first.d_ptr, second.d_ptr);
}

bool RecMgmt::StoredFilesResp::isNull(void) const
{
	Q_D(const StoredFilesResp);
	return d == Q_NULLPTR;
}

bool RecMgmt::StoredFilesResp::isValid(void) const
{
	Q_D(const StoredFilesResp);
	return (!isNull()) && (d->m_limit > 0) &&
	    (((!d->m_dms.isEmpty()) || (!d->m_dis.isEmpty())) ||
	     (d->m_error.code() != ErrorEntry::ERR_NO_ERROR));
}

const RecMgmt::DmEntryList &RecMgmt::StoredFilesResp::dms(void) const
{
	Q_D(const StoredFilesResp);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullDms;
	}

	return d->m_dms;
}

void RecMgmt::StoredFilesResp::setDms(const DmEntryList &dms)
{
	ensureStoredFilesRespPrivate();
	Q_D(StoredFilesResp);
	d->m_dms = dms;
}

#ifdef Q_COMPILER_RVALUE_REFS
void RecMgmt::StoredFilesResp::setDms(DmEntryList &&dms)
{
	ensureStoredFilesRespPrivate();
	Q_D(StoredFilesResp);
	d->m_dms = ::std::move(dms);
}
#endif /* Q_COMPILER_RVALUE_REFS */

const RecMgmt::DiEntryList &RecMgmt::StoredFilesResp::dis(void) const
{
	Q_D(const StoredFilesResp);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullDis;
	}

	return d->m_dis;
}

void RecMgmt::StoredFilesResp::setDis(const DiEntryList &dis)
{
	ensureStoredFilesRespPrivate();
	Q_D(StoredFilesResp);
	d->m_dis = dis;
}

#ifdef Q_COMPILER_RVALUE_REFS
void RecMgmt::StoredFilesResp::setDis(DiEntryList &&dis)
{
	ensureStoredFilesRespPrivate();
	Q_D(StoredFilesResp);
	d->m_dis = ::std::move(dis);
}
#endif /* Q_COMPILER_RVALUE_REFS */

int RecMgmt::StoredFilesResp::limit(void) const
{
	Q_D(const StoredFilesResp);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return NULL_LIMIT;
	}

	return d->m_limit;
}

void RecMgmt::StoredFilesResp::setLimit(int l)
{
	ensureStoredFilesRespPrivate();
	Q_D(StoredFilesResp);
	d->m_limit = l;
}

const RecMgmt::ErrorEntry &RecMgmt::StoredFilesResp::error(void) const
{
	Q_D(const StoredFilesResp);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullErrorEntry;
	}

	return d->m_error;
}

void RecMgmt::StoredFilesResp::setError(const ErrorEntry &e)
{
	ensureStoredFilesRespPrivate();
	Q_D(StoredFilesResp);
	d->m_error = e;
}

#ifdef Q_COMPILER_RVALUE_REFS
void RecMgmt::StoredFilesResp::setError(ErrorEntry &&e)
{
	ensureStoredFilesRespPrivate();
	Q_D(StoredFilesResp);
	d->m_error = ::std::move(e);
}
#endif /* Q_COMPILER_RVALUE_REFS */

RecMgmt::StoredFilesResp RecMgmt::StoredFilesResp::fromJson(
    const QByteArray &json, bool *ok)
{
	QJsonObject jsonObj;
	if (Q_UNLIKELY(!Json::Helper::readRootObject(json, jsonObj))) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return StoredFilesResp();
	}

	return fromJsonVal(jsonObj, ok);
}

RecMgmt::StoredFilesResp RecMgmt::StoredFilesResp::fromJsonVal(
    const QJsonValue &jsonVal, bool *ok)
{
	StoredFilesResp sfr;

	if (Q_UNLIKELY(!jsonVal.isObject())) {
		goto fail;
	}

	{
		const QJsonObject jsonObj = jsonVal.toObject();
		{
			QJsonArray arr;
			if (Json::Helper::readArray(jsonObj, keyDms, arr,
			        Json::Helper::ACCEPT_VALID)) {
				bool iOk = false;
				sfr.setDms(DmEntryList::fromJsonVal(arr, &iOk));
				if (Q_UNLIKELY(!iOk)) {
					goto fail;
				}
			} else {
				goto fail;
			}
		}
		{
			QJsonArray arr;
			if (Json::Helper::readArray(jsonObj, keyDis, arr,
			        Json::Helper::ACCEPT_VALID)) {
				bool iOk = false;
				sfr.setDis(DiEntryList::fromJsonVal(arr, &iOk));
				if (Q_UNLIKELY(!iOk)) {
					goto fail;
				}
			} else {
				goto fail;
			}
		}
		{
			int readVal = NULL_LIMIT;
			if (Json::Helper::readInt(jsonObj, keyLimit, readVal,
			        Json::Helper::ACCEPT_VALID)) {
				if (Q_UNLIKELY(readVal < 0)) {
					goto fail;
				}
				sfr.setLimit(readVal);
			} else {
				if (ok != Q_NULLPTR) {
					*ok = false;
				}
				return StoredFilesResp();
			}
		}
		{
			QJsonValue jsonVal;
			if (Json::Helper::readValue(jsonObj, keyError, jsonVal,
			        Json::Helper::ACCEPT_NULL)) {
				bool iOk = false;
				sfr.setError(ErrorEntry::fromJsonVal(jsonVal, &iOk));
				if (Q_UNLIKELY(!iOk)) {
					goto fail;
				}
			} else {
				goto fail;
			}
		}

		if (ok != Q_NULLPTR) {
			*ok = true;
		}
		return sfr;
	}

fail:
	if (ok != Q_NULLPTR) {
		*ok = false;
	}
	return StoredFilesResp();
}

bool RecMgmt::StoredFilesResp::toJsonVal(QJsonValue &jsonVal) const
{
	QJsonObject jsonObj;

	{
		QJsonValue jsonVal;
		if (Q_UNLIKELY(!dms().toJsonVal(jsonVal))) {
			goto fail;
		}
		jsonObj.insert(keyDms, jsonVal);
	}
	{
		QJsonValue jsonVal;
		if (Q_UNLIKELY(!dis().toJsonVal(jsonVal))) {
			goto fail;
		}
		jsonObj.insert(keyDis, jsonVal);
	}
	jsonObj.insert(keyLimit, limit());
	{
		QJsonValue jsonVal;
		if (Q_UNLIKELY(!error().toJsonVal(jsonVal))) {
			goto fail;
		}
		jsonObj.insert(keyError, jsonVal);
	}

	jsonVal = jsonObj;
	return true;

fail:
	jsonVal = QJsonObject();
	return false;
}
