// 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 "src/ui/scenic/lib/flatland/uber_struct_system.h"

#include <lib/syslog/cpp/macros.h>

namespace flatland {

// |UberStructSystem| implementations.

TransformHandle::InstanceId UberStructSystem::GetNextInstanceId() {
  // |latest_instance_id_| is only used for tests, but returning a member value can result in
  // threads "stealing" instance IDs from each other, so we return a local value here instead,
  // which does not have the same risk.
  auto next_instance_id = scheduling::GetNextSessionId();
  latest_instance_id_ = next_instance_id;
  return next_instance_id;
}

std::shared_ptr<UberStructSystem::UberStructQueue> UberStructSystem::AllocateQueueForSession(
    scheduling::SessionId session_id) {
  FX_DCHECK(!pending_structs_queues_.count(session_id));

  auto [queue_kv, success] =
      pending_structs_queues_.emplace(session_id, std::make_shared<UberStructQueue>());
  FX_DCHECK(success);

  return queue_kv->second;
}

void UberStructSystem::RemoveSession(scheduling::SessionId session_id) {
  FX_DCHECK(pending_structs_queues_.count(session_id));

  pending_structs_queues_.erase(session_id);
  uber_struct_map_.erase(session_id);
}

scheduling::SessionUpdater::UpdateResults UberStructSystem::UpdateSessions(
    const std::unordered_map<scheduling::SessionId, scheduling::PresentId>& sessions_to_update) {
  scheduling::SessionUpdater::UpdateResults results;
  for (const auto& [session_id, present_id] : sessions_to_update) {
    // Find the queue associated with this SessonId. It may not exist if the SessionId is
    // associated with a GFX session instead of a Flatland one.
    auto queue_kv = pending_structs_queues_.find(session_id);
    if (queue_kv == pending_structs_queues_.end()) {
      continue;
    }

    // Pop entries from that queue until the correct PresentId is found, then commit that
    // UberStruct to the snapshot. If the next pending UberStruct has a PresentId greater than the
    // target one, the update has failed because PresentIds are strictly increasing.
    bool successful_update = false;
    auto pending_struct = queue_kv->second->Pop();
    while (pending_struct.has_value()) {
      if (pending_struct->present_id == present_id) {
        uber_struct_map_[session_id] = std::move(pending_struct->uber_struct);
        successful_update = true;
        break;
      } else if (pending_struct->present_id > present_id) {
        break;
      }

      pending_struct = queue_kv->second->Pop();
    }

    if (!successful_update) {
      results.sessions_with_failed_updates.insert(session_id);
    }
  }
  return results;
}

void UberStructSystem::ForceUpdateAllSessions(size_t max_updates_per_queue) {
  // Pop entries from each queue until empty.
  for (auto& [session_id, queue] : pending_structs_queues_) {
    size_t update_count = 0;
    auto pending_struct = queue->Pop();
    while (pending_struct.has_value()) {
      uber_struct_map_[session_id] = std::move(pending_struct.value().uber_struct);
      pending_struct = queue->Pop();

      if (++update_count > max_updates_per_queue) {
        break;
      }
    }
  }
}

UberStruct::InstanceMap UberStructSystem::Snapshot() { return uber_struct_map_; }

size_t UberStructSystem::GetSessionCount() { return pending_structs_queues_.size(); }

TransformHandle::InstanceId UberStructSystem::GetLatestInstanceId() const {
  return latest_instance_id_;
}

// |UberStructSystem::Queue| implementations.

void UberStructSystem::UberStructQueue::Push(scheduling::PresentId present_id,
                                             std::unique_ptr<UberStruct> uber_struct) {
  FX_DCHECK(uber_struct);

  // Acquire the lock and update the appropriate queue.
  {
    std::scoped_lock lock(queue_mutex_);

    // PresentIds must be strictly increasing
    FX_DCHECK(pending_structs_.empty() || pending_structs_.back().present_id < present_id);

    pending_structs_.push({.present_id = present_id, .uber_struct = std::move(uber_struct)});
  }
}

std::optional<UberStructSystem::PendingUberStruct> UberStructSystem::UberStructQueue::Pop() {
  std::optional<PendingUberStruct> pending_struct;

  // Acquire the lock and fetch the next PendingUberStruct, if there is one.
  {
    std::scoped_lock lock(queue_mutex_);
    if (pending_structs_.empty()) {
      pending_struct = std::nullopt;
    } else {
      pending_struct = std::move(pending_structs_.front());
      pending_structs_.pop();
    }
  }

  return pending_struct;
}

size_t UberStructSystem::UberStructQueue::GetPendingSize() {
  std::scoped_lock lock(queue_mutex_);
  return pending_structs_.size();
}

}  // namespace flatland
