#pragma once
#include "rtt.h"
#include "log.h"
#include "texture.h"

struct LayerFrame
{
    struct Snapshot
    {
        std::unique_ptr<uint8_t[]> image[6] = SIXPLETTE(0);
        std::array<glm::vec4, 6> m_dirty_box = SIXPLETTE(glm::vec4(0));
        std::array<bool, 6> m_dirty_face = SIXPLETTE(false);
        int width = 0;
        int height = 0;
        void create(int w, int h);
        void clear();
        void optimize();
        int memsize() const;
    };

    std::array<RTT, 6> m_rtt;
    std::array<glm::vec4, 6> m_dirty_box = SIXPLETTE(glm::vec4(0));
    std::array<bool, 6> m_dirty_face = SIXPLETTE(false);
    std::unique_ptr<Snapshot> m_gpu_data;
    int m_duration = 1;
    int w = 0, h = 0;

    //// default
    //LayerFrame() = default;
    //// copy
    //LayerFrame(const LayerFrame&) = delete;
    //LayerFrame& operator=(const LayerFrame&) = delete;
    //// move
    //LayerFrame(LayerFrame&& other);
    //LayerFrame& operator=(LayerFrame&&);

    bool create(int width, int height, int duration = 1);
    bool resize(int width, int height);
    void clear(const glm::vec4& c);
    LayerFrame clone() noexcept;
    // return previous state
    bool gpu_load() noexcept;
    // return if succesfully loaded on gpu
    bool gpu_unload() noexcept;
    Snapshot snapshot(std::array<glm::vec4, 6>* dirty_box = nullptr, std::array<bool, 6>* dirty_face = nullptr);
    void restore(const Snapshot& snap);
};

class Layer
{
    static uint32_t s_count;
    std::vector<LayerFrame> m_frames;
public:
    Layer() { id = s_count++; }
    Layer(const Layer&) = delete;
    uint32_t id;
    int m_frame_index = 0;
    bool m_visible = true;
    bool m_alpha_locked = false;
    float m_opacity = 1.f;
    bool m_hightlight = false;
    int m_blend_mode = 0;
    std::string m_name;
    int w = 0;
    int h = 0;
    RTT& rtt(int i, int frame = -1);
    glm::vec4& box(int i, int frame = -1);
    bool& face(int i, int frame = -1);
    LayerFrame& frame(int frame = -1);
    void resize(int width, int height);
    bool create(int width, int height, std::string name);
    bool add_frame(int index = -1);
    void remove_frame(int frame);
    void duplicate_frame(int frame);
    void frames_gpu_update();
    int frames_count() const noexcept { return m_frames.size(); }
    int frame_duration(int frame) const noexcept { return m_frames[frame].m_duration; }
    void set_frame_duration(int frame, int duration) noexcept { m_frames[frame].m_duration = duration; }
    int move_frame_offset(int frame, int offset) noexcept;
    int total_duration() const noexcept;
    void goto_frame(int frame) noexcept;
    void clear(const glm::vec4& c, int frame = -1);
    LayerFrame::Snapshot snapshot(int frame = -1, std::array<glm::vec4, 6>* dirty_box = nullptr, std::array<bool, 6>* dirty_face = nullptr);
    TextureCube gen_cube();
    Texture2D gen_equirect(glm::ivec2 size = { 0, 0 });
    PBO gen_equirect_pbo(glm::ivec2 size = { 0, 0 });
    void restore(const LayerFrame::Snapshot& snap, int frame = -1);
    void destroy();
    void optimize(int frame = -1);
};
