/*
 * Copyright (C) 2014-2026 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 <QJsonObject>
#include <QString>
#ifdef QT_QML_LIB
#  include <QQmlEngine> /* qmlRegisterType */
#endif /* QT_QML_LIB */
#include <utility> /* ::std::move, ::std::swap */

#include "src/datovka_shared/compat/compiler.h" /* macroStdMove */
#include "src/datovka_shared/json/basic.h"
#include "src/datovka_shared/json/draft_interface.h"
#include "src/datovka_shared/json/helper.h"

/* Null objects - for convenience. */
static const Json::DmDraft::AttachmentList nullAttachmentList;
static const QByteArray nullByteArray;
static const QString nullString;
static const Isds::Envelope nullEnvelope;
static const QStringList nullStringList;

#define DFLT_BOOL_VAL false
#define DFLT_TXT_FMT -1

/* Attachment */
static const QString keyName("name");
static const QString keyData("data");
static const QString keyPath("path");
static const QString keyCreatedFromText("createdFromText");

/* DmDraft */
static const QString keyDmEnvelope("dmEnvelope");
static const QString keyDmRecipients("dmRecipients");
static const QString keyDmAttachments("dmAttachments");
static const QString keyShortMessageText("shortMessageText");
static const QString keyShortMessageTextFmt("shortMessageTextFmt");
static const QString keyCntrlDowmloadMessage("cntrlDowmloadMessage");
static const QString keyCntrlUploadMessageRm("cntrlUploadMessageRm");

/* Envelope */
static const QString keyDmAnnotation("dmAnnotation");
static const QString keyDmRecipientRefNumber("dmRecipientRefNumber");
static const QString keyDmSenderRefNumber("dmSenderRefNumber");
static const QString keyDmRecipientIdent("dmRecipientIdent");
static const QString keyDmSenderIdent("dmSenderIdent");
static const QString keyDmLegalTitleLaw("dmLegalTitleLaw");
static const QString keyDmLegalTitleYear("dmLegalTitleYear");
static const QString keyDmLegalTitleSect("dmLegalTitleSect");
static const QString keyDmLegalTitlePar("dmLegalTitlePar");
static const QString keyDmLegalTitlePoint("dmLegalTitlePoint");
static const QString keyDmPersonalDelivery("dmPersonalDelivery");
static const QString keyDmAllowSubstDelivery("dmAllowSubstDelivery");
static const QString keyDmToHands("dmToHands");
/* Envelope - outgoing */
static const QString keyDmOVM("dmOVM");
static const QString keyDmType("dmType");
static const QString keyDmPublishOwnID("dmPublishOwnID");
static const QString keyIdLevel("idLevel");

/*!
 * @brief PIMPL Json::DmDraft::Attachment class.
 */
class Json::DmDraft::AttachmentPrivate {
	//Q_DISABLE_COPY(AttachmentPrivate)
public:
	AttachmentPrivate(void)
	    : m_name(), m_data(), m_path(), m_createdFromText(DFLT_BOOL_VAL)
	{ }

	AttachmentPrivate &operator=(const AttachmentPrivate &other) Q_DECL_NOTHROW
	{
		m_name = other.m_name;
		m_data = other.m_data;
		m_path = other.m_path;
		m_createdFromText = other.m_createdFromText;

		return *this;
	}

	bool operator==(const AttachmentPrivate &other) const
	{
		return (m_name == other.m_name)
		    && (m_data == other.m_data)
		    && (m_path == other.m_path)
		    && (m_createdFromText == other.m_createdFromText);
	}

	QString m_name; /*!< Attachment name. */
	QByteArray m_data; /*!< Attachment content. */
	QString m_path; /*!< Path to attachment file. */
	bool m_createdFromText; /*!< File was created from short message text. */
};

Json::DmDraft::Attachment::Attachment(void)
    : Object(),
    d_ptr(Q_NULLPTR)
{
}

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

	*d = *other.d_func();
}

#ifdef Q_COMPILER_RVALUE_REFS
Json::DmDraft::Attachment::Attachment(Attachment &&other) Q_DECL_NOEXCEPT
    : 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 */

Json::DmDraft::Attachment::~Attachment(void)
{
}

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

