#pragma once

#include "Dtypes.h"

using SessionIdType = uint32_t;
constexpr size_t MAX_USERS = 64;
constexpr size_t INITIAL_SESSIONS_PER_USER = 128;
constexpr size_t USER_STRING_ID_MAX_LEN = 63;

struct User
{
public:
    User() : numSessions_(0), numSessionsAllocated_(0), sessionIds_(nullptr) {}

    void init(const String &stringId_, size_t sessionAllocateSize = INITIAL_SESSIONS_PER_USER);
    void freeResources();

    bool load(const String &name);
    void save();
    void remove();
    bool valid() const { return sessionIds_ != nullptr; }

    void insertSession(SessionIdType sessionId);
    bool removeSession(SessionIdType sessionId);

    bool hasSession(SessionIdType sessionId) const;

    const String &stringId() const { return stringId_; }

    // session access
    SessionIdType *sessionBegin() { return sessionIds_; }
    SessionIdType *sessionEnd() { return sessionIds_ + numSessions_; }
    size_t numSessions() const { return numSessions_; }
    const SessionIdType *sessionBegin() const { return sessionIds_; }
    const SessionIdType *sessionEnd() const { return sessionIds_ + numSessions_; }

private:
    void growSessionArrayIfNecessary();

    String stringId_;
    size_t numSessions_;
    size_t numSessionsAllocated_;
    SessionIdType *sessionIds_;
};

class UserStorage
{
public:
    UserStorage()
        : numUsers_(0)
    {
    }

    void init()
    {
        numUsers_ = 0;
        fillFromFileSystem();
    }

    User *getUserInfo(const String &stringId);
    User *getUnassignedUser();

    User *addNewUser(const String &stringId);
    bool deleteUser(const String &stringId);

    User *begin() { return &users_[0]; }
    User *beginWithoutUnassigned() { return &users_[1]; }
    User *end() { return &users_[numUsers_]; }

    const User *begin() const { return &users_[0]; }
    const User *end() const { return &users_[numUsers_]; }

    size_t numUsers() const { return numUsers_; }

private:
    void fillFromFileSystem();

    User users_[MAX_USERS];
    size_t numUsers_;
};