/*
 * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
 * its licensors.
 *
 * For complete copyright and license terms please see the LICENSE at the root of this
 * distribution (the "License"). All use of this software is governed by the License,
 * or, if provided, by the license below or the license accompanying this file. Do not
 * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *
 */
#pragma once

#if defined(_MSC_VER) && !defined(GAMELIFT_USE_STD)
#pragma warning(push)           // Save warning settings.
#pragma warning(disable : 4996) // Disable deprecated warning for strncpy
#endif

#include <aws/gamelift/common/GameLift_EXPORTS.h>
#include <aws/gamelift/server/model/AttributeValue.h>

#ifndef GAMELIFT_USE_STD
#ifndef MAX_ATTR_STRING_LENGTH
#define MAX_ATTR_STRING_LENGTH 101
#endif
#ifndef MAX_TEAM_STRING_LENGTH
#define MAX_TEAM_STRING_LENGTH 101
#endif
#ifndef MAX_PLAYER_ID_STRING_LENGTH
#define MAX_PLAYER_ID_STRING_LENGTH 129
#endif
#ifndef MAX_PLAYER_ATTRIBUTES_SIZE
#define MAX_PLAYER_ATTRIBUTES_SIZE 10
#endif
#ifndef MAX_LATENCY_SIZE
#define MAX_LATENCY_SIZE 20
#endif
#ifndef REGION_LENGTH
#define REGION_LENGTH 65
#endif
#else
#include <map>
#include <string>
#endif

namespace Aws {
namespace GameLift {
namespace Server {
namespace Model {

/**
 * <p>A player object to be used when making a StartMatchBackfill request.
 * For more information, see the <a
 * href="http://docs.aws.amazon.com/gamelift/latest/developerguide/">Amazon
 * GameLift Developer Guide</a>.</p>
 */
class AWS_GAMELIFT_API Player {
#ifdef GAMELIFT_USE_STD
public:
    /**
     * <p>Constructor.</p>
     */
    Player() {}

    /**
     * <p>Destructor.</p>
     */
    ~Player() {}

    /**
     * <p>Copy Constructor.</p>
     */
    Player(const Player &other)
        : m_playerId(other.m_playerId), m_team(other.m_team), m_playerAttributes(other.m_playerAttributes), m_latencyInMs(other.m_latencyInMs) {}

    /**
     * <p>Move Constructor.</p>
     */
    Player(Player &&other) { *this = std::move(other); }

    /**
     * <p>Copy assignment Constructor.</p>
     */
    Player &operator=(const Player &other) {
        m_playerId = other.m_playerId;
        m_team = other.m_team;
        m_playerAttributes = other.m_playerAttributes;
        m_latencyInMs = other.m_latencyInMs;

        return *this;
    }

    /**
     * <p>Move assignment Constructor.</p>
     */
    Player &operator=(Player &&other) {
        m_playerId = std::move(other.m_playerId);
        m_team = std::move(other.m_team);
        m_playerAttributes = std::move(other.m_playerAttributes);
        m_latencyInMs = std::move(other.m_latencyInMs);

        return *this;
    }

    inline const std::string &GetPlayerId() const { return m_playerId; }

    inline void SetPlayerId(const std::string &value) { m_playerId = value; }

    inline void SetPlayerId(std::string &&value) { m_playerId = value; }

    inline void SetPlayerId(const char *value) { m_playerId.assign(value); }

    inline Player &WithPlayerId(const std::string &value) {
        SetPlayerId(value);
        return *this;
    }

    inline Player &WithPlayerId(std::string &&value) {
        SetPlayerId(value);
        return *this;
    }

    inline Player &WithPlayerId(const char *value) {
        SetPlayerId(value);
        return *this;
    }

    inline const std::string &GetTeam() const { return m_team; }

    inline void SetTeam(const std::string &value) { m_team = value; }

    inline void SetTeam(std::string &&value) { m_team = value; }

    inline void SetTeam(const char *value) { m_team.assign(value); }

    inline Player &WithTeam(const std::string &value) {
        SetTeam(value);
        return *this;
    }

    inline Player &WithTeam(std::string &&value) {
        SetTeam(value);
        return *this;
    }

    inline Player &WithTeam(const char *value) {
        SetTeam(value);
        return *this;
    }

