#include "utils/Archive.h"
#include "math/Random.h"

#include <vector>

struct Atom
    uint64_t pos;
    float mass;

    Atom(uint64_t p, float m);

    void operator=(Atom other);

    friend Archive& operator<<(Archive& ar, Atom &a);
    friend Archive& operator>>(Archive& ar, Atom &a);

struct AtomNeighborhood
    Atom* center;
    Atom* left;
    Atom* right;

    AtomNeighborhood(Atom *l, Atom *c, Atom *r);

    bool hasLeft();
    bool hasRight();

class AtomicDomain

    AtomicDomain(uint64_t nBins);

    // access atoms
    Atom* front();
    Atom* randomAtom();
    AtomNeighborhood randomAtomWithNeighbors();
    AtomNeighborhood randomAtomWithRightNeighbor();

    uint64_t randomFreePosition() const;
    uint64_t size() const;

    void erase(uint64_t pos);
    void insert(uint64_t pos, float mass);

    // serialization
    friend Archive& operator<<(Archive &ar, AtomicDomain &domain);
    friend Archive& operator>>(Archive &ar, AtomicDomain &domain);


    // size of atomic domain to ensure all bins are equal length
    uint64_t mDomainLength;

    // domain storage, sorted vector
    std::vector<Atom> mAtoms;

    // random number generator
    mutable GapsRng mRng;