#include <iostream>
#include <string>
#include <vector>
#include <map>

#include <boost/variant.hpp>
#include <boost/optional.hpp>

using string = std::string;

namespace cppmodel {


struct Class;
using Type = boost::variant<Class*,string>;

struct Var{
    string name, value;
    Type type;
    bool is_volatile = false;
    bool is_mutable = false;
    bool is_const = false;
    bool is_static = false;
    bool is_ref = false;
    std::uint8_t is_pointer = 0; // 0 false, otherwise pointer depth in *
    std::uint8_t has_bits = 0;//bits
};

using BasicArgumentList = std::vector<Var>;

struct Using
{
    string aliasname,aliastype;
    boost::optional<BasicArgumentList> arguments;
};

struct Function{
    string name,test,body,comment;
    std::vector<Type> arguments;
    Type rtype = "void";
    boost::optional<BasicArgumentList> template_arguments;
    bool isTemplate()const {return template_arguments.is_initialized() && !template_arguments.get().empty();}
    bool is_noexcept = true;
    bool is_inline = false;
    bool is_static = false;
};

struct Default{};
struct Delete{};
using default_or_delete = boost::optional<boost::variant<Default,Delete>>;

struct Ref{};
struct RefRef{};
using RefQualifier = boost::optional<boost::variant<Ref,RefRef> >;

struct Method{
    string name,test,body,comment;
    std::vector<Type> arguments;
    Type rtype = "void";
    bool is_virtual = false, is_pure_virtual = false, is_const = false;
    boost::optional<BasicArgumentList> template_arguments;
    default_or_delete dod;
    RefQualifier refqualifier;
    bool is_noexcept = true;
    bool is_inline = false;
    bool is_static = false;
    bool is_override = false;
};

struct Constructor{
    string test,body;
    std::vector<Type> arguments;
    Class& type;
    boost::optional<BasicArgumentList> template_arguments;
    default_or_delete dod;
    bool is_noexcept = true;
};

struct Private{};
struct Public{};
struct Protected{};

using Access = boost::variant<Private,Public,Protected>;

struct Destructor{
    string test,body;
    Class& type;
    Access access;
    default_or_delete dod;
    bool is_virtual = false;
    bool is_inline = false;
    bool is_friend = false;
};

struct Parent
{
    Type type;
    Access access;
    bool is_virtual;
};

using ClassMembers = boost::variant<Class*, Var,Function,Method,Constructor,Using>;

struct Class
{
    string test,name,comment;
    boost::optional<Destructor> destructor;
    std::multimap<Access,ClassMembers> members;
    std::vector<Parent> parents;
    boost::optional<BasicArgumentList> template_arguments;
    bool isTemplate()const{return template_arguments.is_initialized() && !template_arguments.get().empty();}
    bool is_final = false;
    bool is_class = false;
    bool is_noexcept = true;
};

class Namespace;
using NamespaceMembers = boost::variant<string,Namespace*, Var, Function, Class,Using>;

struct Namespace{
    string name;
    std::vector<NamespaceMembers> members;
};

}

int main(int argc, char *argv[])
{
    using namespace cppmodel;
    Namespace root{"cppmodel",{}};
    auto& members = root.members;
    members.push_back("struct Class;");
    Using type{"type","boost::variant<Class*,string>",{}};
    members.push_back(type);

    std::cout << "Hello World!" << std::endl;
    return 0;
}