// Copyright 2019 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 <lib/fdio/vfs.h>
#include <lib/vfs/cpp/internal/dirent_filler.h>
#include <lib/vfs/cpp/pseudo_dir.h>

#include <mutex>

namespace vfs {

PseudoDir::PseudoDir() : next_node_id_(kDotId + 1) {}

PseudoDir::~PseudoDir() = default;

zx_status_t PseudoDir::AddSharedEntry(std::string name,
                                      std::shared_ptr<Node> vn) {
  ZX_DEBUG_ASSERT(vn);

  auto id = next_node_id_++;
  return AddEntry(
      std::make_unique<SharedEntry>(id, std::move(name), std::move(vn)));
}

zx_status_t PseudoDir::AddEntry(std::string name, std::unique_ptr<Node> vn) {
  ZX_DEBUG_ASSERT(vn);

  auto id = next_node_id_++;
  return AddEntry(
      std::make_unique<UniqueEntry>(id, std::move(name), std::move(vn)));
}

zx_status_t PseudoDir::AddEntry(std::unique_ptr<Entry> entry) {
  ZX_DEBUG_ASSERT(entry);

  if (!vfs::internal::IsValidName(entry->name())) {
    return ZX_ERR_INVALID_ARGS;
  }

  std::lock_guard<std::mutex> guard(mutex_);

  if (entries_by_name_.find(entry->name()) != entries_by_name_.end()) {
    return ZX_ERR_ALREADY_EXISTS;
  }
  entries_by_name_[entry->name()] = entry.get();
  auto id = entry->id();
  entries_by_id_.emplace_hint(entries_by_id_.end(), id, std::move(entry));

  return ZX_OK;
}

zx_status_t PseudoDir::RemoveEntry(const std::string& name) {
  std::lock_guard<std::mutex> guard(mutex_);
  auto entry = entries_by_name_.find(name);
  if (entry == entries_by_name_.end()) {
    return ZX_ERR_NOT_FOUND;
  }
  entries_by_id_.erase(entry->second->id());
  entries_by_name_.erase(name);

  return ZX_OK;
}

zx_status_t PseudoDir::RemoveEntry(const std::string& name, Node* node) {
  std::lock_guard<std::mutex> guard(mutex_);
  auto entry = entries_by_name_.find(name);
  if (entry == entries_by_name_.end() || entry->second->node() != node) {
    return ZX_ERR_NOT_FOUND;
  }
  entries_by_id_.erase(entry->second->id());
  entries_by_name_.erase(name);

  return ZX_OK;
}

zx_status_t PseudoDir::Lookup(const std::string& name,
                              vfs::internal::Node** out_node) const {
  std::lock_guard<std::mutex> guard(mutex_);

  auto search = entries_by_name_.find(name);
  if (search != entries_by_name_.end()) {
    *out_node = search->second->node();
    return ZX_OK;
  } else {
    return ZX_ERR_NOT_FOUND;
  }
}

zx_status_t PseudoDir::Readdir(uint64_t offset, void* data, uint64_t len,
                               uint64_t* out_offset, uint64_t* out_actual) {
  vfs::internal::DirentFiller df(data, len);
  *out_actual = 0;
  *out_offset = offset;
  if (offset < kDotId) {
    if (df.Next(".", 1, fuchsia::io::DIRENT_TYPE_DIRECTORY,
                fuchsia::io::INO_UNKNOWN) != ZX_OK) {
      *out_actual = df.GetBytesFilled();
      return ZX_ERR_INVALID_ARGS;  // out_actual would be 0
    }
    (*out_offset)++;
  }

  std::lock_guard<std::mutex> guard(mutex_);

  for (auto it = entries_by_id_.upper_bound(*out_offset);
       it != entries_by_id_.end(); ++it) {
    fuchsia::io::NodeAttributes attr;
    auto d_type = fuchsia::io::DIRENT_TYPE_UNKNOWN;
    auto ino = fuchsia::io::INO_UNKNOWN;
    if (it->second->node()->GetAttr(&attr) == ZX_OK) {
      d_type = ((fuchsia::io::MODE_TYPE_MASK & attr.mode) >> 12);
      ino = attr.id;
    }

    if (df.Next(it->second->name(), d_type, ino) != ZX_OK) {
      *out_actual = df.GetBytesFilled();
      if (*out_actual == 0) {
        // no space to fill even 1 dentry
        return ZX_ERR_INVALID_ARGS;
      }
      return ZX_OK;
    }
    *out_offset = it->second->id();
  }

  *out_actual = df.GetBytesFilled();
  return ZX_OK;
}

bool PseudoDir::IsEmpty() const {
  std::lock_guard<std::mutex> guard(mutex_);
  return entries_by_name_.size() == 0;
}

PseudoDir::Entry::Entry(uint64_t id, std::string name)
    : id_(id), name_(std::move(name)) {}

PseudoDir::Entry::~Entry() = default;

PseudoDir::SharedEntry::SharedEntry(uint64_t id, std::string name,
                                    std::shared_ptr<Node> node)
    : Entry(id, std::move(name)), node_(std::move(node)) {}

vfs::internal::Node* PseudoDir::SharedEntry::node() const {
  return node_.get();
}

PseudoDir::SharedEntry::~SharedEntry() = default;

PseudoDir::UniqueEntry::UniqueEntry(uint64_t id, std::string name,
                                    std::unique_ptr<Node> node)
    : Entry(id, std::move(name)), node_(std::move(node)) {}

vfs::internal::Node* PseudoDir::UniqueEntry::node() const {
  return node_.get();
}

PseudoDir::UniqueEntry::~UniqueEntry() = default;

}  // namespace vfs
