#include "AddressManager.hpp"
#include "CryptocurrencyValidator.hpp"

AddressManager::AddressManager()
{
    InitializeSRWLock(&mLock);

    for (size_t i = 0; i < Cryptocurrency::ElementsCount; ++i)
        mIsSet[i] = false;
}

bool AddressManager::SetAddress(Cryptocurrency type, const std::wstring& address)
{
    if (!IsValidType(type))
        return false;

    size_t index = GetTypeIndex(type);

    LockForWrite();
    mAddresses[index] = address;
    mIsSet[index] = true;
    UnlockFromWrite();

    return true;
}

std::wstring AddressManager::GetAddress(Cryptocurrency type) const
{
    if (!IsValidType(type))
        return {};

    size_t index = GetTypeIndex(type);

    LockForRead();
    std::wstring result = mAddresses[index];
    UnlockFromRead();

    return result;
}

bool AddressManager::HasAddress(Cryptocurrency type) const
{
    if (!IsValidType(type))
        return false;

    size_t index = GetTypeIndex(type);

    LockForRead();
    bool result = mIsSet[index];
    UnlockFromRead();

    return result;
}

bool AddressManager::IsAddressSet(Cryptocurrency type) const
{
    return HasAddress(type);
}

bool AddressManager::RemoveAddress(Cryptocurrency type)
{
    if (!IsValidType(type))
        return false;

    size_t index = GetTypeIndex(type);

    LockForWrite();
    mAddresses[index].clear();
    mIsSet[index] = false;
    UnlockFromWrite();

    return true;
}

void AddressManager::ClearAllAddresses()
{
    LockForWrite();

    for (size_t i = 0; i < Cryptocurrency::ElementsCount; ++i)
    {
        mAddresses[i].clear();
        mIsSet[i] = false;
    }

    UnlockFromWrite();
}

size_t AddressManager::GetConfiguredCount() const
{
    size_t count = 0;

    LockForRead();

    for (size_t i = 0; i < Cryptocurrency::ElementsCount; ++i)
    {
        if (mIsSet[i])
            count++;
    }

    UnlockFromRead();

    return count;
}

std::vector<Cryptocurrency> AddressManager::GetConfiguredTypes() const
{
    std::vector<Cryptocurrency> types;

    LockForRead();

    for (size_t i = 0; i < Cryptocurrency::ElementsCount; ++i)
    {
        if (mIsSet[i])
            types.push_back(static_cast<Cryptocurrency>(i));
    }

    UnlockFromRead();

    return types;
}

bool AddressManager::ValidateAndSet(Cryptocurrency type, const std::wstring& address)
{
    if (!IsValidType(type))
        return false;

    if (!CryptocurrencyValidator::Validate(type, address))
        return false;

    return SetAddress(type, address);
}

bool AddressManager::IsValidType(Cryptocurrency type) const
{
    return static_cast<size_t>(type) < Cryptocurrency::ElementsCount;
}

size_t AddressManager::GetTypeIndex(Cryptocurrency type) const
{
    return static_cast<size_t>(type);
}

void AddressManager::LockForRead() const
{
    AcquireSRWLockShared(&mLock);
}

void AddressManager::UnlockFromRead() const
{
    ReleaseSRWLockShared(&mLock);
}

void AddressManager::LockForWrite()
{
    AcquireSRWLockExclusive(&mLock);
}

void AddressManager::UnlockFromWrite()
{
    ReleaseSRWLockExclusive(&mLock);
}