#pragma once
#include <drogon/exports.h>
#include <trantor/utils/Logger.h>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
#include <unordered_map>
#include <vector>
#include <type_traits>
#include <cstdlib>
#ifndef _MSC_VER
#include <cxxabi.h>
#endif
#include <stdio.h>
namespace drogon
{
class DrObjectBase;
using DrAllocFunc = std::function<DrObjectBase *()>;
using DrSharedAllocFunc = std::function<std::shared_ptr<DrObjectBase>()>;
class DROGON_EXPORT DrClassMap
{
  public:
    static void registerClass(const std::string &className,
                              const DrAllocFunc &func,
                              const DrSharedAllocFunc &sharedFunc = nullptr);
    static DrObjectBase *newObject(const std::string &className);
    static std::shared_ptr<DrObjectBase> newSharedObject(
        const std::string &className);
    static const std::shared_ptr<DrObjectBase> &getSingleInstance(
        const std::string &className);
    template <typename T>
    static std::shared_ptr<T> getSingleInstance()
    {
        static_assert(std::is_base_of<DrObjectBase, T>::value,
                      "T must be a sub-class of DrObjectBase");
        static auto const singleton =
            std::dynamic_pointer_cast<T>(getSingleInstance(T::classTypeName()));
        assert(singleton);
        return singleton;
    }
    static void setSingleInstance(const std::shared_ptr<DrObjectBase> &ins);
    static std::vector<std::string> getAllClassName();
    static std::string demangle(const char *mangled_name)
    {
#ifndef _MSC_VER
        std::size_t len = 0;
        int status = 0;
        std::unique_ptr<char, decltype(&std::free)> ptr(
            __cxxabiv1::__cxa_demangle(mangled_name, nullptr, &len, &status),
            &std::free);
        if (status == 0)
        {
            return std::string(ptr.get());
        }
        LOG_ERROR << "Demangle error!";
        return "";
#else
        auto pos = strstr(mangled_name, " ");
        if (pos == nullptr)
            return std::string{mangled_name};
        else
            return std::string{pos + 1};
#endif
    }
  protected:
    static std::unordered_map<std::string,
                              std::pair<DrAllocFunc, DrSharedAllocFunc>> &
    getMap();
};
}  