Json::DmDraft::Attachment &Json::DmDraft::Attachment::operator=(const Attachment &other) Q_DECL_NOTHROW
{
	if (other.d_func() == Q_NULLPTR) {
		d_ptr.reset(Q_NULLPTR);
		return *this;
	}
	ensureAttachmentPrivate(*this);
	Q_D(Attachment);

	*d = *other.d_func();

	return *this;
}

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

bool Json::DmDraft::Attachment::operator==(const Attachment &other) const
{
	Q_D(const Attachment);
	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 Json::DmDraft::Attachment::operator!=(const Attachment &other) const
{
	return !operator==(other);
}

void Json::DmDraft::Attachment::swap(Attachment &first, Attachment &second) Q_DECL_NOTHROW
{
	using ::std::swap;
	swap(first.d_ptr, second.d_ptr);
}

bool Json::DmDraft::Attachment::isNull(void) const
{
	Q_D(const Attachment);
	return d == Q_NULLPTR;
}

const QString &Json::DmDraft::Attachment::name(void) const
{
	Q_D(const Attachment);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullString;
	}
	return d->m_name;
}

void Json::DmDraft::Attachment::setName(const QString &n)
{
	ensureAttachmentPrivate();
	Q_D(Attachment);
	d->m_name = n;
}

#ifdef Q_COMPILER_RVALUE_REFS
void Json::DmDraft::Attachment::setName(QString &&n)
{
	ensureAttachmentPrivate();
	Q_D(Attachment);
	d->m_name = ::std::move(n);
}
#endif /* Q_COMPILER_RVALUE_REFS */

const QByteArray &Json::DmDraft::Attachment::data(void) const
{
	Q_D(const Attachment);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullByteArray;
	}
	return d->m_data;
}

void Json::DmDraft::Attachment::setData(const QByteArray &da)
{
	ensureAttachmentPrivate();
	Q_D(Attachment);
	d->m_data = da;
}

#ifdef Q_COMPILER_RVALUE_REFS
void Json::DmDraft::Attachment::setData(QByteArray &&da)
{
	ensureAttachmentPrivate();
	Q_D(Attachment);
	d->m_data = ::std::move(da);
}
#endif /* Q_COMPILER_RVALUE_REFS */

const QString &Json::DmDraft::Attachment::path(void) const
{
	Q_D(const Attachment);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullString;
	}
	return d->m_path;
}

void Json::DmDraft::Attachment::setPath(const QString &p)
{
	ensureAttachmentPrivate();
	Q_D(Attachment);
	d->m_path = p;
}

#ifdef Q_COMPILER_RVALUE_REFS
void Json::DmDraft::Attachment::setPath(QString &&p)
{
	ensureAttachmentPrivate();
	Q_D(Attachment);
	d->m_path = ::std::move(p);
}
#endif /* Q_COMPILER_RVALUE_REFS */

bool Json::DmDraft::Attachment::createdFromText(void) const
{
	Q_D(const Attachment);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return DFLT_BOOL_VAL;
	}
	return d->m_createdFromText;
}

void Json::DmDraft::Attachment::setCreatedFromText(bool cft)
{
	ensureAttachmentPrivate();
	Q_D(Attachment);
	d->m_createdFromText = cft;
}

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

	return fromJsonVal(jsonObj, ok);
}

