#ifndef COMPONENT_HPP
#define COMPONENT_HPP

#if defined(LINUX) || defined(MINGW)
#include <SDL2/SDL.h>
#else
// Windows and Mac use a different path
// If you have compilation errors, change this as needed.
#include <SDL.h>

#endif

#include "imgui.h"
#include "imgui_impl_sdl2.h"
#include "imgui_impl_sdlrenderer.h"

#include <vector>
#include <string>
#include <algorithm>

/**
 * Tags for Component types
 * Used to identify which (if any) subsystems should interface with components using the tags.
 */
enum ComponentTag {
    Physics,
    Input,
    Graphics,
    Position
};

/**
 * Virtual class for all components to inherit from.
 * Contains all the functionality for Game Objects.
 * 
 * @see GameObject
 */
class Component {
public:
    /**
     * Construct a new Component object
     */
    Component();

    /**
     * Destroy the Component object
     */
    ~Component();

    /**
     * Updates the state of the component object.
     * Called by the Engine every tick
     * 
     * @param e any inputs given by the user
     * @param frame what frame is the game currently displaying
     * @param broadcastList a list to be used to send messages between components
     * @see ParseAndUpdateBroadcast()
     */
    virtual void Update(SDL_Event e, int frame, std::vector<std::string> broadcastList);

    /**
     * Renders the component (if it has anything to render)
     * 
     * @param ren the SDL renderer to be displayed upon
     * @see IGraphicsEngineRenderer
     */
    virtual void Render(SDL_Renderer *ren);

    /**
     * Using Imgui, render an editor for this component
     * 
     * @see GameMakerGUI#RenderEditor()
     * @param showEditor 
     */
    virtual void ShowComponentEditor(bool* showEditor);

    /**
     * Checks if the component has the given tag
     * 
     * @param t the tag to be checked
     * @return true if the component has t
     */
    virtual bool HasTag(ComponentTag t);

    /**
     * The name of the component type.
     * Used by the GUI
     * 
     * @see GameMakerGUI#CreateComponent()
     * @return the name of the component
     */
    virtual const char* ComponentTypeName() {return "Component";}

    /**
     * Communicate with other components.
     * Removes previous broadcasts by this Component and adds any new ones.
     * Reads any relevant broadcasts from other Components.
     * 
     * @param broadcastList the persistent list of broadcasts
     * @see #Update()
     */
    void ParseAndUpdateBroadcast(std::vector<std::string> broadcastList);

protected:
    std::vector<ComponentTag> tags;
    std::vector<std::string> previousBroadcasts;
    std::vector<std::string> pendingBroadcasts;
};

#endif
