// 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.

#ifndef FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_LOCATION_H_
#define FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_LOCATION_H_

#include <optional>
#include <type_traits>

#include "impeller/archivist/archivable.h"
#include "impeller/archivist/archive.h"
#include "impeller/base/allocation.h"

namespace impeller {

class Archive;
class ArchiveClassRegistration;
class ArchiveStatement;

class ArchiveLocation {
 public:
  PrimaryKey GetPrimaryKey() const;

  template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
  bool Write(const std::string& member, T item) {
    return WriteIntegral(member, static_cast<int64_t>(item));
  }

  bool Write(const std::string& member, double item);

  bool Write(const std::string& member, const std::string& item);

  bool Write(const std::string& member, const Allocation& allocation);

  template <class T,
            class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
  bool WriteArchivable(const std::string& member, const T& other) {
    const ArchiveDef& otherDef = T::ArchiveDefinition;
    return Write(member, otherDef, other);
  }

  template <class T, class = std::enable_if_t<std::is_enum<T>::value>>
  bool WriteEnum(const std::string& member, const T& item) {
    return WriteIntegral(member, static_cast<int64_t>(item));
  }

  template <class T,
            class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
  bool Write(const std::string& member, const std::vector<T>& items) {
    /*
     *  All items in the vector are individually encoded and their keys noted
     */
    std::vector<int64_t> members;
    members.reserve(items.size());

    const ArchiveDef& itemDefinition = T::kArchiveDefinition;
    for (const auto& item : items) {
      auto row_id = context_.ArchiveInstance(itemDefinition, item);
      if (!row_id.has_value()) {
        return false;
      }
      members.emplace_back(row_id.value());
    }

    /*
     *  The keys are flattened into the vectors table. Write to that table
     */
    auto vectorInsert = WriteVectorKeys(std::move(members));

    if (!vectorInsert.has_value()) {
      return false;
    }

    return WriteIntegral(member, vectorInsert.value());
  }

  template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
  bool Read(const std::string& member, T& item) {
    int64_t decoded = 0;
    auto result = ReadIntegral(member, decoded);
    item = static_cast<T>(decoded);
    return result;
  }

  bool Read(const std::string& member, double& item);

  bool Read(const std::string& member, std::string& item);

  bool Read(const std::string& member, Allocation& allocation);

  template <class T,
            class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
  bool ReadArchivable(const std::string& member, T& other) {
    const ArchiveDef& otherDef = T::ArchiveDefinition;
    return decode(member, otherDef, other);
  }

  template <class T, class = std::enable_if_t<std::is_enum<T>::value>>
  bool ReadEnum(const std::string& member, T& item) {
    int64_t desugared = 0;
    if (ReadIntegral(member, desugared)) {
      item = static_cast<T>(desugared);
      return true;
    }
    return false;
  }

  template <class T,
            class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
  bool Read(const std::string& member, std::vector<T>& items) {
    /*
     *  From the member, find the foreign key of the vector
     */
    int64_t vectorForeignKey = 0;
    if (!ReadIntegral(member, vectorForeignKey)) {
      return false;
    }

    /*
     *  Get vector keys
     */
    std::vector<int64_t> keys;
    if (!ReadVectorKeys(vectorForeignKey, keys)) {
      return false;
    }

    const ArchiveDef& otherDef = T::kArchiveDefinition;
    for (const auto& key : keys) {
      items.emplace_back();

      if (!context_.UnarchiveInstance(otherDef, key, items.back())) {
        return false;
      }
    }

    return true;
  }

 private:
  Archive& context_;
  ArchiveStatement& statement_;
  const ArchiveClassRegistration& registration_;
  PrimaryKey primary_key_;

  friend class Archive;

  ArchiveLocation(Archive& context,
                  ArchiveStatement& statement,
                  const ArchiveClassRegistration& registration,
                  PrimaryKey name);

  bool WriteIntegral(const std::string& member, int64_t item);

  bool ReadIntegral(const std::string& member, int64_t& item);

  std::optional<int64_t> WriteVectorKeys(std::vector<int64_t>&& members);

  bool ReadVectorKeys(PrimaryKey name, std::vector<int64_t>& members);

  bool Write(const std::string& member,
             const ArchiveDef& otherDef,
             const Archivable& other);

  bool Read(const std::string& member,
            const ArchiveDef& otherDef,
            Archivable& other);

  ArchiveLocation(const ArchiveLocation&) = delete;

  ArchiveLocation& operator=(const ArchiveLocation&) = delete;
};

}  // namespace impeller

#endif  // FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_LOCATION_H_