Json::DmDraft::Attachment Json::DmDraft::Attachment::fromJsonVal(
    const QJsonValue &jsonVal, bool *ok)
{
	if (Q_UNLIKELY(jsonVal.isNull())) {
		if (ok != Q_NULLPTR) {
			*ok = true;
		}
		return Attachment();
	}

	Attachment at;

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

	{
		const QJsonObject jsonObj = jsonVal.toObject();

		{
			QString valStr;
			if (Helper::readString(jsonObj, keyName, valStr,
			        Helper::ACCEPT_NULL | Helper::ACCEPT_MISSING)) {
				at.setName(macroStdMove(valStr));
			} else {
				goto fail;
			}
		}
		{
			QByteArray valData;
			if (Helper::readBase64DataString(jsonObj, keyData,
			        valData,
			        Helper::ACCEPT_NULL | Helper::ACCEPT_MISSING)) {
				at.setData(macroStdMove(valData));
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (Helper::readString(jsonObj, keyPath, valStr,
			        Helper::ACCEPT_NULL | Helper::ACCEPT_MISSING)) {
				at.setPath(macroStdMove(valStr));
			} else {
				goto fail;
			}
		}
		{
			bool valBool;
			if (Helper::readBool(jsonObj, keyCreatedFromText, valBool,
			        Helper::ACCEPT_NULL | Helper::ACCEPT_MISSING)) {
				at.setCreatedFromText(valBool);
			} else {
				goto fail;
			}
		}
	}

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

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

bool Json::DmDraft::Attachment::toJsonVal(QJsonValue &jsonVal) const
{
	if (Q_UNLIKELY(isNull())) {
		jsonVal = QJsonValue();
		return true;
	}

	QJsonObject jsonObj;

	if (!name().isNull()) {
		jsonObj.insert(keyName, name());
	}
	if (!data().isNull()) {
		jsonObj.insert(keyData, QString::fromUtf8(data().toBase64()));
	}
	if (!path().isNull()) {
		jsonObj.insert(keyPath, path());
	}
	if (createdFromText()) {
		jsonObj.insert(keyCreatedFromText, createdFromText());
	}

	jsonVal = jsonObj;
	return true;
}

Json::DmDraft::AttachmentList::AttachmentList(void)
    : Object(),
    QList<Attachment>()
{
}

Json::DmDraft::AttachmentList::AttachmentList(const QList<Attachment> &other)
   : Object(),
    QList<Attachment>(other)
{
}

#ifdef Q_COMPILER_RVALUE_REFS
Json::DmDraft::AttachmentList::AttachmentList(QList<Attachment> &&other)
    : Object(),
    QList<Attachment>(::std::move(other))
{
}
#endif /* Q_COMPILER_RVALUE_REFS */

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

	return fromJsonVal(jsonArr, ok);
}

Json::DmDraft::AttachmentList Json::DmDraft::AttachmentList::fromJsonVal(
    const QJsonValue &jsonVal, bool *ok)
{
	AttachmentList atl;

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

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

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

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

bool Json::DmDraft::AttachmentList::toJsonVal(QJsonValue &jsonVal) const
{
	QJsonArray arr;

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

	jsonVal = arr;
	return true;

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

/*!
 * @brief PIMPL Json::DmDraft class.
 */
class Json::DmDraftPrivate {
	//Q_DISABLE_COPY(DmDraftPrivate)
public:
	DmDraftPrivate(void)
	    : m_dmEnvelope(), m_dmRecipients(), m_dmAttachments(),
	    m_shortMessageText(), m_shortMessageTextFmt(DFLT_TXT_FMT),
	    m_cntrlDowmloadMessage(DFLT_BOOL_VAL),
	    m_cntrlUploadMessageRm(DFLT_BOOL_VAL)
	{ }

	DmDraftPrivate &operator=(const DmDraftPrivate &other) Q_DECL_NOTHROW
	{
		m_dmEnvelope = other.m_dmEnvelope;
		m_dmRecipients = other.m_dmRecipients;
		m_dmAttachments = other.m_dmAttachments;
		m_shortMessageText = other.m_shortMessageText;
		m_shortMessageTextFmt = other.m_shortMessageTextFmt;
		m_cntrlDowmloadMessage = other.m_cntrlDowmloadMessage;
		m_cntrlUploadMessageRm = other.m_cntrlUploadMessageRm;

		return *this;
	}

	bool operator==(const DmDraftPrivate &other) const
	{
		return (m_dmEnvelope == other.m_dmEnvelope) &&
		    (m_dmRecipients == other.m_dmRecipients) &&
		    (m_dmAttachments == other.m_dmAttachments) &&
		    (m_shortMessageText == other.m_shortMessageText) &&
		    (m_shortMessageTextFmt == other.m_shortMessageTextFmt) &&
		    (m_cntrlDowmloadMessage == other.m_cntrlDowmloadMessage) &&
		    (m_cntrlUploadMessageRm == other.m_cntrlUploadMessageRm);
	}

	Isds::Envelope m_dmEnvelope;
	QStringList m_dmRecipients;
	DmDraft::AttachmentList m_dmAttachments;
	QString m_shortMessageText;
	int m_shortMessageTextFmt;
	bool m_cntrlDowmloadMessage;
	bool m_cntrlUploadMessageRm;
};

void Json::DmDraft::declareTypes(void)
{
#ifdef QT_QML_LIB
	qmlRegisterType<DmDraft>("cz.nic.mobileDatovka.draft", 1, 0, "DmDraft");
#endif /* QT_QML_LIB */
	qRegisterMetaType<DmDraft>("DmDraft");

	qRegisterMetaType<DmDraft::Attachment>("DmDraft::Attachment");
	qRegisterMetaType<DmDraft::AttachmentList>("DmDraft::AttachmentList");
	/*
	 * Calling qRegisterMetaType() with the pointer types enables automatic
	 * conversion of QML object (QVariants) to respective pointers.
	 */
	qRegisterMetaType<DmDraft *>("DmDraft *");
	qRegisterMetaType<DmDraft *>("const DmDraft *");

	/* TODO -- Declare enevelope directlry from envelope. */
	qRegisterMetaType<Isds::Envelope>("Envelope");
}

Json::DmDraft::DmDraft(void)
    : Object(),
    d_ptr(Q_NULLPTR)
{
}

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

	*d = *other.d_func();
}

#ifdef Q_COMPILER_RVALUE_REFS
Json::DmDraft::DmDraft(DmDraft &&other) Q_DECL_NOEXCEPT
    : 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 */

Json::DmDraft::~DmDraft(void)
{
}

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

Json::DmDraft &Json::DmDraft::operator=(const DmDraft &other) Q_DECL_NOTHROW
{
	if (other.d_func() == Q_NULLPTR) {
		d_ptr.reset(Q_NULLPTR);
		return *this;
	}
	ensureDmDraftPrivate(*this);
	Q_D(DmDraft);

	*d = *other.d_func();

	return *this;
}

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

bool Json::DmDraft::operator==(const DmDraft &other) const
{
	Q_D(const DmDraft);
	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 Json::DmDraft::operator!=(const DmDraft &other) const
{
	return !operator==(other);
}

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

bool Json::DmDraft::isNull(void) const
{
	Q_D(const DmDraft);
	return d == Q_NULLPTR;
}

const Isds::Envelope &Json::DmDraft::dmEnvelope(void) const
{
	Q_D(const DmDraft);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullEnvelope;
	}
	return d->m_dmEnvelope;
}

void Json::DmDraft::setDmEnvelope(const Isds::Envelope &e)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_dmEnvelope = e;
}

#ifdef Q_COMPILER_RVALUE_REFS
void Json::DmDraft::setDmEnvelope(Isds::Envelope &&e)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_dmEnvelope = ::std::move(e);
}
#endif /* Q_COMPILER_RVALUE_REFS */

