#pragma once

#include "elog_entry.hpp"
#include "log_manager.hpp"

#include <functional>
#include <vector>

namespace phosphor
{
namespace logging
{

/**
 * @brief The function type that will be called on start up.
 * @param[in] internal::Manager& - A reference to the Manager class.
 */
using StartupFunction = std::function<void(internal::Manager&)>;

using AdditionalDataArg = std::vector<std::string>;
using AssociationEndpointsArg = std::vector<std::string>;
using FFDCArg = FFDCEntries;

/**
 *  @brief The function type that will be called after an event log
 *         is created.
 * @param[in] const std::string& - The Message property
 * @param[in] uin32_t - The event log ID
 * @param[in] uint64_t - The event log timestamp
 * @param[in] Level - The event level
 * @param[in] const AdditionalDataArg&) - the additional data
 * @param[in] const AssociationEndpoints& - Association endpoints (callouts)
 * @param[in] const FFDCArg& - A vector of FFDC file info.
 */
using CreateFunction = std::function<void(
    const std::string&, uint32_t, uint64_t, Entry::Level,
    const AdditionalDataArg&, const AssociationEndpointsArg&, const FFDCArg&)>;

/**
 * @brief The function type that will be called after an event log is deleted.
 * @param[in] uint32_t - The event log ID
 */
using DeleteFunction = std::function<void(uint32_t)>;

/**
 * @brief The function type that will to check if an event log is prohibited
 *        from being deleted.
 * @param[in] uint32_t - The event log ID
 * @param[out] bool - set to true if the delete is prohibited
 */
using DeleteProhibitedFunction = std::function<void(uint32_t, bool&)>;

/**
 * @brief The function type that will return list of Hw Isolated
 *        log IDs
 * @param[out] std::vector<uint32_t>& - Hw Isolated log IDs
 */
using LogIDWithHwIsolationFunction =
    std::function<void(std::vector<uint32_t>&)>;
using LogIDsWithHwIsolationFunctions =
    std::vector<LogIDWithHwIsolationFunction>;

using StartupFunctions = std::vector<StartupFunction>;
using CreateFunctions = std::vector<CreateFunction>;
using DeleteFunctions = std::vector<DeleteFunction>;
using DeleteProhibitedFunctions = std::vector<DeleteProhibitedFunction>;

/**
 * @brief Register an extension hook function
 *
 * Call this macro at global scope to register a hook to call.
 * Each hook point has a unique function prototype.
 */
#define REGISTER_EXTENSION_FUNCTION(func)                                      \
    namespace func##_ns                                                        \
    {                                                                          \
        Extensions e{func};                                                    \
    }

/**
 * @brief Disable default error log capping
 *
 * Call this macro at global scope to tell phosphor-logging to disable its
 * default error log capping algorithm, so that an extension can use its own
 * instead.
 */
#define DISABLE_LOG_ENTRY_CAPS()                                               \
    namespace disable_caps##_ns                                                \
    {                                                                          \
        Extensions e{Extensions::DefaultErrorCaps::disable};                   \
    }

/**
 * @class Extensions
 *
 * This class manages any error log extensions.  Extensions can register
 * their hook functions with this class with the provided macros so that they
 * are then able to create their own types of logs based on the native logs.
 *
 * The class should only be constructed at a global scope via the macros.
 */
class Extensions
{
  public:
    Extensions() = delete;
    ~Extensions() = default;
    Extensions(const Extensions&) = delete;
    Extensions& operator=(const Extensions&) = delete;
    Extensions(Extensions&&) = delete;
    Extensions& operator=(Extensions&&) = delete;

    enum class DefaultErrorCaps
    {
        disable,
        enable
    };

    /**
     * @brief Constructor to register a startup function
     *
     * Functions registered with this contructor will be called
     * when phosphor-log-manager starts up.
     *
     * @param[in] func - The startup function to register
     */
    explicit Extensions(StartupFunction func)
    {
        getStartupFunctions().push_back(func);
    }

    /**
     * @brief Constructor to register a create function
     *
     * Functions registered with this contructor will be called
     * after phosphor-log-manager creates an event log.
     *
     * @param[in] func - The create function to register
     */
    explicit Extensions(CreateFunction func)
    {
        getCreateFunctions().push_back(func);
    }

    /**
     * @brief Constructor to register a delete function
     *
     * Functions registered with this contructor will be called
     * after phosphor-log-manager deletes an event log.
     *
     * @param[in] func - The delete function to register
     */
    explicit Extensions(DeleteFunction func)
    {
        getDeleteFunctions().push_back(func);
    }

    /**
     * @brief Constructor to register a delete prohibition function
     *
     * Functions registered with this contructor will be called
     * before phosphor-log-manager deletes an event log to ensure
     * deleting the log is allowed.
     *
     * @param[in] func - The function to register
     */
    explicit Extensions(DeleteProhibitedFunction func)
    {
        getDeleteProhibitedFunctions().push_back(func);
    }

    /**
     * @brief Constructor to register a LogID with HwIsolation function
     *
     * Functions registered with this contructor will be called
     * before phosphor-log-manager deletes all event log.
     *
     * @param[in] func - The function to register
     */
    explicit Extensions(LogIDWithHwIsolationFunction func)
    {
        getLogIDWithHwIsolationFunctions().emplace_back(func);
    }

    /**
     * @brief Constructor to disable event log capping
     *
     * This constructor should only be called by the
     * DISABLE_LOG_ENTRY_CAPS macro to disable the default
     * event log capping so that the extension can use their own.
     *
     * @param[in] defaultCaps - Enable or disable default capping.
     */
    explicit Extensions(DefaultErrorCaps defaultCaps)
    {
        getDefaultErrorCaps() = defaultCaps;
    }

    /**
     * @brief Returns the Startup functions
     * @return StartupFunctions - the Startup functions
     */
    static StartupFunctions& getStartupFunctions();

    /**
     * @brief Returns the Create functions
     * @return CreateFunctions - the Create functions
     */
    static CreateFunctions& getCreateFunctions();

    /**
     * @brief Returns the Delete functions
     * @return DeleteFunctions - the Delete functions
     */
    static DeleteFunctions& getDeleteFunctions();

    /**
     * @brief Returns the DeleteProhibited functions
     * @return DeleteProhibitedFunctions - the DeleteProhibited functions
     */
    static DeleteProhibitedFunctions& getDeleteProhibitedFunctions();

    /**
     * @brief Returns the LogIDWithHwIsolationFunction functions
     * @return LogIDsWithHwIsolationFunctions - the LogIDWithHwIsolationFunction
     * functions
     */
    static LogIDsWithHwIsolationFunctions& getLogIDWithHwIsolationFunctions();

    /**
     * @brief Returns the DefaultErrorCaps value
     * @return DefaultErrorCaps - the DefaultErrorCaps value
     */
    static DefaultErrorCaps& getDefaultErrorCaps();

    /**
     * @brief Say if the default log capping policy should be disabled
     * @return bool - true if it should be disabled
     */
    static bool disableDefaultLogCaps()
    {
        return getDefaultErrorCaps() == DefaultErrorCaps::disable;
    }
};

} // namespace logging
} // namespace phosphor