// Copyright 2018 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 "garnet/lib/ui/scenic/session.h"

#include <lib/async/cpp/task.h>
#include <lib/async/default.h>

namespace scenic_impl {

Session::Session(
    SessionId id,
    ::fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener)
    : id_(id), listener_(listener.Bind()), weak_factory_(this) {}

Session::~Session() = default;

void Session::Enqueue(::std::vector<fuchsia::ui::scenic::Command> cmds) {
  for (auto& cmd : cmds) {
    // TODO(SCN-710): This dispatch is far from optimal in terms of performance.
    // We need to benchmark it to figure out whether it matters.
    System::TypeId type_id = SystemTypeForCmd(cmd);
    auto dispatcher = type_id != System::TypeId::kInvalid
                          ? dispatchers_[type_id].get()
                          : nullptr;
    if (dispatcher) {
      dispatcher->DispatchCommand(std::move(cmd));
    } else {
      EnqueueEvent(std::move(cmd));
    }
  }
}

void Session::Present(uint64_t presentation_time,
                      ::std::vector<zx::event> acquire_fences,
                      ::std::vector<zx::event> release_fences,
                      PresentCallback callback) {
  // TODO(MZ-469): Move Present logic into Session.
  auto& dispatcher = dispatchers_[System::TypeId::kGfx];
  FXL_DCHECK(dispatcher);
  TempSessionDelegate* delegate =
      static_cast<TempSessionDelegate*>(dispatcher.get());
  delegate->Present(presentation_time, std::move(acquire_fences),
                    std::move(release_fences), std::move(callback));
}

void Session::SetCommandDispatchers(
    std::array<std::unique_ptr<CommandDispatcher>, System::TypeId::kMaxSystems>
        dispatchers) {
  for (size_t i = 0; i < System::TypeId::kMaxSystems; ++i) {
    dispatchers_[i] = std::move(dispatchers[i]);
  }
}

void Session::HitTest(uint32_t node_id, ::fuchsia::ui::gfx::vec3 ray_origin,
                      ::fuchsia::ui::gfx::vec3 ray_direction,
                      HitTestCallback callback) {
  auto& dispatcher = dispatchers_[System::TypeId::kGfx];
  FXL_DCHECK(dispatcher);
  TempSessionDelegate* delegate =
      static_cast<TempSessionDelegate*>(dispatcher.get());
  delegate->HitTest(node_id, std::move(ray_origin), std::move(ray_direction),
                    std::move(callback));
}

void Session::SetDebugName(std::string debug_name) {
  auto& dispatcher = dispatchers_[System::TypeId::kGfx];
  FXL_DCHECK(dispatcher);
  TempSessionDelegate* delegate =
      static_cast<TempSessionDelegate*>(dispatcher.get());
  delegate->SetDebugName(debug_name);
}

void Session::HitTestDeviceRay(::fuchsia::ui::gfx::vec3 ray_origin,
                               ::fuchsia::ui::gfx::vec3 ray_direction,
                               HitTestCallback callback) {
  auto& dispatcher = dispatchers_[System::TypeId::kGfx];
  FXL_DCHECK(dispatcher);
  TempSessionDelegate* delegate =
      reinterpret_cast<TempSessionDelegate*>(dispatcher.get());
  delegate->HitTestDeviceRay(std::move(ray_origin), std::move(ray_direction),
                             std::move(callback));
}

void Session::PostFlushTask() {
  // If this is the first EnqueueEvent() since the last FlushEvent(), post a
  // task to ensure that FlushEvents() is called.
  if (buffered_events_.empty()) {
    async::PostTask(async_get_default_dispatcher(),
                    [weak = weak_factory_.GetWeakPtr()] {
                      if (weak) {
                        weak->FlushEvents();
                      }
                    });
  }
}

void Session::EnqueueEvent(fuchsia::ui::gfx::Event event) {
  PostFlushTask();

  fuchsia::ui::scenic::Event scenic_event;
  scenic_event.set_gfx(std::move(event));
  buffered_events_.push_back(std::move(scenic_event));
}

void Session::EnqueueEvent(fuchsia::ui::scenic::Command unhandled_command) {
  PostFlushTask();

  fuchsia::ui::scenic::Event scenic_event;
  scenic_event.set_unhandled(std::move(unhandled_command));
  buffered_events_.push_back(std::move(scenic_event));
}

void Session::EnqueueEvent(fuchsia::ui::input::InputEvent event) {
  // Force an immediate flush, preserving event order.
  fuchsia::ui::scenic::Event scenic_event;
  scenic_event.set_input(std::move(event));
  buffered_events_.push_back(std::move(scenic_event));

  FlushEvents();
}

void Session::FlushEvents() {
  if (!buffered_events_.empty()) {
    if (listener_) {
      listener_->OnScenicEvent(std::move(buffered_events_));
    } else if (event_callback_) {
      // Only use the callback if there is no listener.  It is difficult to do
      // better because we std::move the argument into OnEvent().
      for (auto& evt : buffered_events_) {
        event_callback_(std::move(evt));
      }
    }
    buffered_events_.clear();
  }
}

void Session::ReportError(fxl::LogSeverity severity, std::string error_string) {
  switch (severity) {
    case fxl::LOG_INFO:
      FXL_LOG(INFO) << error_string;
      return;
    case fxl::LOG_WARNING:
      FXL_LOG(WARNING) << error_string;
      return;
    case fxl::LOG_ERROR:
      FXL_LOG(ERROR) << error_string;
      if (listener_) {
        listener_->OnScenicError(std::move(error_string));
      } else if (error_callback_) {
        // Only use the callback if there is no listener.  It is difficult to do
        // better because we std::move the argument into OnEvent().
        error_callback_(std::move(error_string));
      }
      return;
    case fxl::LOG_FATAL:
      FXL_LOG(FATAL) << error_string;
      return;
    default:
      // Invalid severity.
      FXL_DCHECK(false);
  }
}

}  // namespace scenic_impl
