/*
 *    Copyright (c) 2017, 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 includes utility macros for coding.
 */
#ifndef OTBR_COMMON_CODE_UTILS_HPP_
#define OTBR_COMMON_CODE_UTILS_HPP_

#include "openthread-br/config.h"

#ifndef OTBR_LOG_TAG
#define OTBR_LOG_TAG "UTILS"
#endif

#include <assert.h>
#include <memory>
#include <stdlib.h>

#include "common/logging.hpp"

/**
 *  This aligns the pointer to @p aAlignType.
 *
 *  @param[in] aMem        A pointer to arbitrary memory.
 *  @param[in] aAlignType  The type to align with and convert the pointer to this type.
 *
 *  @returns A pointer to aligned memory.
 */
#define OTBR_ALIGNED(aMem, aAlignType) \
    reinterpret_cast<aAlignType>(      \
        ((reinterpret_cast<unsigned long>(aMem) + sizeof(aAlignType) - 1) / sizeof(aAlignType)) * sizeof(aAlignType))

// Allocate the structure using "raw" storage.
#define OT_DEFINE_ALIGNED_VAR(name, size, align_type) \
    align_type name[(((size) + (sizeof(align_type) - 1)) / sizeof(align_type))]

#ifndef CONTAINING_RECORD
#define BASE 0x1
#define myoffsetof(s, m) (((size_t) & (((s *)BASE)->m)) - BASE)
#define CONTAINING_RECORD(address, type, field) ((type *)((uint8_t *)(address)-myoffsetof(type, field)))
#endif /* CONTAINING_RECORD */

/**
 *  This checks for the specified status, which is expected to
 *  commonly be successful, and branches to the local label 'exit' if
 *  the status is unsuccessful.
 *
 *  @param[in] aStatus  A scalar status to be evaluated against zero (0).
 */
#define SuccessOrExit(aStatus, ...) \
    do                              \
    {                               \
        if ((aStatus) != 0)         \
        {                           \
            __VA_ARGS__;            \
            goto exit;              \
        }                           \
    } while (false)

/**
 * This macro verifies a given error status to be successful (compared against value zero (0)), otherwise, it emits a
 * given error messages and exits the program.
 *
 * @param[in] aStatus   A scalar error status to be evaluated against zero (0).
 * @param[in] aMessage  A message (text string) to print on failure.
 */
#define SuccessOrDie(aStatus, aMessage)                                                   \
    do                                                                                    \
    {                                                                                     \
        if ((aStatus) != 0)                                                               \
        {                                                                                 \
            otbrLogEmerg("FAILED %s:%d - %d: %s", __FILE__, __LINE__, aStatus, aMessage); \
            exit(-1);                                                                     \
        }                                                                                 \
    } while (false)

/**
 *  This checks for the specified condition, which is expected to
 *  commonly be true, and both executes @a ... and branches to the
 *  local label 'exit' if the condition is false.
 *
 *  @param[in] aCondition  A Boolean expression to be evaluated.
 *  @param[in] ...         An expression or block to execute when the
 *                         assertion fails.
 */
#define VerifyOrExit(aCondition, ...) \
    do                                \
    {                                 \
        if (!(aCondition))            \
        {                             \
            __VA_ARGS__;              \
            goto exit;                \
        }                             \
    } while (false)

/**
 * This macro checks for the specified condition, which is expected to commonly be true,
 * and both prints the message and terminates the program if the condition is false.
 *
 * @param[in] aCondition  The condition to verify
 * @param[in] aMessage    A message (text string) to print on failure.
 */
#define VerifyOrDie(aCondition, aMessage)                                    \
    do                                                                       \
    {                                                                        \
        if (!(aCondition))                                                   \
        {                                                                    \
            otbrLogEmerg("FAILED %s:%d - %s", __FILE__, __LINE__, aMessage); \
            exit(-1);                                                        \
        }                                                                    \
    } while (false)

/**
 * This macro prints the message and terminates the program.
 *
 * @param[in] aMessage    A message (text string) to print.
 */
#define DieNow(aMessage)                                                 \
    do                                                                   \
    {                                                                    \
        otbrLogEmerg("FAILED %s:%d - %s", __FILE__, __LINE__, aMessage); \
        exit(-1);                                                        \
    } while (false)

/**
 *  This unconditionally executes @a ... and branches to the local
 *  label 'exit'.
 *
 *  @note The use of this interface implies neither success nor
 *        failure for the overall exit status of the enclosing
 *        function body.
 *
 *  @param[in] ...  An optional expression or block to execute
 *                  when the assertion fails.
 */
#define ExitNow(...) \
    do               \
    {                \
        __VA_ARGS__; \
        goto exit;   \
    } while (false)

#define OTBR_NOOP
#define OTBR_UNUSED_VARIABLE(variable) ((void)(variable))

template <typename T, typename... Args> std::unique_ptr<T> MakeUnique(Args &&...args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

/**
 * This method converts 8 uint8_t bytes into uint64_t using big-endian.
 *
 * @param[in] aValue  The input 8 uint8_t bytes.
 * @returns The converted uint64_t.
 */
uint64_t ConvertOpenThreadUint64(const uint8_t *aValue);

/**
 * This class makes any class that derives from it non-copyable. It is intended to be used as a private base class.
 */
class NonCopyable
{
public:
    NonCopyable(const NonCopyable &)            = delete;
    NonCopyable &operator=(const NonCopyable &) = delete;

protected:
    NonCopyable(void) = default;
};

template <typename T> class Optional
{
public:
    constexpr Optional(void) = default;

    Optional(T aValue) { SetValue(aValue); }

    ~Optional(void) { ClearValue(); }

    Optional(const Optional &aOther) { AssignFrom(aOther); }

    Optional &operator=(const Optional &aOther) { AssignFrom(aOther); }

    constexpr const T *operator->(void) const { return &GetValue(); }

    constexpr const T &operator*(void) const { return GetValue(); }

    constexpr bool HasValue(void) const { return mHasValue; }

private:
    T &GetValue(void) const
    {
        assert(mHasValue);
        return *const_cast<T *>(reinterpret_cast<const T *>(&mStorage));
    }

    void ClearValue(void)
    {
        if (mHasValue)
        {
            GetValue().~T();
            mHasValue = false;
        }
    }

    void SetValue(const T &aValue)
    {
        ClearValue();
        new (&mStorage) T(aValue);
        mHasValue = true;
    }

    void AssignFrom(const Optional &aOther)
    {
        ClearValue();
        if (aOther.mHasValue)
        {
            SetValue(aOther.GetValue());
        }
    }

    alignas(T) unsigned char mStorage[sizeof(T)];
    bool mHasValue = false;
};

#endif // OTBR_COMMON_CODE_UTILS_HPP_