const QStringList &Json::DmDraft::dmRecipients(void) const
{
	Q_D(const DmDraft);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullStringList;
	}
	return d->m_dmRecipients;
}

void Json::DmDraft::setDmRecipients(const QStringList &rl)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_dmRecipients = rl;
}

#ifdef Q_COMPILER_RVALUE_REFS
void Json::DmDraft::setDmRecipients(QStringList &&rl)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_dmRecipients = ::std::move(rl);
}
#endif /* Q_COMPILER_RVALUE_REFS */

const Json::DmDraft::AttachmentList &Json::DmDraft::dmAttachments(void) const
{
	Q_D(const DmDraft);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullAttachmentList;
	}
	return d->m_dmAttachments;
}

void Json::DmDraft::setDmAttachments(const AttachmentList &al)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_dmAttachments = al;
}

#ifdef Q_COMPILER_RVALUE_REFS
void Json::DmDraft::setDmAttachments(AttachmentList &&al)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_dmAttachments = ::std::move(al);
}
#endif /* Q_COMPILER_RVALUE_REFS */

const QString &Json::DmDraft::shortMessageText(void) const
{
	Q_D(const DmDraft);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return nullString;
	}
	return d->m_shortMessageText;
}

void Json::DmDraft::setShortMessageText(const QString &smt)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_shortMessageText = smt;
}

#ifdef Q_COMPILER_RVALUE_REFS
void Json::DmDraft::setShortMessageText(QString &&smt)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_shortMessageText = ::std::move(smt);
}
#endif /* Q_COMPILER_RVALUE_REFS */

qint64 Json::DmDraft::shortMessageTextFmt(void) const
{
	Q_D(const DmDraft);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return DFLT_TXT_FMT;
	}
	return d->m_shortMessageTextFmt;
}

void Json::DmDraft::setShortMessageTextFmt(qint64 smtf)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_shortMessageTextFmt = (smtf >= 0) ? smtf : DFLT_TXT_FMT;
}

