#ifndef INCLUDED_STORE_
#define INCLUDED_STORE_

#include <iosfwd>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <queue>

#include "../xrefdata/xrefdata.h"

// XrefData elements in the vector d_xrefVector. 
// XrefData's usedBy() returns a vector of indices in d_xrefVector of functions
//          using XrefData's symbol(). 
//          XrefData's element's identifier itself is returned by XrefData's 
//          name().
// 
// Indices of defined elements are stored in d_defIdx. Other entries in 
//          d_defIdx are used, but not defined in the specified object
//          files. 



namespace FBB
{
    class Pattern;
}

class Store
{
    friend std::ostream &operator<<(std::ostream &out, Store const &store);

    size_t d_currentIdx;
    std::string d_sourceFile;
    std::string d_objFile;
    std::string d_symbol;

    using IdxIter = std::vector<size_t>::iterator;

    XrefVector d_xrefVector;
    mutable std::vector<size_t> d_defIdx;       // indices of defined 
                                                // functions/objects

                                    // GLOBALS main.cc tmp/main.o (main.cc)
    std::pair<size_t, size_t> d_globals;        // convert GLOBALS idx to
                                                // its first function
    public:
        Store();

        void setSource(std::string const &fname);
        void setObjfile(std::string const &fname);

        void setFunction(std::string const &function);
        void setObject(std::string const &object);
        void undefined(std::string const &symbol);

        void tree(std::string const &symbol) const;
        void calledBy(std::string const &spec);

    private:
        void define(std::string const &symbol, bool isFunction);
        std::ostream &insertInto(std::ostream &out) const;
        void insert(std::ostream &out, std::string const &name, 
                                                        bool doSelect) const;

        void callers(std::unordered_set<size_t> &done, 
                     std::queue<size_t> &todo) const;

        void checkGlobals(IdxIter &begin, IdxIter &end);

        size_t symbolIdx(std::string const &symbol) const;

        static bool findSymbol(XrefData const &data, 
                               std::string const &target);

        static void insertDefined(size_t idx, std::ostream &out, 
                                  XrefVector const &xref);
        static void usedBy(size_t idx, std::ostream &out, 
                                  XrefVector const &xref);
        static std::string rmBlanks(std::string const &symbol);
};

inline std::ostream &operator<<(std::ostream &out, Store const &store)
{
    return store.insertInto(out);   
}
        
#endif





