#pragma once
#include <luna/Result.h>
#include <luna/Types.h>

class Bitmap
{
  public:
    Bitmap();
    Bitmap(void* location, usize size_in_bytes);

    // Naive initialization functions.
    void initialize(void* location, usize size_in_bytes);
    void* move(void* new_location, usize new_location_size_in_bytes);

    // Dynamic memory initialization functions.
    Result<void> allocate(usize size_in_bytes);
    Result<void*> resize(usize new_size_in_bytes);
    Result<void> deallocate();

    void set(usize index, bool value);
    bool get(usize index) const;

    // size() returns size in bits! If you want the size in bytes, call size_in_bytes().
    usize size() const
    {
        return m_size_in_bytes * 8;
    }

    usize size_in_bytes() const
    {
        return m_size_in_bytes;
    }

    void* location() const
    {
        return (void*)m_location;
    }

    bool initialized() const
    {
        return m_location;
    }

    Option<usize> find(bool value, usize begin = 0) const;

    Option<usize> find_and_toggle(bool value, usize begin = 0);

    Option<usize> find_region(bool value, usize count, usize begin = 0) const;

    Option<usize> find_and_toggle_region(bool value, usize count, usize begin = 0);

    bool match_region(usize start, usize bits, bool value);
    Result<bool> try_match_region(usize start, usize bits, bool value);

    void clear(bool value);
    void clear_region(usize start, usize bits, bool value);

  private:
    u8 value_byte(bool b) const
    {
        return b ? 0xff : 0;
    }

    bool match_region_impl(usize start, usize bits, bool value);

    u8* m_location = nullptr;
    usize m_size_in_bytes = 0;
};