// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "rtree.h"

#include <list>

#include "flutter/fml/logging.h"
#include "third_party/skia/include/core/SkBBHFactory.h"
#include "third_party/skia/include/core/SkRect.h"

namespace flutter {

RTree::RTree() : bbh_{SkRTreeFactory{}()}, all_ops_count_(0) {}

void RTree::insert(const SkRect boundsArray[],
                   const SkBBoxHierarchy::Metadata metadata[],
                   int N) {
  FML_DCHECK(0 == all_ops_count_);
  bbh_->insert(boundsArray, metadata, N);
  for (int i = 0; i < N; i++) {
    if (metadata != nullptr && metadata[i].isDraw) {
      draw_op_[i] = boundsArray[i];
    }
  }
  all_ops_count_ = N;
}

void RTree::insert(const SkRect boundsArray[], int N) {
  insert(boundsArray, nullptr, N);
}

void RTree::search(const SkRect& query, std::vector<int>* results) const {
  bbh_->search(query, results);
}

std::list<SkRect> RTree::searchNonOverlappingDrawnRects(
    const SkRect& query) const {
  // Get the indexes for the operations that intersect with the query rect.
  std::vector<int> intermediary_results;
  search(query, &intermediary_results);

  std::list<SkRect> final_results;
  for (int index : intermediary_results) {
    auto draw_op = draw_op_.find(index);
    // Ignore records that don't draw anything.
    if (draw_op == draw_op_.end()) {
      continue;
    }
    auto current_record_rect = draw_op->second;
    auto replaced_existing_rect = false;
    // // If the current record rect intersects with any of the rects in the
    // // result list, then join them, and update the rect in final_results.
    std::list<SkRect>::iterator curr_rect_itr = final_results.begin();
    std::list<SkRect>::iterator first_intersecting_rect_itr;
    while (!replaced_existing_rect && curr_rect_itr != final_results.end()) {
      if (SkRect::Intersects(*curr_rect_itr, current_record_rect)) {
        replaced_existing_rect = true;
        first_intersecting_rect_itr = curr_rect_itr;
        curr_rect_itr->join(current_record_rect);
      }
      curr_rect_itr++;
    }
    // It's possible that the result contains duplicated rects at this point.
    // For example, consider a result list that contains rects A, B. If a
    // new rect C is a superset of A and B, then A and B are the same set after
    // the merge. As a result, find such cases and remove them from the result
    // list.
    while (replaced_existing_rect && curr_rect_itr != final_results.end()) {
      if (SkRect::Intersects(*curr_rect_itr, *first_intersecting_rect_itr)) {
        first_intersecting_rect_itr->join(*curr_rect_itr);
        curr_rect_itr = final_results.erase(curr_rect_itr);
      } else {
        curr_rect_itr++;
      }
    }
    if (!replaced_existing_rect) {
      final_results.push_back(current_record_rect);
    }
  }
  return final_results;
}

size_t RTree::bytesUsed() const {
  return bbh_->bytesUsed();
}

RTreeFactory::RTreeFactory() {
  r_tree_ = sk_make_sp<RTree>();
}

sk_sp<RTree> RTreeFactory::getInstance() {
  return r_tree_;
}

sk_sp<SkBBoxHierarchy> RTreeFactory::operator()() const {
  return r_tree_;
}

}  // namespace flutter