    inline const std::map<std::string, AttributeValue> &GetPlayerAttributes() const { return m_playerAttributes; }

    inline void SetPlayerAttributes(const std::map<std::string, AttributeValue> &value) { m_playerAttributes = value; }

    inline void SetPlayerAttributes(const std::map<std::string, AttributeValue> &&value) { m_playerAttributes = std::move(value); }

    inline Player &WithPlayerAttributes(const std::map<std::string, AttributeValue> &value) {
        SetPlayerAttributes(value);
        return *this;
    }

    inline Player &WithPlayerAttributes(std::map<std::string, AttributeValue> &&value) {
        SetPlayerAttributes(value);
        return *this;
    }

    inline Player &AddPlayerAttribute(const std::string &attrName, const AttributeValue &attrValue) {
        m_playerAttributes.emplace(attrName, attrValue);
        return *this;
    }

    inline Player &AddPlayerAttribute(const std::string &&attrName, const AttributeValue &&attrValue) {
        m_playerAttributes.emplace(std::move(attrName), std::move(attrValue));
        return *this;
    }

    inline const std::map<std::string, int> &GetLatencyInMs() const { return m_latencyInMs; }

    inline void SetLatencyInMs(const std::map<std::string, int> &value) { m_latencyInMs = value; }

    inline void SetLatencyInMs(const std::map<std::string, int> &&value) { m_latencyInMs = std::move(value); }

    inline Player &WithLatencyInMs(const std::map<std::string, int> &value) {
        SetLatencyInMs(value);
        return *this;
    }

    inline Player &WithLatencyInMs(std::map<std::string, int> &&value) {
        SetLatencyInMs(value);
        return *this;
    }

    inline Player &AddLatencyInMs(const std::string &attrName, const int &attrValue) {
        m_latencyInMs[attrName] = attrValue;
        return *this;
    }

    inline Player &AddLatencyInMs(const std::string &&attrName, const int &attrValue) {
        m_latencyInMs.emplace(std::move(attrName), attrValue);
        return *this;
    }

private:
    std::string m_playerId;
    std::string m_team;
    std::map<std::string, AttributeValue> m_playerAttributes;
    std::map<std::string, int> m_latencyInMs;
#else
public:
    struct NamedAttribute;
    struct RegionAndLatency;
    typedef char AttributeStringType[MAX_ATTR_STRING_LENGTH];

    /**
     * <p>Constructor.</p>
     */
    Player() : m_attributeCount(0), m_latencyCount(0) {
        m_playerId[0] = 0;
        m_team[0] = 0;
    }

    /**
     * <p>Destructor.</p>
     */
    ~Player() {}

    /**
     * <p>Copy Constructor.</p>
     */
    Player(const Player &other) { *this = other; }

    /**
     * <p>Move Constructor.</p>
     */
    Player(Player &&other) { *this = std::move(other); }

    /**
     * <p>Copy assignment Constructor.</p>
     */
    Player &operator=(const Player &other) {
        SetPlayerId(other.m_playerId);
        SetTeam(other.m_team);

        m_attributeCount = other.m_attributeCount;
        m_latencyCount = other.m_latencyCount;

        for (int index = 0; index < m_attributeCount; ++index) {
            m_playerAttributes[index] = other.m_playerAttributes[index];
        }
        for (int index = 0; index < m_latencyCount; ++index) {
            m_latencyInMs[index] = other.m_latencyInMs[index];
        }

        return *this;
    }

    /**
     * <p>Move assignment Constructor.</p>
     */
    Player &operator=(Player &&other) {
        *this = other;

        return *this;
    }

    inline const char *GetPlayerId() const { return m_playerId; }

    inline void SetPlayerId(const char *value) {
        strncpy(m_playerId, value, sizeof(m_playerId));
        m_playerId[MAX_PLAYER_ID_STRING_LENGTH - 1] = '\0';
    }

    inline Player &WithPlayerId(const char *value) {
        SetPlayerId(value);
        return *this;
    }

    inline const char *GetTeam() const { return m_team; }

    inline void SetTeam(const char *value) {
        strncpy(m_team, value, sizeof(m_team));
        m_team[MAX_TEAM_STRING_LENGTH - 1] = '\0';
    }

