
#include <string>

#include <nmstl/ptr>
#include <nmstl/serial>

using namespace std;
using namespace nmstl;

class Super {
    string name;

  public:
    Super() {}
    Super(string name) : name(name) {}
    virtual ~Super() {}

    string get_name() const { return name; }
    virtual string as_string() const { return "SUPER{" + name + "}"; }

    NMSTL_SERIAL_BASE(Super, int, << name);
};
NMSTL_TO_STRING(Super);

class SubA : public Super {
    int a;

  public:
    SubA() {}
    SubA(string name, int a) : Super(name), a(a) {}

    virtual string as_string() const { return "SUBA{" + get_name() + "," + a + "}"; };

    NMSTL_SERIAL_SUBCLASS(SubA, Super, << a);
};

class SubB : public Super {
    bool a;

  public:
    SubB() {}
    SubB(string name, bool a) : Super(name), a(a) {}

    virtual string as_string() const { return "SUBB{" + get_name() + "," + a + "}"; };
    bool get_a() const { return a; }

    NMSTL_SERIAL_SUBCLASS(SubB, Super, << a);
};

class SubC : public SubB {
  public:
    SubC() {}
    SubC(string name, bool a) : SubB(name, a) {}

    virtual string as_string() const { return "SUBC{" + get_name() + "," + get_a() + "}"; };

    NMSTL_SERIAL_SUBCLASS(SubC, SubB, );
};

NMSTL_SERIAL_DEFINE(Super, 0x01010101);
NMSTL_SERIAL_DEFINE(SubA,  0x02020202);
NMSTL_SERIAL_DEFINE(SubB,  0x03030303);
NMSTL_SERIAL_DEFINE(SubC,  0x04040404);

int main() {
    oserialstring oss(oserial::binary | oserial::nosignature);

    ptr<Super> suba(new SubA("AAA", 12345));
    ptr<Super> subb(new SubB("BBB", true));
    ptr<Super> subc(new SubC("CCC", true));
    ptr<Super> nil;

    cout << suba << endl << subb << endl << subc << endl << nil << endl;

    oss << suba << subb << subc << nil;

    cout << to_escaped_string(oss.str()) << endl;

    cout << "0x01010101 is a " << Super::typename_for_typeid(0x01010101) << endl;
    cout << "0x02020202 is a " << Super::typename_for_typeid(0x02020202) << endl;
    cout << "0x03030303 is a " << Super::typename_for_typeid(0x03030303) << endl;
    cout << "0x04040404 is a " << Super::typename_for_typeid(0x04040404) << endl;

    ptr<Super> x1, x2, x3, x4;
    iserialstring iss(oss.str(), iserial::binary);
    iss >> x1 >> x2 >> x3 >> x4;
    if (iss) {
        cout << x1 << endl << x2 << endl << x3 << endl << x4 << endl;
    } else {
        cout << "Error deserializing: " << iss.stat() << endl;
    }
}