bool Json::DmDraft::cntrlDowmloadMessage(void) const
{
	Q_D(const DmDraft);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return DFLT_BOOL_VAL;
	}
	return d->m_cntrlDowmloadMessage;
}

void Json::DmDraft::setCntrlDowmloadMessage(bool cdm)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_cntrlDowmloadMessage = cdm;
}

bool Json::DmDraft::cntrlUploadMessageRm(void) const
{
	Q_D(const DmDraft);
	if (Q_UNLIKELY(d == Q_NULLPTR)) {
		return DFLT_BOOL_VAL;
	}
	return d->m_cntrlUploadMessageRm;
}

void Json::DmDraft::setCntrlUploadMessageRm(bool cum)
{
	ensureDmDraftPrivate();
	Q_D(DmDraft);
	d->m_cntrlUploadMessageRm = cum;
}

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

	return fromJsonVal(jsonObj, ok);
}

/*!
 * @brief Convert JSON value to envelope.
 */
static
Isds::Envelope envelopeFromJsonVal(const QJsonValue &jsonVal, bool *ok)
{
	Isds::Envelope env;

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

	{
		const QJsonObject jsonObj = jsonVal.toObject();

		{
			QString valStr;
			if (::Json::Helper::readString(jsonObj, keyDmAnnotation,
			        valStr,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmAnnotation(valStr);
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (::Json::Helper::readString(jsonObj,
			        keyDmRecipientRefNumber, valStr,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmRecipientRefNumber(valStr);
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (::Json::Helper::readString(jsonObj,
			        keyDmSenderRefNumber, valStr,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmSenderRefNumber(valStr);
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (::Json::Helper::readString(jsonObj,
			        keyDmRecipientIdent, valStr,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmRecipientIdent(valStr);
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (::Json::Helper::readString(jsonObj,
			        keyDmSenderIdent, valStr,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmSenderIdent(valStr);
			} else {
				goto fail;
			}
		}
		{
			int valInt = 0;
			if (::Json::Helper::readInt(jsonObj,
			        keyDmLegalTitleLaw, valInt,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmLegalTitleLaw(valInt);
			} else {
				goto fail;
			}
		}
		{
			int valInt = 0;
			if (::Json::Helper::readInt(jsonObj,
			        keyDmLegalTitleYear, valInt,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmLegalTitleYear(valInt);
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (::Json::Helper::readString(jsonObj,
			        keyDmLegalTitleSect, valStr,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmLegalTitleSect(valStr);
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (::Json::Helper::readString(jsonObj,
			        keyDmLegalTitlePar, valStr,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmLegalTitlePar(valStr);
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (::Json::Helper::readString(jsonObj,
			        keyDmLegalTitlePoint, valStr,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmLegalTitlePoint(valStr);
			} else {
				goto fail;
			}
		}
		{
			enum Isds::Type::NilBool valNilBool = Isds::Type::BOOL_NULL;
			if (::Json::Helper::readNilBool(jsonObj,
			        keyDmPersonalDelivery, valNilBool,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmPersonalDelivery(valNilBool);
			} else {
				goto fail;
			}
		}
		{
			enum Isds::Type::NilBool valNilBool = Isds::Type::BOOL_NULL;
			if (::Json::Helper::readNilBool(jsonObj,
			        keyDmAllowSubstDelivery, valNilBool,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmAllowSubstDelivery(valNilBool);
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (::Json::Helper::readString(jsonObj, keyDmToHands,
			        valStr,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmToHands(valStr);
			} else {
				goto fail;
			}
		}
		{
			enum Isds::Type::NilBool valNilBool = Isds::Type::BOOL_NULL;
			if (::Json::Helper::readNilBool(jsonObj, keyDmOVM,
			        valNilBool,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmOVM(valNilBool);
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (::Json::Helper::readString(jsonObj, keyDmType,
			        valStr,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				if (!valStr.isEmpty()) {
					env.setDmType(valStr.at(0));
				}
			} else {
				goto fail;
			}
		}
		{
			enum Isds::Type::NilBool valNilBool = Isds::Type::BOOL_NULL;
			if (::Json::Helper::readNilBool(jsonObj,
			        keyDmPublishOwnID, valNilBool,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setDmPublishOwnID(valNilBool);
			} else {
				goto fail;
			}
		}
		{
			int valInt = 0;
			if (::Json::Helper::readInt(jsonObj, keyIdLevel,
			        valInt,
			        ::Json::Helper::ACCEPT_NULL | ::Json::Helper::ACCEPT_MISSING)) {
				env.setIdLevel(valInt);
			} else {
				goto fail;
			}
		}
	}

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

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

Json::DmDraft Json::DmDraft::fromJsonVal(const QJsonValue &jsonVal,
    bool *ok)
{
	if (Q_UNLIKELY(jsonVal.isNull())) {
		if (ok != Q_NULLPTR) {
			*ok = true;
		}
		return DmDraft();
	}

	DmDraft dmCon;

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

	{
		const QJsonObject jsonObj = jsonVal.toObject();

		{
			QJsonValue jsonVal;
			if (Helper::readValue(jsonObj, keyDmEnvelope,
			        jsonVal,
			        Helper::ACCEPT_NULL | Helper::ACCEPT_MISSING )) {
				bool iOk = false;
				dmCon.setDmEnvelope(envelopeFromJsonVal(jsonVal, &iOk));
				if (Q_UNLIKELY(!iOk)) {
					goto fail;
				}
			} else {
				goto fail;
			}
		}
		{
			QStringList list;
			if (Helper::readStringList(jsonObj, keyDmRecipients,
			        list,
			        Helper::ACCEPT_NULL | Helper::ACCEPT_MISSING)) {
				dmCon.setDmRecipients(list);
			} else {
				goto fail;
			}
		}
		{
			QJsonArray arr;
			if (Helper::readArray(jsonObj, keyDmAttachments, arr,
			        Helper::ACCEPT_NULL | Helper::ACCEPT_MISSING)) {
				bool iOk = false;
				dmCon.setDmAttachments(AttachmentList::fromJsonVal(arr, &iOk));
				if (Q_UNLIKELY(!iOk)) {
					goto fail;
				}
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (Helper::readString(jsonObj, keyShortMessageText,
			        valStr,
			        Helper::ACCEPT_NULL | Helper::ACCEPT_MISSING)) {
				dmCon.setShortMessageText(valStr);
			} else {
				goto fail;
			}
		}
		{
			int valInt = -1;
			if (Helper::readInt(jsonObj,
			        keyShortMessageTextFmt, valInt,
			        Helper::ACCEPT_NULL | Helper::ACCEPT_MISSING)) {
				dmCon.setShortMessageTextFmt(valInt);
			} else {
				goto fail;
			}
		}
		{
			bool valBool;
			if (Helper::readBool(jsonObj, keyCntrlDowmloadMessage, valBool,
			        Helper::ACCEPT_VALID)) {
				dmCon.setCntrlDowmloadMessage(valBool);
			} else {
				goto fail;
			}
		}
		{
			bool valBool;
			if (Helper::readBool(jsonObj, keyCntrlUploadMessageRm, valBool,
			        Helper::ACCEPT_VALID)) {
				dmCon.setCntrlUploadMessageRm(valBool);
			} else {
				goto fail;
			}
		}
	}

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

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

bool Json::DmDraft::toJsonVal(QJsonValue &jsonVal) const
{
	if (Q_UNLIKELY(isNull())) {
		jsonVal = QJsonValue();
		return true;
	}

	QJsonObject jsonObj;

	{
		QJsonObject jsonObjEnv;

		if (!dmEnvelope().dmAnnotation().isEmpty()) {
			jsonObjEnv.insert(keyDmAnnotation,
			    dmEnvelope().dmAnnotation());
		}
		if (!dmEnvelope().dmRecipientRefNumber().isEmpty()) {
			jsonObjEnv.insert(keyDmRecipientRefNumber,
			    dmEnvelope().dmRecipientRefNumber());
		}
		if (!dmEnvelope().dmSenderRefNumber().isEmpty()) {
			jsonObjEnv.insert(keyDmSenderRefNumber,
			    dmEnvelope().dmSenderRefNumber());
		}
		if (!dmEnvelope().dmRecipientIdent().isEmpty()) {
			jsonObjEnv.insert(keyDmRecipientIdent,
			    dmEnvelope().dmRecipientIdent());
		}
		if (!dmEnvelope().dmSenderIdent().isEmpty()) {
			jsonObjEnv.insert(keyDmSenderIdent,
			    dmEnvelope().dmSenderIdent());
		}

		if (dmEnvelope().dmLegalTitleLaw() >= 0) {
			jsonObjEnv.insert(keyDmLegalTitleLaw, dmEnvelope().dmLegalTitleLaw());
		}
		if (dmEnvelope().dmLegalTitleYear() >= 0) {
			jsonObjEnv.insert(keyDmLegalTitleYear, dmEnvelope().dmLegalTitleYear());
		}
		if (!dmEnvelope().dmLegalTitleSect().isEmpty()) {
			jsonObjEnv.insert(keyDmLegalTitleSect,
			    dmEnvelope().dmLegalTitleSect());
		}
		if (!dmEnvelope().dmLegalTitlePar().isEmpty()) {
			jsonObjEnv.insert(keyDmLegalTitlePar,
			    dmEnvelope().dmLegalTitlePar());
		}
		if (!dmEnvelope().dmLegalTitlePoint().isEmpty()) {
			jsonObjEnv.insert(keyDmLegalTitlePoint,
			    dmEnvelope().dmLegalTitlePoint());
		}

		if (dmEnvelope().dmPersonalDelivery() != Isds::Type::BOOL_NULL) {
			jsonObjEnv.insert(keyDmPersonalDelivery,
			    (dmEnvelope().dmPersonalDelivery() != Isds::Type::BOOL_NULL)
			        ? QJsonValue(dmEnvelope().dmPersonalDelivery() == Isds::Type::BOOL_TRUE)
			        : QJsonValue());
		}
		if (dmEnvelope().dmAllowSubstDelivery() != Isds::Type::BOOL_NULL) {
			jsonObjEnv.insert(keyDmAllowSubstDelivery,
			    (dmEnvelope().dmAllowSubstDelivery() != Isds::Type::BOOL_NULL)
			        ? QJsonValue(dmEnvelope().dmAllowSubstDelivery() == Isds::Type::BOOL_TRUE)
			        : QJsonValue());
		}
		if (!dmEnvelope().dmToHands().isEmpty()) {
			jsonObjEnv.insert(keyDmToHands, dmEnvelope().dmToHands());
		}

		if (dmEnvelope().dmOVM() != Isds::Type::BOOL_NULL) {
			jsonObjEnv.insert(keyDmOVM,
			    (dmEnvelope().dmOVM() != Isds::Type::BOOL_NULL)
			        ? QJsonValue(dmEnvelope().dmOVM() == Isds::Type::BOOL_TRUE)
			        : QJsonValue());
		}
		if (!dmEnvelope().dmType().isNull()) {
			jsonObjEnv.insert(keyDmType, QString(dmEnvelope().dmType()));
		}
		if (dmEnvelope().dmPublishOwnID() != Isds::Type::BOOL_NULL) {
			jsonObjEnv.insert(keyDmPublishOwnID,
			    (dmEnvelope().dmPublishOwnID() != Isds::Type::BOOL_NULL)
			        ? QJsonValue(dmEnvelope().dmPublishOwnID() == Isds::Type::BOOL_TRUE)
			        : QJsonValue());
		}
		if (dmEnvelope().idLevel() != Isds::Type::IDLEV_NULL) {
			jsonObjEnv.insert(keyIdLevel, dmEnvelope().idLevel());
		}

		jsonObj.insert(keyDmEnvelope, jsonObjEnv);
	}

	if (!dmRecipients().isEmpty()) {
		jsonObj.insert(keyDmRecipients,
		    QJsonArray::fromStringList(dmRecipients()));
	}

	if (!dmAttachments().isEmpty()) {
		QJsonValue jsonVal;
		if (Q_UNLIKELY(!dmAttachments().toJsonVal(jsonVal))) {
			goto fail;
		}
		jsonObj.insert(keyDmAttachments, jsonVal);
	}

	if (!shortMessageText().isEmpty()) {
		jsonObj.insert(keyShortMessageText, shortMessageText());
	}
	if (shortMessageTextFmt() >= 0) {
		jsonObj.insert(keyShortMessageTextFmt, shortMessageTextFmt());
	}

	jsonObj.insert(keyCntrlDowmloadMessage, cntrlDowmloadMessage());
	jsonObj.insert(keyCntrlUploadMessageRm, cntrlUploadMessageRm());

	jsonVal = jsonObj;
	return true;

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