/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *    Copyright (c) 2019 Nest Labs, Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/**
 *    @file
 *          Provides an implementation of the PlatformManager object.
 */
/* this file behaves like a config.h, comes first */
#include <platform/internal/CHIPDeviceLayerInternal.h>

#include <platform/Infineon/CYW30739/DiagnosticDataProviderImpl.h>
#include <platform/PlatformManager.h>
#include <platform/internal/GenericPlatformManagerImpl.ipp>

#include <crypto/CHIPCryptoPAL.h>
#include <hal/wiced_memory.h>
#include <wiced_hal_platform.h>

namespace chip {
namespace DeviceLayer {

PlatformManagerImpl PlatformManagerImpl::sInstance;

CHIP_ERROR PlatformManagerImpl::_InitChipStack(void)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    wiced_result_t result;

    // Initialize the configuration system.
    err = PersistedStorage::KeyValueStoreMgrImpl().Init();
    SuccessOrExit(err);

    /* Create the thread object. */
    mThread = wiced_rtos_create_thread();
    VerifyOrExit(mThread != nullptr, err = CHIP_ERROR_NO_MEMORY);

    /* Initialize the event flags. */
    ReturnErrorOnFailure(mEventFlags.Init());

    /* Initialize the event queue. */
    mEventQueue = wiced_rtos_create_queue();
    VerifyOrExit(mEventQueue != nullptr, err = CHIP_ERROR_NO_MEMORY);

    result = wiced_rtos_init_queue(mEventQueue, "EventQueue", sizeof(ChipDeviceEvent), CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE);
    VerifyOrExit(result == WICED_SUCCESS, err = CHIP_ERROR_NO_MEMORY);

    /* Initialize the timer. */
    result = wiced_init_timer(&mTimer, TimerCallback, 0, WICED_MILLI_SECONDS_TIMER);
    VerifyOrExit(result == WICED_SUCCESS, err = CHIP_ERROR_INTERNAL);

    /* Initialize the mutex. */
    mMutex = wiced_rtos_create_mutex();
    VerifyOrExit(mMutex != nullptr, err = CHIP_ERROR_NO_MEMORY);

    result = wiced_rtos_init_mutex(mMutex);
    VerifyOrExit(result == WICED_SUCCESS, err = CHIP_ERROR_INTERNAL);

    ReturnErrorOnFailure(chip::Crypto::add_entropy_source(GetEntropy, NULL, 16));

    ReturnErrorOnFailure(GenericPlatformManagerImpl<ImplClass>::_InitChipStack());

exit:
    return err;
}

void PlatformManagerImpl::_RunEventLoop(void)
{
    ChipLogDetail(DeviceLayer, "Free RAM sizes: %lu\n", wiced_memory_get_free_bytes());

    while (true)
    {
        uint32_t flags_set = 0;
        if (mEventFlags.WaitAnyForever(flags_set) != CHIP_NO_ERROR)
        {
            continue;
        }

        if (flags_set & kTimerEventFlag)
        {
            HandleTimerEvent();
        }

        if (flags_set & kPostEventFlag)
        {
            HandlePostEvent();
        }
    }
}

CHIP_ERROR PlatformManagerImpl::_StartEventLoopTask(void)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    wiced_result_t result;

    result = wiced_rtos_init_thread(mThread, CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY, CHIP_DEVICE_CONFIG_CHIP_TASK_NAME,
                                    EventLoopTaskMain, CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE, this);
    VerifyOrExit(result == WICED_SUCCESS, err = CHIP_ERROR_NO_MEMORY);

exit:
    return err;
}

CHIP_ERROR PlatformManagerImpl::_StopEventLoopTask()
{
    return CHIP_NO_ERROR;
}

void PlatformManagerImpl::_LockChipStack(void)
{
    const wiced_result_t result = wiced_rtos_lock_mutex(mMutex);
    VerifyOrReturn(result == WICED_SUCCESS, ChipLogError(DeviceLayer, "%s %x", __func__, result));
}

void PlatformManagerImpl::_UnlockChipStack(void)
{
    const wiced_result_t result = wiced_rtos_unlock_mutex(mMutex);
    VerifyOrReturn(result == WICED_SUCCESS || result == WICED_NOT_OWNED, ChipLogError(DeviceLayer, "%s %x", __func__, result));
}

CHIP_ERROR PlatformManagerImpl::_PostEvent(const ChipDeviceEvent * event)
{
    const wiced_result_t result = wiced_rtos_push_to_queue(mEventQueue, const_cast<ChipDeviceEvent *>(event), WICED_NO_WAIT);
    if (WICED_SUCCESS != result)
    {
        ChipLogError(DeviceLayer, "wiced_rtos_push_to_queue %u", result);
        return CHIP_ERROR_INTERNAL;
    }

    mEventFlags.Set(kPostEventFlag);

    return CHIP_NO_ERROR;
}

CHIP_ERROR PlatformManagerImpl::_StartChipTimer(System::Clock::Timeout durationMS)
{
    if (durationMS.count() == 0)
    {
        TimerCallback(0);
    }
    else
    {
        const wiced_result_t result = wiced_start_timer(&mTimer, durationMS.count());
        if (WICED_SUCCESS != result)
        {
            ChipLogError(DeviceLayer, "wiced_start_timer 0x%02x", result);
            return CHIP_ERROR_INTERNAL;
        }
    }
    return CHIP_NO_ERROR;
}

void PlatformManagerImpl::_Shutdown() {}

void PlatformManagerImpl::HandleTimerEvent(void)
{
    const CHIP_ERROR err = static_cast<System::LayerImplFreeRTOS &>(DeviceLayer::SystemLayer()).HandlePlatformTimer();
    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(DeviceLayer, "HandlePlatformTimer %ld", err.AsInteger());
    }
}

void PlatformManagerImpl::HandlePostEvent(void)
{
    wiced_result_t result;
    ChipDeviceEvent event;

    /* Check the event queue. */
    if (wiced_rtos_is_queue_empty(mEventQueue))
    {
        return;
    }

    /* Pop one event from the event queue. */
    result = wiced_rtos_pop_from_queue(mEventQueue, &event, WICED_WAIT_FOREVER);

    if (WICED_SUCCESS != result)
    {
        ChipLogError(DeviceLayer, "wiced_rtos_pop_from_queue %u", result);
        return;
    }

    /* Process this event. */
    DispatchEvent(&event);

    /* Set another application thread event if the event queue is not empty. */
    if (!wiced_rtos_is_queue_empty(mEventQueue))
    {
        mEventFlags.Set(kPostEventFlag);
    }
}

void PlatformManagerImpl::EventLoopTaskMain(uint32_t arg)
{
    ChipLogDetail(DeviceLayer, "CHIP task running");
    reinterpret_cast<PlatformManagerImpl *>(arg)->RunEventLoop();
}

void PlatformManagerImpl::TimerCallback(WICED_TIMER_PARAM_TYPE params)
{
    PlatformMgrImpl().mEventFlags.Set(kTimerEventFlag);
}

int PlatformManagerImpl::GetEntropy(void * data, unsigned char * output, size_t len, size_t * olen)
{
    const wiced_result_t result = wiced_hal_platform_random_get(output, len, olen);
    if (result != WICED_SUCCESS)
    {
        return -1;
    }
    return 0;
}

} // namespace DeviceLayer
} // namespace chip
