#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <typeindex>
#include <typeinfo>

using namespace std;

class DataInOut {
public:
    shared_ptr<void> data = nullptr;
    type_index type = typeid(nullptr);
    bool initialized = false;
    bool optional = false;

    // template <class Archive>
    virtual bool dummy_funct(int &ar, const char* charName){
        cout<< "serialize_or_throw from DataInOut address is an empty function." << endl; 
        return true;
    }

    virtual shared_ptr<DataInOut> clone() const { return make_shared<DataInOut>(*this); }

    virtual ~DataInOut() = default; // Destructor
};

template <typename T>
class DataInOutType : public DataInOut {
public: 
    // template <class Archive>
    bool dummy_funct(int &ar, const char* charName){
        cout << "serialize_or_throw from DataInOutTYPE is an FULL function." << endl;
        return true;
    }

    shared_ptr<DataInOut> clone() const override { return make_shared<DataInOutType<T>>(*this); }
}; 

class mapClass {
private:
    map<string, shared_ptr<DataInOut> > _m;
    
public:

    template<typename T>
    void set(const string &key, shared_ptr<T> var, bool optional = false) {
        cout << "set entry with " << var.get() << endl;
        auto dataIO_ptr = make_shared<DataInOutType<T>>();
        dataIO_ptr->type = typeid(T);
        dataIO_ptr->data = var;
        dataIO_ptr->optional = optional;
        dataIO_ptr->initialized = true;
        _m[key] = dataIO_ptr;
        int toto = 1;
        // dataIO_ptr->dummy_funct(toto, key.c_str());
        // cout << "set EXIT" << endl;
    }

    void call_dummy(const string &key){
        int dummyArchive = 1;
        _m.at(key)->dummy_funct(dummyArchive, key.c_str());
    }
};

int main() {
    cout << "Hello World!" << endl;

    mapClass mapTest;
    auto length = make_shared<double>(1.0);

    mapTest.set("length", length);
    cout << "mapTest is out of set" << endl;
    mapTest.call_dummy("length");

    cout << "ByeBye!" << endl;
    return 0;
}