#ifndef Foundation_Atom_Atom_INCLUDED
#define Foundation_Atom_Atom_INCLUDED

#include <iosfwd>
#include <map>
#include <vector>
#include <string>
#include <stddef.h>

#include <foundation/TnTypes.h>

#include <foundation/Init.hpp>

namespace Tn {

namespace Foundation {

struct Atom {

    // typedef size_t index;
    /* tag_t should be size_t but QNX is apparently broken when that happens. */

    typedef size_t tag_t;

    Atom() : tag(0) {}
    Atom(Atom const & that) : tag(that.tag) {}
    Atom(std::string const & name) : tag(getTag(name)) {}
    // Broken QNX compiler...
    // Atom(char const * name) : tag(getTag(name)) {}

    friend inline bool operator==(Atom a, Atom b) {
        return a.tag==b.tag;
    }

    friend inline bool operator!=(Atom a, Atom b) {
        return a.tag!=b.tag;
    }

    friend inline bool operator<(Atom a, Atom b) {
        return a.tag<b.tag;
    }

    friend inline bool null(Atom s) {
        return s.tag==0;
    }

    std::string const & name() const;

    static void init(bool);

private:

#if 0
	// QNX is broken and can't handle the 'const'
    typedef std::map<std::string const, tag_t> Tags;
    typedef std::pair<std::string const, tag_t> TagsEntry;
#else
    typedef std::map<std::string, tag_t> Tags;
    typedef std::pair<std::string, tag_t> TagsEntry;
#endif

    typedef std::vector<std::string> Names;
    
    struct Table {
        Tags tags;
        Names names;
    };
    
    tag_t tag;

    tag_t getTag(std::string const & name);

    static Table* table;

private:

    /*  The gensym function generates a atom that is guaranteed to be
     *  unique even if its name isn't.
     */

    friend Atom gensym(std::string const &);
    // Broken QNX compiler...
    // friend Atom gensym(char const *);

    Atom(size_t t) : tag(t) {}
};


std::ostream& operator<<(std::ostream&, Atom const &);

namespace {

::Tn::Foundation::Init atom_init(&Atom::init);

}

} // namespace Foundation

} // namespace Tn


#endif

