#include <pake/dirtiable-image.hpp>

namespace pake {

  struct dirty_region_builder {

    std::vector<region> regions_not_on_bottom;
    std::list<region> regions_on_bottom;

    void add_row(const std::vector<region> &row) {

      std::list<region> new_regions_on_bottom;

      for (auto i = row.begin(); i < row.end(); ++i) {
        bool expanded = false;
        for (auto j = regions_on_bottom.begin(); j != regions_on_bottom.end(); ++j)
          if (i->start_x == j->start_x && i->width == j->width) {
            j->height += i->height;
            new_regions_on_bottom.push_back(*j);
            regions_on_bottom.erase(j);
            expanded = true;
            break;
          }
        if (!expanded)
          new_regions_on_bottom.push_back(*i);
      }

      for (auto i = regions_on_bottom.begin(); i != regions_on_bottom.end(); ++i)
        regions_not_on_bottom.push_back(*i);

      regions_on_bottom = std::move(new_regions_on_bottom);

    }

  };

  std::vector<region> dirtiable_image::get_dirty_regions() {

    dirty_region_builder builder;

    std::vector<region> row;

    for (int y = 0; y < dirty.height; ++y) {

      int r = 0;
      for (int x = 0; x < dirty.width; ++x)
        if (!dirty.at(x, y)) {
          if (r != x)
            row.push_back({
              .start_x = r, .start_y = y,
              .width = x - r, .height = 1
            });
          r = x + 1;
        }
      if (r != dirty.width)
        row.push_back({
          .start_x = r, .start_y = y,
          .width = dirty.width - r, .height = 1
        });

      builder.add_row(row);
      row.clear();

    }

    builder.add_row(row);
    return builder.regions_not_on_bottom;

  }

  void dirtiable_image::clear_dirty() {
    dirty.fill(false);
  }

  dirtiable_image::dirtiable_image(int width, int height)
  : image(width, height), dirty(width, height) {
    dirty.fill(false);
  }

}
