#pragma once
#include "Menu.h"

enum class ButtonAttr{
    NONE=0b00,
    UNSELECTABLE=0b01, //Makes the component unselectable.
    UNSELECTABLE_VIA_KEYBOARD=0b10, //Makes the component unselectable via keyboard.
};

enum class ComponentAttr{
    NONE=0b0000,
    LEFT_ALIGN=0b0001, //Labels are centered by default.
    SHADOW=0b0010, //Adds shadows to the label text.
    OUTLINE=0b0100, //Adds an outline around the component.
    BACKGROUND=0b1000, //Renders the background of the menu theme for this component.
};

class MenuComponent:IAttributable{
    friend class Menu;
    friend class MenuItemButton;
    friend class ScrollableWindowComponent;
    friend class InventoryScrollableWindowComponent;
    MenuType menuDest;
private:
    virtual bool GetHoverState(Crawler*game);
    //CALL THIS FOR A PARENT to check a child's DrawDecal validity!
    virtual bool PointWithinParent(MenuComponent*child,vi2d drawPos);
    std::pair<MenuType,std::string>memoryLeakInfo; //Used to identify memory leak hints for this component.
protected:
    float hoverEffect=0;
    std::string name="";
    geom2d::rect<float>rect;
    std::string label;
    bool border=true;
    bool draggable=false;
    bool background=true;
    bool showDefaultLabel=true;
    MenuFunc onClick;
    MenuType parentMenu=MenuType::ENUM_END;
    MenuComponent*parentComponent=nullptr;
    bool hovered=false;
    bool selectable=true;
    bool selectableViaKeyboard=true;
    bool disabled=false; //If set to true, this component will not be rendered or updated.
    bool renderInMain=true; //If set to false, this component is the responsibility of some other windowing system and won't be rendered or updated via the main window loop.
    bool valid=true; //If set to false, this would cause the component to be removed.
    virtual void Update(Crawler*game);
    virtual void Draw(Crawler*game,vf2d parentPos);
    virtual void DrawDecal(Crawler*game,vf2d parentPos,bool focused);
    virtual bool GetHoverState(Crawler*game,MenuComponent*child);
    virtual void AfterCreate(); //Called after the creation of all menus finish.
public:
    MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE);
    MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE);
    virtual ~MenuComponent();
    void _Update(Crawler*game);
    void _Draw(Crawler*game);
    void _Draw(Crawler*game,vf2d parentPos);
    void _DrawDecal(Crawler*game,bool focused);
    void _DrawDecal(Crawler*game,vf2d parentPos,bool focused);
    vf2d GetPos();
    //We picked up a draggable component, we should make a copy and return it here. If a nullptr is returned here, the pickup is not allowed.
    //WARNING!!! This allocates a brand new component when successful!!! Be prepared to clear it!
    virtual MenuComponent*PickUpDraggableItem();
    //We are attempting to drop draggable onto this item. If it's not allowed, return false.
    virtual bool DropDraggableItem(MenuComponent*draggable);
    //A notification that a button outside the region has been selected. Return false if it's not allowed.
    virtual bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton);
    //Called whenever an inventory slot gets updated, whether it's adding or removing an item.
    virtual void OnInventorySlotsUpdate(ITCategory cat);
    std::string GetLabel();
    void Enable(bool enabled);
    virtual void Cleanup();
};

constexpr auto operator|(ButtonAttr attribute,ButtonAttr attribute2) noexcept
{
    return ButtonAttr(static_cast<std::underlying_type_t<ButtonAttr>>(attribute)|static_cast<std::underlying_type_t<ButtonAttr>>(attribute2));
}

constexpr auto operator&(ButtonAttr attribute,ButtonAttr attribute2) noexcept
{
    return static_cast<std::underlying_type_t<ButtonAttr>>(attribute)&static_cast<std::underlying_type_t<ButtonAttr>>(attribute2);
}


constexpr auto operator|(ComponentAttr attribute,ComponentAttr attribute2) noexcept
{
    return ComponentAttr(static_cast<std::underlying_type_t<ComponentAttr>>(attribute)|static_cast<std::underlying_type_t<ComponentAttr>>(attribute2));
}
constexpr auto operator&(ComponentAttr attribute,ComponentAttr attribute2) noexcept
{
    return static_cast<std::underlying_type_t<ComponentAttr>>(attribute)&static_cast<std::underlying_type_t<ComponentAttr>>(attribute2);
}