// Copyright 2017 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/ledger/bin/storage/impl/object_impl.h"

#include <zircon/status.h>

#include <utility>

#include "src/ledger/bin/storage/impl/btree/tree_node.h"
#include "src/ledger/bin/storage/impl/file_index.h"
#include "src/ledger/bin/storage/impl/file_index_generated.h"
#include "src/ledger/bin/storage/impl/object_digest.h"
#include "src/ledger/bin/storage/impl/object_identifier_encoding.h"
#include "src/ledger/bin/storage/public/data_source.h"
#include "src/ledger/bin/storage/public/types.h"
#include "src/ledger/lib/logging/logging.h"
#include "src/ledger/lib/vmo/strings.h"
#include "third_party/abseil-cpp/absl/strings/string_view.h"

namespace storage {

namespace {
uint64_t ToFullPages(uint64_t value) { return (value + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1)); }
}  // namespace

Status BasePiece::AppendReferences(ObjectReferencesAndPriority* references) const {
  // Chunks have no references.
  const auto digest_info = GetObjectDigestInfo(GetIdentifier().object_digest());
  if (digest_info.is_chunk()) {
    return Status::OK;
  }
  LEDGER_DCHECK(digest_info.piece_type == PieceType::INDEX);
  // The piece is an index: parse it and append its children to references.
  const FileIndex* file_index;
  RETURN_ON_ERROR(FileIndexSerialization::ParseFileIndex(GetData(), &file_index));
  for (const auto* child : *file_index->children()) {
    ObjectDigest child_digest =
        ToObjectIdentifier(child->object_identifier(), GetIdentifier().factory()).object_digest();
    // References must not contain inline pieces.
    if (GetObjectDigestInfo(child_digest).is_inlined()) {
      continue;
    }
    // Piece references are always eager.
    references->emplace(child_digest, KeyPriority::EAGER);
  }
  return Status::OK;
}

InlinePiece::InlinePiece(ObjectIdentifier identifier) : identifier_(std::move(identifier)) {}

absl::string_view InlinePiece::GetData() const {
  return ExtractObjectDigestData(identifier_.object_digest());
}

ObjectIdentifier InlinePiece::GetIdentifier() const { return identifier_; }

DataChunkPiece::DataChunkPiece(ObjectIdentifier identifier,
                               std::unique_ptr<DataSource::DataChunk> chunk)
    : identifier_(std::move(identifier)), chunk_(std::move(chunk)) {}

absl::string_view DataChunkPiece::GetData() const { return chunk_->Get(); }

ObjectIdentifier DataChunkPiece::GetIdentifier() const { return identifier_; }

LevelDBPiece::LevelDBPiece(ObjectIdentifier identifier, std::unique_ptr<leveldb::Iterator> iterator)
    : identifier_(std::move(identifier)), iterator_(std::move(iterator)) {}

absl::string_view LevelDBPiece::GetData() const {
  return convert::ExtendedStringView(iterator_->value());
}

ObjectIdentifier LevelDBPiece::GetIdentifier() const { return identifier_; }

Status BaseObject::AppendReferences(ObjectReferencesAndPriority* references) const {
  LEDGER_DCHECK(references);
  // Blobs have no references.
  const auto digest_info = GetObjectDigestInfo(GetIdentifier().object_digest());
  if (digest_info.object_type == ObjectType::BLOB) {
    return Status::OK;
  }
  LEDGER_DCHECK(digest_info.object_type == ObjectType::TREE_NODE);
  // Parse the object into a TreeNode.
  std::unique_ptr<const btree::TreeNode> node;
  RETURN_ON_ERROR(btree::TreeNode::FromObject(*this, &node));
  node->AppendReferences(references);
  return Status::OK;
}

ChunkObject::ChunkObject(std::unique_ptr<const Piece> piece) : piece_(std::move(piece)) {
  LEDGER_DCHECK(GetObjectDigestInfo(piece_->GetIdentifier().object_digest()).is_chunk())
      << "INDEX piece " << piece_->GetIdentifier() << " cannot be used as an object.";
}

std::unique_ptr<const Piece> ChunkObject::ReleasePiece() { return std::move(piece_); }

ObjectIdentifier ChunkObject::GetIdentifier() const { return piece_->GetIdentifier(); }

Status ChunkObject::GetData(absl::string_view* data) const {
  *data = piece_->GetData();
  return Status::OK;
}

VmoObject::VmoObject(ObjectIdentifier identifier, ledger::SizedVmo vmo)
    : identifier_(std::move(identifier)), vmo_(std::move(vmo)) {}

VmoObject::~VmoObject() {
  if (vmar_) {
    vmar_.destroy();
  }
}

ObjectIdentifier VmoObject::GetIdentifier() const { return identifier_; }

Status VmoObject::GetData(absl::string_view* data) const {
  RETURN_ON_ERROR(Initialize());
  *data = data_;
  return Status::OK;
}

Status VmoObject::GetVmo(ledger::SizedVmo* vmo) const {
  zx_status_t zx_status = vmo_.Duplicate(ZX_RIGHTS_BASIC | ZX_RIGHT_READ | ZX_RIGHT_MAP, vmo);
  if (zx_status != ZX_OK) {
    LEDGER_LOG(ERROR) << "Unable to duplicate a vmo: " << zx_status_get_string(zx_status);
    return Status::INTERNAL_ERROR;
  }
  return Status::OK;
}

Status VmoObject::Initialize() const {
  if (initialized_) {
    return Status::OK;
  }

  uintptr_t allocate_address;
  zx_status_t zx_status = zx::vmar::root_self()->allocate(
      0, ToFullPages(vmo_.size()),
      ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, &vmar_, &allocate_address);
  if (zx_status != ZX_OK) {
    LEDGER_LOG(ERROR) << "Unable to allocate VMAR: " << zx_status_get_string(zx_status);
    return Status::INTERNAL_ERROR;
  }

  char* mapped_address;
  zx_status =
      vmar_.map(0, vmo_.vmo(), 0, vmo_.size(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC,
                reinterpret_cast<uintptr_t*>(&mapped_address));
  if (zx_status != ZX_OK) {
    LEDGER_LOG(ERROR) << "Unable to map VMO: " << zx_status_get_string(zx_status);
    vmar_.reset();
    return Status::INTERNAL_ERROR;
  }

  data_ = absl::string_view(mapped_address, vmo_.size());
  initialized_ = true;

  return Status::OK;
}

}  // namespace storage
