#ifndef SYMBOLS_H
#define SYMBOLS_H
#include <map>
#include <set>
#include <string>
#include <vector>

typedef unsigned short int symb_id_t;
typedef std::vector<std::string> vec_str_t;
typedef std::set<std::string> set_str_t;
typedef std::map<std::string, unsigned int> dict_uint_t;
class Symbols {
   public:
    Symbols(const vec_str_t &symbs, const set_str_t &unique_symbs);
    Symbols(const Symbols &other);
    Symbols &operator=(const Symbols &other);

    /** Return the symbol ID of the atom at site indx */
    inline symb_id_t id(unsigned int indx) const {
        return symb_ids[indx];
    };

    /** Check if the symb_id and symbols are consistent */
    bool is_consistent() const;

    /** Set a new symbol */
    void set_symbol(unsigned int indx, const std::string &symb);

    /** Get symbol at position n*/
    const std::string &get_symbol(unsigned int n) const {
        return symbols[n];
    };

    /** Get the array of symbols */
    const vec_str_t &get_symbols() const {
        return symbols;
    };

    /** Return the size of the symbol container */
    unsigned int size() const {
        return symbols.size();
    };

    /** Re-initialize all symbols */
    void set_symbols(const vec_str_t &new_symbs);

    /** Get the ID of a particular symbol */
    unsigned int get_symbol_id(const std::string &symb) const {
        return symb_id_translation.at(symb);
    };

    /** Return the number of uniquee symbols */
    unsigned int num_unique_symbols() const {
        return symb_id_translation.size();
    };

   private:
    std::vector<symb_id_t> symb_ids;
    vec_str_t symbols;
    dict_uint_t symb_id_translation;

    /** Syncronize the IDs with the symbols vector */
    void update_ids();

    /** Transfer figures to other class */
    void swap(Symbols &other) const;
};
#endif
