/*
 *    Copyright (c) 2019, The OpenThread Authors.
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without
 *    modification, are permitted provided that the following conditions are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *    3. Neither the name of the copyright holder nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 *    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
 *    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 *   This file implements Thread Radio Encapsulation Link (TREL) interface.
 */

#include "trel_interface.hpp"

#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE

#include <string.h>

#include "common/array.hpp"
#include "common/as_core_type.hpp"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/locator_getters.hpp"
#include "common/log.hpp"
#include "common/string.hpp"
#include "net/dns_types.hpp"

namespace ot {
namespace Trel {

RegisterLogModule("TrelInterface");

const char Interface::kTxtRecordExtAddressKey[] = "xa";
const char Interface::kTxtRecordExtPanIdKey[]   = "xp";

Interface::Interface(Instance &aInstance)
    : InstanceLocator(aInstance)
    , mInitialized(false)
    , mEnabled(false)
    , mFiltered(false)
    , mRegisterServiceTask(aInstance, HandleRegisterServiceTask)
{
}

void Interface::Init(void)
{
    OT_ASSERT(!mInitialized);

    mInitialized = true;

    if (mEnabled)
    {
        mEnabled = false;
        Enable();
    }
}

void Interface::Enable(void)
{
    VerifyOrExit(!mEnabled);

    mEnabled = true;
    VerifyOrExit(mInitialized);

    otPlatTrelEnable(&GetInstance(), &mUdpPort);

    LogInfo("Enabled interface, local port:%u", mUdpPort);
    mRegisterServiceTask.Post();

exit:
    return;
}

void Interface::Disable(void)
{
    VerifyOrExit(mEnabled);

    mEnabled = false;
    VerifyOrExit(mInitialized);

    otPlatTrelDisable(&GetInstance());
    mPeerTable.Clear();
    LogDebg("Disabled interface");

exit:
    return;
}

void Interface::HandleExtAddressChange(void)
{
    VerifyOrExit(mInitialized && mEnabled);
    LogDebg("Extended Address changed, re-registering DNS-SD service");
    mRegisterServiceTask.Post();

exit:
    return;
}

void Interface::HandleExtPanIdChange(void)
{
    VerifyOrExit(mInitialized && mEnabled);
    LogDebg("Extended PAN ID changed, re-registering DNS-SD service");
    mRegisterServiceTask.Post();

exit:
    return;
}

void Interface::HandleRegisterServiceTask(Tasklet &aTasklet)
{
    aTasklet.Get<Interface>().RegisterService();
}

void Interface::RegisterService(void)
{
    // TXT data consists of two entries: the length fields, the
    // "key" string, "=" char, and binary representation of the MAC
    // or Extended PAN ID values.
    static constexpr uint8_t kTxtDataSize =
        /* ExtAddr  */ sizeof(uint8_t) + sizeof(kTxtRecordExtAddressKey) - 1 + sizeof(char) + sizeof(Mac::ExtAddress) +
        /* ExtPanId */ sizeof(uint8_t) + sizeof(kTxtRecordExtPanIdKey) - 1 + sizeof(char) +
        sizeof(MeshCoP::ExtendedPanId);

    uint8_t                        txtDataBuffer[kTxtDataSize];
    MutableData<kWithUint16Length> txtData;
    Dns::TxtEntry                  txtEntries[2];

    VerifyOrExit(mInitialized && mEnabled);

    txtEntries[0].Init(kTxtRecordExtAddressKey, Get<Mac::Mac>().GetExtAddress().m8, sizeof(Mac::ExtAddress));
    txtEntries[1].Init(kTxtRecordExtPanIdKey, Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId().m8,
                       sizeof(MeshCoP::ExtendedPanId));

    txtData.Init(txtDataBuffer, sizeof(txtDataBuffer));
    SuccessOrAssert(Dns::TxtEntry::AppendEntries(txtEntries, GetArrayLength(txtEntries), txtData));

    LogInfo("Registering DNS-SD service: port:%u, txt:\"%s=%s, %s=%s\"", mUdpPort, kTxtRecordExtAddressKey,
            Get<Mac::Mac>().GetExtAddress().ToString().AsCString(), kTxtRecordExtPanIdKey,
            Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId().ToString().AsCString());

    otPlatTrelRegisterService(&GetInstance(), mUdpPort, txtData.GetBytes(), static_cast<uint8_t>(txtData.GetLength()));

exit:
    return;
}

extern "C" void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo)
{
    Instance &instance = AsCoreType(aInstance);

    VerifyOrExit(instance.IsInitialized());
    instance.Get<Interface>().HandleDiscoveredPeerInfo(*static_cast<const Interface::Peer::Info *>(aInfo));

exit:
    return;
}

void Interface::HandleDiscoveredPeerInfo(const Peer::Info &aInfo)
{
    Peer *                 entry;
    Mac::ExtAddress        extAddress;
    MeshCoP::ExtendedPanId extPanId;
    bool                   isNew = false;

    VerifyOrExit(mInitialized && mEnabled);

    SuccessOrExit(ParsePeerInfoTxtData(aInfo, extAddress, extPanId));

    VerifyOrExit(extAddress != Get<Mac::Mac>().GetExtAddress());

    if (aInfo.IsRemoved())
    {
        entry = mPeerTable.FindMatching(extAddress);
        VerifyOrExit(entry != nullptr);
        RemovePeerEntry(*entry);
        ExitNow();
    }

    // It is a new entry or an update to an existing entry. First
    // check whether we have an existing entry that matches the same
    // socket address, and remove it if it is associated with a
    // different Extended MAC address. This ensures that we do not
    // keep stale entries in the peer table.

    entry = mPeerTable.FindMatching(aInfo.GetSockAddr());

    if ((entry != nullptr) && !entry->Matches(extAddress))
    {
        RemovePeerEntry(*entry);
        entry = nullptr;
    }

    if (entry == nullptr)
    {
        entry = mPeerTable.FindMatching(extAddress);
    }

    if (entry == nullptr)
    {
        entry = GetNewPeerEntry();
        VerifyOrExit(entry != nullptr);

        entry->SetExtAddress(extAddress);
        isNew = true;
    }

    if (!isNew)
    {
        VerifyOrExit((entry->GetExtPanId() != extPanId) || (entry->GetSockAddr() != aInfo.GetSockAddr()));
    }

    entry->SetExtPanId(extPanId);
    entry->SetSockAddr(aInfo.GetSockAddr());

    entry->Log(isNew ? "Added" : "Updated");

exit:
    return;
}

Error Interface::ParsePeerInfoTxtData(const Peer::Info &      aInfo,
                                      Mac::ExtAddress &       aExtAddress,
                                      MeshCoP::ExtendedPanId &aExtPanId) const
{
    Error                   error;
    Dns::TxtEntry           entry;
    Dns::TxtEntry::Iterator iterator;
    bool                    parsedExtAddress = false;
    bool                    parsedExtPanId   = false;

    aExtPanId.Clear();

    iterator.Init(aInfo.GetTxtData(), aInfo.GetTxtLength());

    while ((error = iterator.GetNextEntry(entry)) == kErrorNone)
    {
        if (strcmp(entry.mKey, kTxtRecordExtAddressKey) == 0)
        {
            VerifyOrExit(!parsedExtAddress, error = kErrorParse);
            VerifyOrExit(entry.mValueLength == sizeof(Mac::ExtAddress), error = kErrorParse);
            aExtAddress.Set(entry.mValue);
            parsedExtAddress = true;
        }
        else if (strcmp(entry.mKey, kTxtRecordExtPanIdKey) == 0)
        {
            VerifyOrExit(!parsedExtPanId, error = kErrorParse);
            VerifyOrExit(entry.mValueLength == sizeof(MeshCoP::ExtendedPanId), error = kErrorParse);
            memcpy(aExtPanId.m8, entry.mValue, sizeof(MeshCoP::ExtendedPanId));
            parsedExtPanId = true;
        }

        // Skip over and ignore any unknown keys.
    }

    VerifyOrExit(error == kErrorNotFound);
    error = kErrorNone;

    VerifyOrExit(parsedExtAddress && parsedExtPanId, error = kErrorParse);

exit:
    return error;
}

Interface::Peer *Interface::GetNewPeerEntry(void)
{
    Peer *peerEntry;

    peerEntry = mPeerTable.PushBack();
    VerifyOrExit(peerEntry == nullptr);

    for (Peer &entry : mPeerTable)
    {
        if (entry.GetExtPanId() != Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId())
        {
            ExitNow(peerEntry = &entry);
        }
    }

    for (Peer &entry : mPeerTable)
    {
        // We skip over any existing entry in neighbor table (even if the
        // entry is in invalid state).

        if (Get<NeighborTable>().FindNeighbor(entry.GetExtAddress(), Neighbor::kInStateAny) != nullptr)
        {
            continue;
        }

#if OPENTHREAD_FTD
        {
            Mac::Address macAddress;

            macAddress.SetExtended(entry.GetExtAddress());

            if (Get<NeighborTable>().FindRxOnlyNeighborRouter(macAddress) != nullptr)
            {
                continue;
            }
        }
#endif

        ExitNow(peerEntry = &entry);
    }

exit:
    return peerEntry;
}

void Interface::RemovePeerEntry(Peer &aEntry)
{
    aEntry.Log("Removing");

    // Replace the entry being removed with the last entry (if not the
    // last one already) and then pop the last entry from array.

    if (&aEntry != mPeerTable.Back())
    {
        aEntry = *mPeerTable.Back();
    }

    mPeerTable.PopBack();
}

Error Interface::Send(const Packet &aPacket, bool aIsDiscovery)
{
    Error error = kErrorNone;
    Peer *peerEntry;

    VerifyOrExit(mInitialized && mEnabled, error = kErrorAbort);
    VerifyOrExit(!mFiltered);

    switch (aPacket.GetHeader().GetType())
    {
    case Header::kTypeBroadcast:
        for (Peer &entry : mPeerTable)
        {
            if (!aIsDiscovery && (entry.GetExtPanId() != Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()))
            {
                continue;
            }

            otPlatTrelSend(&GetInstance(), aPacket.GetBuffer(), aPacket.GetLength(), &entry.mSockAddr);
        }
        break;

    case Header::kTypeUnicast:
    case Header::kTypeAck:
        peerEntry = mPeerTable.FindMatching(aPacket.GetHeader().GetDestination());
        VerifyOrExit(peerEntry != nullptr, error = kErrorAbort);
        otPlatTrelSend(&GetInstance(), aPacket.GetBuffer(), aPacket.GetLength(), &peerEntry->mSockAddr);
        break;
    }

exit:
    return error;
}

extern "C" void otPlatTrelHandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength)
{
    Instance &instance = AsCoreType(aInstance);

    VerifyOrExit(instance.IsInitialized());
    instance.Get<Interface>().HandleReceived(aBuffer, aLength);

exit:
    return;
}

void Interface::HandleReceived(uint8_t *aBuffer, uint16_t aLength)
{
    LogDebg("HandleReceived(aLength:%u)", aLength);

    VerifyOrExit(mInitialized && mEnabled && !mFiltered);

    mRxPacket.Init(aBuffer, aLength);
    Get<Link>().ProcessReceivedPacket(mRxPacket);

exit:
    return;
}

const Interface::Peer *Interface::GetNextPeer(PeerIterator &aIterator) const
{
    const Peer *entry = mPeerTable.At(aIterator);

    if (entry != nullptr)
    {
        aIterator++;
    }

    return entry;
}

void Interface::Peer::Log(const char *aAction) const
{
    OT_UNUSED_VARIABLE(aAction);

    LogInfo("%s peer mac:%s, xpan:%s, %s", aAction, GetExtAddress().ToString().AsCString(),
            GetExtPanId().ToString().AsCString(), GetSockAddr().ToString().AsCString());
}

} // namespace Trel
} // namespace ot

#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
