// Copyright 2023 The Fuchsia 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 "src/storage/f2fs/f2fs.h"

namespace f2fs {

namespace {
static bool IsOverlap(const ExtentInfo &x, const ExtentInfo &y) {
  return (x.fofs < y.fofs + y.len && y.fofs < x.fofs + x.len);
}

static bool IsMergeable(const ExtentInfo &front, const ExtentInfo &back) {
  return (front.fofs + front.len == back.fofs && front.blk_addr + front.len == back.blk_addr);
}

static bool IsFrontSplitable(const ExtentInfo &front, const ExtentInfo &back) {
  return (front.fofs < back.fofs && front.fofs + front.len > back.fofs);
}

static bool IsBackSplitable(const ExtentInfo &front, const ExtentInfo &back) {
  return (back.fofs < front.fofs + front.len && back.fofs + back.len > front.fofs + front.len);
}
}  // namespace

zx::result<> ExtentTree::InsertExtent(ExtentInfo target_extent_info) {
  std::lock_guard lock(tree_lock_);

  // If it overlaps with |largest_extent_info_|, we just invalidate the existing
  // |largest_extent_info_|.
  if (largest_extent_info_.has_value() &&
      IsOverlap(largest_extent_info_.value(), target_extent_info)) {
    largest_extent_info_ = std::nullopt;
  }

  std::vector<ExtentInfo> new_extents;
  auto current = extent_node_tree_.lower_bound(target_extent_info.fofs);
  if (current != extent_node_tree_.begin()) {
    --current;
  }

  while (current != extent_node_tree_.end()) {
    auto next = current;
    ++next;

    if (IsOverlap(current->GetExtentInfo(), target_extent_info) ||
        IsMergeable(current->GetExtentInfo(), target_extent_info) ||
        IsMergeable(target_extent_info, current->GetExtentInfo())) {
      ZX_DEBUG_ASSERT(current->InContainer());
      auto erased = extent_node_tree_.erase(current);

      std::optional<ExtentInfo> front_splitted = std::nullopt;
      std::optional<ExtentInfo> back_splitted = std::nullopt;

      // Front split
      if (IsFrontSplitable(erased->GetExtentInfo(), target_extent_info)) {
        front_splitted = erased->GetExtentInfo();
        front_splitted->len =
            safemath::checked_cast<uint32_t>(target_extent_info.fofs - front_splitted->fofs);

        if (front_splitted->len >= kMinExtentLen) {
          new_extents.push_back(front_splitted.value());
        }
      }

      // Back split
      if (IsBackSplitable(target_extent_info, erased->GetExtentInfo())) {
        back_splitted = erased->GetExtentInfo();
        pgoff_t diff = target_extent_info.fofs + target_extent_info.len - back_splitted->fofs;

        back_splitted->fofs += diff;
        back_splitted->blk_addr += diff;
        back_splitted->len -= diff;

        if (back_splitted->len >= kMinExtentLen) {
          new_extents.push_back(back_splitted.value());
        }
      }

      // Front merge
      if (front_splitted.has_value() && IsMergeable(front_splitted.value(), target_extent_info)) {
        target_extent_info.fofs = front_splitted->fofs;
        target_extent_info.blk_addr = front_splitted->blk_addr;
        target_extent_info.len += front_splitted->len;
      } else if (IsMergeable(erased->GetExtentInfo(), target_extent_info)) {
        target_extent_info.fofs = erased->GetExtentInfo().fofs;
        target_extent_info.blk_addr = erased->GetExtentInfo().blk_addr;
        target_extent_info.len += erased->GetExtentInfo().len;
      }

      // Back merge
      if (back_splitted.has_value() && IsMergeable(target_extent_info, back_splitted.value())) {
        target_extent_info.len += back_splitted->len;
      } else if (IsMergeable(target_extent_info, current->GetExtentInfo())) {
        target_extent_info.len += erased->GetExtentInfo().len;
      }
    } else if (target_extent_info.fofs + target_extent_info.len < current->GetExtentInfo().fofs) {
      break;
    }

    current = next;
  }

  if (target_extent_info.blk_addr != kNullAddr) {
    new_extents.push_back(target_extent_info);
  }

  for (const auto &extent_info : new_extents) {
    if (!largest_extent_info_.has_value() || extent_info.len >= largest_extent_info_->len) {
      largest_extent_info_ = extent_info;
    }

    extent_node_tree_.insert(std::make_unique<ExtentNode>(extent_info));
  }

  return zx::ok();
}

zx::result<ExtentInfo> ExtentTree::LookupExtent(pgoff_t file_offset) {
  fs::SharedLock tree_lock(tree_lock_);
  auto it = extent_node_tree_.upper_bound(file_offset);
  if (it == extent_node_tree_.begin()) {
    return zx::error(ZX_ERR_NOT_FOUND);
  }

  --it;
  ZX_ASSERT(it->GetExtentInfo().fofs <= file_offset);
  if (it->GetExtentInfo().fofs + it->GetExtentInfo().len <= file_offset) {
    return zx::error(ZX_ERR_NOT_FOUND);
  }

  return zx::ok(it->GetExtentInfo());
}

ExtentInfo ExtentTree::GetLargestExtent() {
  fs::SharedLock lock(tree_lock_);
  if (!largest_extent_info_.has_value()) {
    return ExtentInfo{};
  }
  return largest_extent_info_.value();
}

void ExtentTree::Reset() {
  std::lock_guard lock(tree_lock_);

  auto current = extent_node_tree_.begin();
  while (current != extent_node_tree_.end()) {
    auto next = current;
    ++next;

    ZX_DEBUG_ASSERT(current->InContainer());
    extent_node_tree_.erase(current);
    current = next;
  }

  ZX_DEBUG_ASSERT(extent_node_tree_.is_empty());
}

}  // namespace f2fs