    inline Player &WithTeam(const char *value) {
        SetTeam(value);
        return *this;
    }

    inline const NamedAttribute *GetPlayerAttributes(int &count) const {
        count = m_attributeCount;
        return m_playerAttributes;
    }

    inline void AddPlayerAttribute(const char *attrName, const AttributeValue &attrValue) {
        if (m_attributeCount < MAX_PLAYER_ATTRIBUTES_SIZE) {
            m_playerAttributes[m_attributeCount++] = NamedAttribute(attrName, attrValue);
        }
    }

    inline Player &WithPlayerAttribute(const char *attrName, const AttributeValue &attrValue) {
        AddPlayerAttribute(attrName, attrValue);
        return *this;
    }

    inline const RegionAndLatency *GetLatencyMs(int &count) const {
        count = m_latencyCount;
        return m_latencyInMs;
    }

    inline void AddLatencyMs(const char *region, int latencyMs) {
        if (m_latencyCount < MAX_LATENCY_SIZE) {
            m_latencyInMs[m_latencyCount++] = RegionAndLatency(region, latencyMs);
        }
    };

    inline Player &WithLatencyMs(const char *region, int latencyMs) {
        AddLatencyMs(region, latencyMs);
        return *this;
    }

    struct NamedAttribute {
        NamedAttribute() { m_name[0] = 0; }

        NamedAttribute(const char *name, const AttributeValue &value) : m_value(value) {
            strncpy(m_name, name, sizeof(m_name));
            m_name[sizeof(m_name) - 1] = 0;
        }

        NamedAttribute(const NamedAttribute &other) : m_value(other.m_value) {
            strncpy(m_name, other.m_name, sizeof(m_name));
            m_name[sizeof(m_name) - 1] = 0;
        }

        NamedAttribute &operator=(const NamedAttribute &other) {
            strncpy(m_name, other.m_name, sizeof(m_name));
            m_name[sizeof(m_name) - 1] = 0;
            m_value = other.m_value;

            return *this;
        }

        NamedAttribute(const NamedAttribute &&other) : m_value(std::move(other.m_value)) {
            strncpy(m_name, other.m_name, sizeof(m_name));
            m_name[sizeof(m_name) - 1] = 0;
        }

        NamedAttribute &operator=(const NamedAttribute &&other) {
            *this = other;

            return *this;
        }

        inline const char *GetName() const { return m_name; }

        inline AttributeValue GetValue() const { return m_value; }

    private:
        AttributeStringType m_name;
        AttributeValue m_value;
    };

    struct RegionAndLatency {
        RegionAndLatency() : m_latencyMs(0) { m_region[0] = 0; }

        RegionAndLatency(const char *region, int latencyMs) {
            strncpy(m_region, region, sizeof(m_region));
            m_region[sizeof(m_region) - 1] = 0;
            m_latencyMs = latencyMs;
        }

        RegionAndLatency(const RegionAndLatency &other) { *this = other; }

        RegionAndLatency &operator=(const RegionAndLatency &other) {
            strncpy(m_region, other.m_region, sizeof(m_region));
            m_region[sizeof(m_region) - 1] = 0;
            m_latencyMs = other.m_latencyMs;

            return *this;
        }

        RegionAndLatency(const RegionAndLatency &&other) { *this = std::move(other); }

        RegionAndLatency &operator=(const RegionAndLatency &&other) {
            *this = other;

            return *this;
        }

        inline const char *GetRegion() const { return m_region; }

        inline int GetLatencyMs() const { return m_latencyMs; }

    private:
        char m_region[REGION_LENGTH];
        int m_latencyMs;
    };

private:
    char m_playerId[MAX_PLAYER_ID_STRING_LENGTH];
    char m_team[MAX_TEAM_STRING_LENGTH];
    NamedAttribute m_playerAttributes[MAX_PLAYER_ATTRIBUTES_SIZE];
    RegionAndLatency m_latencyInMs[MAX_LATENCY_SIZE];
    int m_attributeCount;
    int m_latencyCount;
#endif
};

} // namespace Model
} // namespace Server
} // namespace GameLift
} // namespace Aws

#if defined(_MSC_VER) && !defined(GAMELIFT_USE_STD)
#pragma warning(pop) // Restore warnings to previous state.
#endif