// Copyright 2022 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cobalt/cache/memory_capped_directory.h"

#include <algorithm>

#include "base/files/file_util.h"
#include "base/strings/string_number_conversions.h"
#include "starboard/directory.h"

namespace cobalt {
namespace cache {

MemoryCappedDirectory::FileInfo::FileInfo(
    base::FilePath directory_path, base::FileEnumerator::FileInfo file_info)
    : file_path_(directory_path.Append(file_info.GetName())),
      last_modified_time_(file_info.GetLastModifiedTime()),
      size_(static_cast<uint32_t>(file_info.GetSize())) {}

MemoryCappedDirectory::FileInfo::FileInfo(base::FilePath file_path,
                                          base::Time last_modified_time,
                                          uint32_t size)
    : file_path_(file_path),
      last_modified_time_(last_modified_time),
      size_(size) {}

bool MemoryCappedDirectory::FileInfo::OldestFirst::operator()(
    const MemoryCappedDirectory::FileInfo& left,
    const MemoryCappedDirectory::FileInfo& right) const {
  return left.last_modified_time_ > right.last_modified_time_;
}

// static
std::unique_ptr<MemoryCappedDirectory> MemoryCappedDirectory::Create(
    const base::FilePath& directory_path, uint32_t max_size) {
  if (!SbDirectoryCreate(directory_path.value().c_str())) {
    return nullptr;
  }
  auto memory_capped_directory = std::unique_ptr<MemoryCappedDirectory>(
      new MemoryCappedDirectory(directory_path, max_size));
  auto* heap = &memory_capped_directory->file_info_heap_;
  base::AutoLock auto_lock(memory_capped_directory->lock_);
  base::FileEnumerator file_enumerator(directory_path, false,
                                       base::FileEnumerator::FILES);
  uint32_t size = 0u;
  while (!file_enumerator.Next().empty()) {
    MemoryCappedDirectory::FileInfo file_info(directory_path,
                                              file_enumerator.GetInfo());
    heap->push_back(file_info);
    memory_capped_directory->file_sizes_[file_info.file_path_] =
        file_info.size_;
    memory_capped_directory->size_ += file_info.size_;
  }
  if (heap->size() > 1) {
    std::make_heap(heap->begin(), heap->end(),
                   MemoryCappedDirectory::FileInfo::OldestFirst());
  }
  return memory_capped_directory;
}

void MemoryCappedDirectory::Delete(uint32_t key) {
  base::AutoLock auto_lock(lock_);
  auto file_path = GetFilePath(key);
  if (base::PathExists(file_path)) {
    base::DeleteFile(file_path, false);
  }
  file_sizes_.erase(file_path);
  auto* heap = &file_info_heap_;
  for (auto it = heap->begin(); it != heap->end(); ++it) {
    if (it->file_path_ == file_path) {
      size_ -= it->size_;
      heap->erase(it);
      if (heap->size() > 1) {
        std::make_heap(heap->begin(), heap->end(),
                       MemoryCappedDirectory::FileInfo::OldestFirst());
      }
      return;
    }
  }
}

void MemoryCappedDirectory::DeleteAll() {
  base::AutoLock auto_lock(lock_);
  // Recursively delete the contents of the directory_path_.
  base::DeleteFile(directory_path_, true);
  // Re-create the directory_path_ which will now be empty.
  SbDirectoryCreate(directory_path_.value().c_str());
  file_info_heap_.clear();
  file_sizes_.clear();
  size_ = 0;
}

std::unique_ptr<std::vector<uint8_t>> MemoryCappedDirectory::Retrieve(
    uint32_t key) {
  auto file_path = GetFilePath(key);
  auto it = file_sizes_.find(file_path);
  if (it == file_sizes_.end()) {
    return nullptr;
  }
  auto size = it->second;
  auto data = std::make_unique<std::vector<uint8_t>>(static_cast<size_t>(size));
  int bytes_read = base::ReadFile(
      file_path, reinterpret_cast<char*>(data->data()), static_cast<int>(size));
  if (bytes_read != size) {
    return nullptr;
  }
  return data;
}

void MemoryCappedDirectory::Store(uint32_t key,
                                  const std::vector<uint8_t>& data) {
  base::AutoLock auto_lock(lock_);
  auto file_path = GetFilePath(key);
  uint32_t new_entry_size = static_cast<uint32_t>(data.size());
  if (!EnsureEnoughSpace(new_entry_size)) {
    return;
  }
  int bytes_written = base::WriteFile(
      file_path, reinterpret_cast<const char*>(data.data()), data.size());
  if (bytes_written != data.size()) {
    base::DeleteFile(file_path, false);
    return;
  }
  size_ += new_entry_size;
  auto* heap = &file_info_heap_;
  heap->push_back(MemoryCappedDirectory::FileInfo(file_path, base::Time::Now(),
                                                  new_entry_size));
  std::push_heap(heap->begin(), heap->end(),
                 MemoryCappedDirectory::FileInfo::OldestFirst());
  file_sizes_[file_path] = new_entry_size;
}

void MemoryCappedDirectory::Resize(uint32_t size) {
  if (max_size_ > size) {
    uint32_t space_to_be_freed = max_size_ - size;
    EnsureEnoughSpace(space_to_be_freed);
  }
  max_size_ = size;
}

MemoryCappedDirectory::MemoryCappedDirectory(
    const base::FilePath& directory_path, uint32_t max_size)
    : directory_path_(directory_path), max_size_(max_size), size_(0u) {}

base::FilePath MemoryCappedDirectory::GetFilePath(uint32_t key) const {
  return directory_path_.Append(base::UintToString(key));
}

bool MemoryCappedDirectory::EnsureEnoughSpace(
    uint32_t additional_size_required) {
  if (additional_size_required > max_size_) {
    return false;
  }
  auto* heap = &file_info_heap_;
  while (size_ + additional_size_required > max_size_) {
    if (heap->size() == 0) {
      return false;
    }
    std::pop_heap(heap->begin(), heap->end(),
                  MemoryCappedDirectory::FileInfo::OldestFirst());
    auto removed = heap->back();
    size_ -= removed.size_;
    base::DeleteFile(removed.file_path_, false);
    file_sizes_.erase(removed.file_path_);
    heap->pop_back();
  }
  return true;
}

}  // namespace cache
}  // namespace cobalt
