/***************************************************************************
* Copyright (c) 2017, Sylvain Corlay and Johan Mabille                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XWIDGETS_FACTORY_HPP
#define XWIDGETS_FACTORY_HPP

#include <functional>
#include <string>
#include <unordered_map>
#include <utility>

#include "xeus/xcomm.hpp"
#include "xeus/xguid.hpp"
#include "xeus/xjson.hpp"

namespace xw
{
    /************************
     * xfactory declaration *
     ************************/

    class xfactory
    {
    public:

        using maker_type = std::function<void(xeus::xcomm&&, const xeus::xjson&, const xeus::buffer_sequence&)>;

        void register_maker(const std::string& model_module,
                            const std::string& model_name,
                            const std::string& view_module,
                            const std::string& view_name,
                            maker_type maker);

        void make(xeus::xcomm&& comm, const xeus::xjson& state, const xeus::buffer_sequence&) const;

    private:

        std::unordered_map<std::string, maker_type> m_makers;
    };

    inline xfactory& get_xfactory();

    /***************************
     * xfactory implementation *
     ***************************/

    inline void xfactory::register_maker(const std::string& model_module,
                                         const std::string& model_name,
                                         const std::string& view_module,
                                         const std::string& view_name,
                                         maker_type maker)
    {
        m_makers[model_module + model_name + view_module + view_name] = std::move(maker);
    }

    inline void xfactory::make(xeus::xcomm&& comm, const xeus::xjson& state, const xeus::buffer_sequence& buffers) const
    {
        std::string model_module = state["_model_module"];
        std::string model_name = state["_model_name"];
        std::string view_module = state["_view_module"];
        std::string view_name = state["_view_name"];
        m_makers.at(model_module + model_name + view_module + view_name)(std::move(comm), state, buffers);
    }

    inline xfactory& get_xfactory()
    {
        static xfactory factory;
        return factory;
    }
}

#endif
