
#ifndef mosaic_mob_main_hh
#define mosaic_mob_main_hh

#include <string>
#include <unordered_map>

#include "itty/quads.hh"

#include "phys.hh"

struct Mobs;            // Passed to render() functions
struct Scene;           // Passed to update() functions
struct Mob_player;      // A pointer is held by Mobs
struct Place;           // A pointer is passed to Mobs

struct Mob : public Body {
        static constexpr int FLIP = 0x100;   // flip the sprite horizontally
        static constexpr int ROOM = 0x200;   // die if step outside the room
        static constexpr int HARM = 0x400;   // harmful to the player
        static constexpr int PHYS = 0x800;   // has physics

        Mob(const itty::Box& box, int flags) : Body{box, flags} {}
        virtual ~Mob() {}
        virtual bool update(Scene& sc) = 0;
        virtual void render(Mobs& mobs) = 0;
};

struct Mobs {
 private:
        struct Audio_deleter {
                void operator()(MIX_Audio* p) const { MIX_DestroyAudio(p); }
        };

        using Audio_ptr = std::unique_ptr<MIX_Audio, Audio_deleter>;

        std::unordered_map<std::string, ssize_t> frames;
        std::unordered_map<std::string, Audio_ptr> audios;
        std::list<std::unique_ptr<Mob>> mobs;
        size_t next_tick;

 public:
        itty::Atlas atlas{1024, 0, GL_NEAREST}; // all mob textures
        itty::Quads quads{atlas};               // all mob sprites
        Mob_player* pc{nullptr};                // pointer to player

        // by default the system runs at whatever fps the media configuration
        // is set up to; these variables are used for behavior that must run at
        // a stable 30fps; frame is the number of 30fps frames since the Mobs
        // object was created, an tick is true only if the frame counter went
        // up this tick.
        bool tick;
        size_t frame;

        Mobs();
        ~Mobs();
        void clear();
        void update(Scene& sc);
        void render(const itty::Box& view);

        // To construct a mob of any type, call one of these functions with the
        // mob type; the mob will be added to the mob list, and a pointer to it
        // returned.
        Mob* construct(const std::string& type, const itty::Box& box, Place* place = nullptr);
        Mob* construct(const std::string& type, const itty::Vec& p, const itty::Vec& r, Place* place = nullptr);

        // Mob-related sfx resources are handled by the Mobs object internally:
        // images are stored into the atlas, and a set of loaded audio objects
        // is kept. Both are emptied when the Mobs object is destroyed. Until
        // then, attempting to load the same file twice will return the same
        // object.
        ssize_t load_frames(const std::string& name, int w, int h);
        MIX_Audio* load_audio(const std::string& name);
};

#endif // mosaic_mob_main_hh
