//
//  NodeFactory.hpp
//  SwitchboardSDK
//
//  Created by Balazs Kiss on 2023. 07. 05..
//

#pragma once

#include <switchboard/export.h>
#include <switchboard_core/NodeTypeInfo.hpp>
#include <switchboard_core/Node.hpp>

#include <any>
#include <vector>
#include <map>
#include <string>
#include <memory>

namespace switchboard {

/**
 * NodeFactory class.
 * @brief Creates node instances.
 */
class SWITCHBOARDSDK_EXPORT NodeFactory {
public:

    /**
     * @brief NodeFactory constructor.
     */
    NodeFactory();

    /**
     * @brief NodeFactory destructor.
     */
    virtual ~NodeFactory();

    /**
     * @brief Returns the prefix of the node type.
     * @details The prefix is used to identify the node type and it follows the format: <extension name>.<node type>.
     *
     * @returns The prefix of the node type.
     */
    virtual std::string getNodeTypePrefix() = 0;

    /**
     * @brief Returns the list of node types that can be created by this factory.
     * @details The node types are returned as a vector of strings, where each string is the type name of the node.
     *
     * @returns A vector of strings containing the node types.
     */
    virtual std::vector<NodeTypeInfo> getNodeTypes();

    /**
     * @brief Creates an Node instance based on type information.
     * @details The returned node instances need to be freed by the user of the NodeFactory.
     *
     * @param type The type of the node.
     * @param config Configuration values for the node.
     *
     * @returns A pointer to the created Node instance, or nullptr if the node could not be created.
     */
    virtual Node* createNode(const std::string& type, const SBAnyMap& config);


    using NodeCreator = std::function<Node*(const SBAnyMap&)>;

    /**
     * @brief Registers a node type with the factory.
     * @details This function allows the factory to create instances of the specified node type.
     *
     * @param type The type information of the node.
     * @param creator A function that creates instances of the node.
     */
    void registerNode(const NodeTypeInfo& type, NodeCreator creator);

private:
    class Impl;
    std::unique_ptr<Impl> pImpl;
};

}
