{{>licenseInfo}}{{#models}}{{#model}}
#include "{{classFilename}}.h"
#include "{{prefixLowerCase}}helpers.h"

using namespace Qt::StringLiterals;
{{#cppCommonNamespaceDeclarations}}
using namespace {{this}};
{{/cppCommonNamespaceDeclarations}}

{{#cppNamespaceDeclarations}}
namespace {{this}} {
{{/cppNamespaceDeclarations}}
{{#composedSchemas.oneOf}}

{{classname}}::{{classname}}({{#complexType}}const {{/complexType}}{{{dataType}}} {{#complexType}}&{{/complexType}}value)
{
    {{setter}}(value);
}
{{/composedSchemas.oneOf}}
{{^composedSchemas}}
{{classname}}::{{classname}}(const QString &json)
{
    this->initializeModel();
    this->fromJson(json);
}
{{/composedSchemas}}

{{classname}}::{{classname}}()
{
    this->initializeModel();
}

{{classname}}::~{{classname}}()
{
}

void {{classname}}::initializeModel()
{
{{^isEnum}}
{{^composedSchemas}}
{{#vars}}
    m_{{name}} = {};
{{#complexType}}
{{^isContainer}}
    m_{{name}}IsValid = m_{{name}}.isValid();
    m_{{name}}IsSet = false;
{{/isContainer}}
{{#isContainer}}
    m_{{name}}IsSet = false;
    m_{{name}}IsValid = !{{{required}}};
{{/isContainer}}
{{/complexType}}
{{^complexType}}
{{#isFreeFormObject}}
    m_{{name}}IsValid = m_{{name}}.isValid();
    m_{{name}}IsSet = false;
{{/isFreeFormObject}}
{{^isFreeFormObject}}
    m_{{name}}IsSet = false;
    // If value isn't set AND isn't required
    // it's counted as valid
    m_{{name}}IsValid = !{{{required}}};
{{/isFreeFormObject}}
{{/complexType}}
{{^-last}}

{{/-last}}
{{/vars}}
{{/composedSchemas}}
{{#composedSchemas.oneOf}}
{{#-first}}
    // by default, set std::monostate{}
    m_oneOf = std::monostate{};

    // By default, a oneOf-object holds no value and is equivalent to std::monostate.
    // Therefore, all isSet and isValid properties are false. Even if all properties
    // are optional, the object is not considered valid until it is set.
{{/-first}}
    m_{{name}}IsValid = false;
    m_{{name}}IsSet = false;

{{/composedSchemas.oneOf}}
{{/isEnum}}
{{#isEnum}}
    m_valueIsSet = false;
    m_valueIsValid = false;
    m_value = e{{classname}}::INVALID_VALUE_OPENAPI_GENERATED;
{{/isEnum}}
}

void {{classname}}::fromJson(const QString &jsonString)
{
{{^isEnum}}
    this->fromJsonValue(QJsonValue::fromJson(jsonString.toUtf8()));
{{/isEnum}}
{{#isEnum}}
{{#allowableValues}}
{{#enumVars}}
    {{#-first}}if{{/-first}}{{^-first}}else if{{/-first}} (jsonString.compare({{#isString}}u"{{value}}"_s{{/isString}}{{^isString}}QString::number({{value}}){{/isString}}, Qt::CaseInsensitive) == 0) {
        m_value = e{{classname}}::{{name}};
        m_valueIsSet = m_valueIsValid = true;
    }{{#-last}} else {
        m_value = e{{classname}}::INVALID_VALUE_OPENAPI_GENERATED;
        m_valueIsSet = m_valueIsValid = false;
    }{{/-last}}
{{/enumVars}}
{{/allowableValues}}
{{/isEnum}}
}

void {{classname}}::fromJsonValue(const QJsonValue &json)
{
{{^isEnum}}
    Q_UNUSED(json);
{{^composedSchemas}}
    if (!json.isObject() || json.toObject().isEmpty()) {
        initializeModel();
        return;
    }
    const QJsonObject jsonObject = json.toObject();
{{#vars}}
{{#complexType}}
{{^isContainer}}
{{#isModel}}
    {
        const QJsonValue modelValue = jsonObject[u"{{baseName}}"_s];
        if (modelValue.isObject()) {
            ::{{cppCommonNamespace}}::fromJsonValue(m_{{name}}, modelValue);
            m_{{name}}IsValid = m_{{name}}.isValid();
            // NOTE: An empty JSON object is still a valid value
            // for models without required properties.
            // Users may intentionally set it for specific reasons.
            m_{{name}}IsSet = m_{{name}}.isSet() || (m_{{name}}IsValid && modelValue.toObject().isEmpty());
        } else {
            m_{{name}} = {};
            m_{{name}}IsValid = m_{{name}}.isValid();
            m_{{name}}IsSet = false;
        }
    }
{{/isModel}}
{{^isModel}}
    {
        const bool result = ::{{cppCommonNamespace}}::fromJsonValue(m_{{name}}, jsonObject[u"{{baseName}}"_s]);
        if (result) {
            m_{{name}}IsValid = m_{{name}}IsSet = {{#isEnumRef}}m_{{name}}.isSet(){{/isEnumRef}}{{^isEnumRef}}result{{/isEnumRef}};
        } else {
            m_{{name}}IsValid = !{{required}};
            m_{{name}}IsSet = result;
        }
    }
{{/isModel}}
{{/isContainer}}
{{#isContainer}}
{{^items.isContainer}}
    if (jsonObject[u"{{baseName}}"_s].isArray() || jsonObject[u"{{baseName}}"_s].isObject()) {
        m_{{name}}IsValid = ::{{cppCommonNamespace}}::fromJsonValue(m_{{name}}, jsonObject[u"{{baseName}}"_s]);
        m_{{name}}IsSet = !jsonObject[u"{{baseName}}"_s].isNull() && m_{{name}}IsValid;
    }
{{/items.isContainer}}
{{#isArray}}
{{#items.isContainer}}
    if (jsonObject[u"{{baseName}}"_s].isArray()) {
        const auto arr = jsonObject[u"{{baseName}}"_s].toArray();
        m_{{name}}IsValid = true;
        if (arr.size() == 0)
            m_{{name}}IsSet = true;

        for (const QJsonValue &jval : arr) {
{{#items.isArray}}
            if (!jval.isArray()) {
{{/items.isArray}}
{{#items.isMap}}
            if (!jval.isObject()) {
{{/items.isMap}}
                m_{{name}}.clear();
                m_{{name}}IsValid = !{{required}};
                m_{{name}}IsSet = false;
                break;
            }

            {{{items.dataType}}} item;
            const bool result = ::{{cppCommonNamespace}}::fromJsonValue(item, jval);
            if (result) {
                m_{{name}}IsValid = m_{{name}}IsSet = result;
            } else {
                m_{{name}}IsValid = !{{required}};
                m_{{name}}IsSet = result;
                m_{{name}}.clear();
                break;
            }
            m_{{name}}.push_back(item);
        }
    }
{{/items.isContainer}}
{{/isArray}}
{{#isMap}}
{{#items.isContainer}}
    if (jsonObject[u"{{baseName}}"_s].isObject()) {
        const auto varmap = jsonObject[u"{{baseName}}"_s].toObject().toVariantMap();
        m_{{name}}IsValid = true;
        if (varmap.size() == 0)
            m_{{name}}IsSet = true;

        for (const auto &[key, value] : varmap.asKeyValueRange()) {
{{#items.isArray}}
            if (!value.canConvert<QJsonValue>()) {
{{/items.isArray}}
{{#items.isMap}}
            if (!value.canConvert<QVariantMap>()) {
{{/items.isMap}}
                m_{{name}}.clear();
                m_{{name}}IsValid = !{{{required}}};
                m_{{name}}IsSet = false;
                break;
            }

            {{{items.dataType}}} item;
            const auto jval = QJsonValue::fromVariant(value);
            const bool result = ::{{cppCommonNamespace}}::fromJsonValue(item, jval);
            if (result) {
                m_{{name}}IsValid = m_{{name}}IsSet = result;
            } else {
                m_{{name}}IsValid = !{{required}};
                m_{{name}}IsSet = result;
                m_{{name}}.clear();
                break;
            }
            m_{{name}}.insert(key, item);
        }
    }
{{/items.isContainer}}
{{/isMap}}
    else { // fallback for wrong data type
        m_{{name}}.clear();
        m_{{name}}IsValid = !{{required}};
        m_{{name}}IsSet = false;
    }
{{/isContainer}}
{{/complexType}}
{{^complexType}}
{{#isFreeFormObject}}
    {
        const QJsonValue modelValue = jsonObject[u"{{baseName}}"_s];
        if (modelValue.isObject()) {
            ::{{cppCommonNamespace}}::fromJsonValue(m_{{name}}, modelValue);
            m_{{name}}IsValid = m_{{name}}.isValid();
            // NOTE: An empty JSON object is still a valid value
            // for models without required properties.
            // Users may intentionally set it for specific reasons.
            m_{{name}}IsSet = m_{{name}}.isSet() || (m_{{name}}IsValid && modelValue.toObject().isEmpty());
        } else {
            m_{{name}} = {};
            m_{{name}}IsValid = m_{{name}}.isValid();
            m_{{name}}IsSet = false;
        }
    }
{{/isFreeFormObject}}
{{^isFreeFormObject}}
    {
        const bool result = ::{{cppCommonNamespace}}::fromJsonValue(m_{{name}}, jsonObject[u"{{baseName}}"_s]);
        if (result) {
            m_{{name}}IsValid = m_{{name}}IsSet = result;
        } else {
            m_{{name}}IsValid = !{{required}};
            m_{{name}}IsSet = result;
        }
    }
{{/isFreeFormObject}}
{{/complexType}}
{{/vars}}
{{/composedSchemas}}
{{#composedSchemas.oneOf}}
{{#-first}}
    // Reset current one
    initializeModel();
    if (json.isUndefined())
        return;

{{/-first}}
{{#complexType}}
{{^isContainer}}
    {
        {{{dataType}}} {{name}}Value;
        {{name}}Value.fromJsonValue(json);
        m_{{name}}IsValid = {{name}}Value.isValid();
        m_{{name}}IsSet = {{name}}Value.isSet() || (m_{{name}}IsValid && json.isObject() && json.toObject().isEmpty());
        if (m_{{name}}IsSet) {
            m_oneOf = {{name}}Value;
            // 'oneOf' means only one from model properties can be VALID.
            // Two and more cannot be valid! => so, return here.
            if (m_{{name}}IsValid)
                return;
        } else {
            m_{{name}}IsValid = m_{{name}}IsSet = false;
        }
    }
{{/isContainer}}
{{#isContainer}}
{{#items.isModel}}
{{#isArray}}
    if (json.isArray()) {
        {{{dataType}}} {{name}}Value;
        // isArray!
        const auto arr = json.toArray();
        m_{{name}}IsValid = true;
        if (arr.size() == 0)
            m_{{name}}IsSet = true;
        for (const QJsonValue &jval : arr) {
{{/isArray}}
{{#isMap}}
    if (json.isObject()) {
        {{{dataType}}} {{name}}Value;
        const auto mapContainer = json.toObject().toVariantMap();
        m_{{name}}IsValid = true;
        if (mapContainer.size() == 0)
            m_{{name}}IsSet = true;
        for (const auto &[key, value] : mapContainer.asKeyValueRange()) {
            const auto jval = QJsonValue::fromVariant(value);
{{/isMap}}
            {{{items.dataType}}} item;
            m_{{name}}IsValid = ::{{cppCommonNamespace}}::fromJsonValue(item, jval);
            if (!m_{{name}}IsValid) {
                m_{{name}}IsSet = false;
                m_oneOf = std::monostate{};
                return;
            }
            m_{{name}}IsSet = item.isSet() || m_{{name}}IsValid;
{{#isArray}}
            {{name}}Value.append(item);
{{/isArray}}
{{#isMap}}
            {{name}}Value.insert(key, item);
{{/isMap}}
        }
        m_oneOf = {{name}}Value;
{{/items.isModel}}
{{^items.isModel}}
    if (json.isArray() || json.isObject()) {
        {{{dataType}}} {{name}}Value;
        m_{{name}}IsValid = ::{{cppCommonNamespace}}::fromJsonValue({{name}}Value, json);
        if (m_{{name}}IsValid) {
            m_oneOf = {{name}}Value;
            m_{{name}}IsSet = m_{{name}}IsValid;
            // 'oneOf' means only one from model properties can be VALID.
            // Two and more cannot be valid! => so, return here.
            return;
        }
        m_{{name}}IsSet = false;
{{/items.isModel}}
    }
{{/isContainer}}
{{/complexType}}
{{^complexType}}
{{#isFreeFormObject}}
    {
        {{{dataType}}} {{name}}Value;
        {{name}}Value.fromJsonValue(json);
        m_{{name}}IsValid = {{name}}Value.isValid();
        m_{{name}}IsSet = {{name}}Value.isSet() || (m_{{name}}IsValid && json.isObject() && json.toObject().isEmpty());
        if (m_{{name}}IsSet) {
            m_oneOf = {{name}}Value;
            // 'oneOf' means only one from model properties can be VALID.
            // Two and more cannot be valid! => so, return here.
            if (m_{{name}}IsValid)
                return;
        } else {
            m_{{name}}IsValid = m_{{name}}IsSet = false;
        }
    }
{{/isFreeFormObject}}
{{/complexType}}
{{#isPrimitiveType}}
{{#isString}}
    if (json.isString()) {
{{/isString}}
{{#isByteArray}}
    if (json.isString()) {
{{/isByteArray}}
{{#isNumeric}}
    if (json.isDouble()) {
{{/isNumeric}}
{{#isBoolean}}
    if (json.isBool()) {
{{/isBoolean}}
        {{{dataType}}} {{name}}Value;
        m_{{name}}IsValid = ::{{cppCommonNamespace}}::fromJsonValue({{name}}Value, json);
        if (m_{{name}}IsValid) {
            m_oneOf = {{name}}Value;
            m_{{name}}IsSet = m_{{name}}IsValid;
            // 'oneOf' means only one from model properties can be VALID.
            // Two and more cannot be valid! => so, return here.
            return;
        }
        m_{{name}}IsSet = false;
    }
{{/isPrimitiveType}}
{{^-last}}

{{/-last}}
{{/composedSchemas.oneOf}}
{{/isEnum}}
{{#isEnum}}
{{#allowableValues}}
{{#enumVars}}
{{#-first}}
{{#isString}}
    fromJson(json.toString());
{{/isString}}
{{^isString}}
    m_value = static_cast<e{{classname}}>(json.toInt());
{{/isString}}
{{/-first}}
{{/enumVars}}
{{/allowableValues}}
{{/isEnum}}
}

QString {{classname}}::asJson() const
{
{{^isEnum}}
    return QString::fromUtf8(this->asJsonValue().toJson(QJsonDocument::Compact));
{{/isEnum}}
{{#isEnum}}
    QString val;
{{#allowableValues}}
    switch (m_value) {
{{#enumVars}}
        case e{{classname}}::{{name}}:
            val = {{#isString}}u"{{value}}"_s{{/isString}}{{^isString}}QString::number({{value}}){{/isString}};
            break;{{#-last}}
        default:
            break;{{/-last}}
{{/enumVars}}
    }
{{/allowableValues}}
    return val;
{{/isEnum}}
}

QJsonValue {{classname}}::asJsonValue() const
{
{{^isEnum}}
{{^composedSchemas}}
    QJsonObject obj;
{{#vars}}
    if (m_{{name}}IsSet) {
        obj.insert(u"{{baseName}}"_s, ::{{cppCommonNamespace}}::toJsonValue(m_{{name}}));
    }
{{/vars}}
    return obj;
{{/composedSchemas}}
{{#composedSchemas}}
{{#oneOf}}
    {
        const auto *value = std::get_if<{{{dataType}}}>(&m_oneOf);
        if (value && m_{{name}}IsSet && m_{{name}}IsValid)
{{#complexType}}
{{^isContainer}}
            return value->asJsonValue();
{{/isContainer}}
{{#isContainer}}
            return ::{{cppCommonNamespace}}::toJsonValue(*value);
{{/isContainer}}
{{/complexType}}
{{^complexType}}
{{#isFreeFormObject}}
            return value->asJsonValue();
{{/isFreeFormObject}}
{{^isFreeFormObject}}
            return QJsonValue(*value);
{{/isFreeFormObject}}
{{/complexType}}
    }
{{/oneOf}}
    // Here we need to return something, if oneOf value was not set at all.
    // An empty QJsonValue() returns 'null' via ::toJson(QJsonDocument::Compact)
    // But 'null' has a special meaning in OpenAPI, so we cannot used it for this case.
    // There is no correct way to handle such situation in OpenAPI spec,
    // it is an implementation detail we should decide. I suggest to return an empty Object '{}'.
    return QJsonObject();
{{/composedSchemas}}
{{/isEnum}}
{{#isEnum}}
{{#allowableValues}}
{{#enumVars}}
{{#-first}}
{{^isString}}
    return QJsonValue(static_cast<int>(m_value));
{{/isString}}
{{#isString}}
    return QJsonValue(asJson());
{{/isString}}
{{/-first}}
{{/enumVars}}
{{/allowableValues}}
{{/isEnum}}
}

{{^isEnum}}
{{^composedSchemas}}
{{#vars}}
{{{dataType}}} {{classname}}::{{getter}}() const
{
    return m_{{name}};
}

void {{classname}}::{{setter}}(const {{{dataType}}} &{{name}})
{
    m_{{name}} = {{name}};
    m_{{name}}IsValid = true{{#complexType}}{{^isContainer}} && {{name}}.isValid(){{/isContainer}}{{/complexType}}{{^complexType}}{{#isFreeFormObject}} && {{name}}.isValid(){{/isFreeFormObject}}{{/complexType}};
{{#complexType}}
{{#isModel}}
    // NOTE: An empty JSON object is still a valid value
    // for models without required properties.
    // Users may intentionally set it for specific reasons.
    m_{{name}}IsSet = m_{{name}}.isSet() || (m_{{name}}IsValid && {{name}}.asJsonValue().toObject().isEmpty());
{{/isModel}}
{{^isModel}}
    m_{{name}}IsSet = {{#isEnumRef}}m_{{name}}.isSet(){{/isEnumRef}}{{^isEnumRef}}m_{{name}}IsValid{{/isEnumRef}};
{{/isModel}}
{{/complexType}}
{{^complexType}}
{{#isFreeFormObject}}
    // NOTE: An empty JSON object is still a valid value
    // for models without required properties.
    // Users may intentionally set it for specific reasons.
    m_{{name}}IsSet = m_{{name}}.isSet() || (m_{{name}}IsValid && {{name}}.asJsonValue().toObject().isEmpty());
{{/isFreeFormObject}}
{{^isFreeFormObject}}
    m_{{name}}IsSet = m_{{name}}IsValid;
{{/isFreeFormObject}}
{{/complexType}}
}

bool {{classname}}::is{{#camelcase}}{{name}}{{/camelcase}}ValueSet() const
{
    return m_{{name}}IsSet;
}

bool {{classname}}::is{{#camelcase}}{{name}}{{/camelcase}}ValueValid() const
{
    return m_{{name}}IsValid;
}

{{/vars}}
{{/composedSchemas}}
{{#composedSchemas.oneOf}}
{{{dataType}}} {{classname}}::{{getter}}() const
{
    if (const auto *value = std::get_if<{{{dataType}}}>(&m_oneOf))
        return *value;
    else
        return {{{dataType}}}{};
}

void {{classname}}::{{setter}}(const {{{dataType}}} &{{name}})
{
    this->initializeModel();
    m_oneOf = {{name}};
    m_{{name}}IsValid = true{{#complexType}}{{^isContainer}} && {{name}}.isValid(){{/isContainer}}{{/complexType}}{{^complexType}}{{#isFreeFormObject}} && {{name}}.isValid(){{/isFreeFormObject}}{{/complexType}};
{{#complexType}}
{{#isModel}}
    // NOTE: An empty JSON object is still a valid value
    // for models without required properties.
    // Users may intentionally set it for specific reasons.
    m_{{name}}IsSet = {{name}}.isSet() || m_{{name}}IsValid;
{{/isModel}}
{{^isModel}}
    m_{{name}}IsSet = {{#isEnumRef}}{{name}}.isSet(){{/isEnumRef}}{{^isEnumRef}}m_{{name}}IsValid{{/isEnumRef}};
{{/isModel}}
{{/complexType}}
{{^complexType}}
{{#isFreeFormObject}}
    // NOTE: An empty JSON object is still a valid value
    // for models without required properties.
    // Users may intentionally set it for specific reasons.
    m_{{name}}IsSet = {{name}}.isSet() || m_{{name}}IsValid;
{{/isFreeFormObject}}
{{^isFreeFormObject}}
    m_{{name}}IsSet = m_{{name}}IsValid;
{{/isFreeFormObject}}
{{/complexType}}
}

bool {{classname}}::is{{#camelcase}}{{name}}{{/camelcase}}Set() const
{
    return m_{{name}}IsSet;
}

bool {{classname}}::is{{#camelcase}}{{name}}{{/camelcase}}Valid() const
{
    return m_{{name}}IsValid;
}

{{/composedSchemas.oneOf}}
{{/isEnum}}
{{#isEnum}}
{{classname}}::e{{classname}} {{classname}}::getValue() const
{
    return m_value;
}

void {{classname}}::setValue({{classname}}::e{{classname}} value)
{
    m_value = value;
    m_valueIsSet = true;
    m_valueIsValid = true;
}
{{/isEnum}}
bool {{classname}}::isSet() const
{
{{^isEnum}}
    bool isObjectUpdated = false;
    do {
{{^composedSchemas}}
{{#vars}}
        if (m_{{name}}IsSet) {
            isObjectUpdated = true;
            break;
        }
{{/vars}}
{{/composedSchemas}}
{{#composedSchemas.oneOf}}
        if (m_{{name}}IsSet) {
            isObjectUpdated = true;
            break;
        }
{{/composedSchemas.oneOf}}
    } while (false);
    return isObjectUpdated;
{{/isEnum}}
{{#isEnum}}
    return m_valueIsSet;
{{/isEnum}}
}

bool {{classname}}::isValid() const
{
{{^isEnum}}
{{^composedSchemas}}
    // only required properties are required for the object to be considered valid
    return {{#vars}}{{#required}}m_{{name}}IsValid && {{/required}}{{/vars}}true;
{{/composedSchemas}}
{{#composedSchemas}}
    return {{#oneOf}}{{^-first}} || {{/-first}}(m_{{name}}IsValid && m_{{name}}IsSet){{#-last}} || {{/-last}}{{/oneOf}}false;
{{/composedSchemas}}
{{/isEnum}}
{{#isEnum}}
    return m_valueIsValid;
{{/isEnum}}
}

{{#cppNamespaceDeclarations}}
} // namespace {{this}}
{{/cppNamespaceDeclarations}}
{{/model}}
{{/models}}
