// 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 <lib/syslog/global.h>
#include <lib/ui/scenic/cpp/commands.h>
#include <lib/ui/scenic/cpp/commands_sizing.h>
#include <lib/ui/scenic/cpp/session.h>
#include <zircon/assert.h>

namespace scenic {

SessionPtrAndListenerRequest CreateScenicSessionPtrAndListenerRequest(
    fuchsia::ui::scenic::Scenic* scenic, async_dispatcher_t* dispatcher) {
  fuchsia::ui::scenic::SessionPtr session;
  fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener_handle;
  auto listener_request = listener_handle.NewRequest();

  scenic->CreateSession(session.NewRequest(dispatcher), std::move(listener_handle));

  return {std::move(session), std::move(listener_request)};
}

Session::Session(fuchsia::ui::scenic::SessionPtr session,
                 fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener> session_listener,
                 async_dispatcher_t* dispatcher)
    : session_(std::move(session)), session_listener_binding_(this) {
  ZX_DEBUG_ASSERT(session_);
  if (session_listener.is_valid())
    session_listener_binding_.Bind(std::move(session_listener), dispatcher);
}

Session::Session(fuchsia::ui::scenic::Scenic* scenic, async_dispatcher_t* dispatcher)
    : session_listener_binding_(this) {
  ZX_DEBUG_ASSERT(scenic);
  scenic->CreateSession(session_.NewRequest(dispatcher),
                        session_listener_binding_.NewBinding(dispatcher));
}

Session::Session(fuchsia::ui::scenic::Scenic* scenic,
                 fidl::InterfaceRequest<fuchsia::ui::views::Focuser> view_focuser,
                 async_dispatcher_t* dispatcher)
    : session_listener_binding_(this) {
  ZX_DEBUG_ASSERT(scenic);
  scenic->CreateSession2(session_.NewRequest(dispatcher),
                         session_listener_binding_.NewBinding(dispatcher), std::move(view_focuser));
}

Session::Session(SessionPtrAndListenerRequest session_and_listener, async_dispatcher_t* dispatcher)
    : Session(std::move(session_and_listener.first), std::move(session_and_listener.second),
              dispatcher) {}

Session::~Session() {
  ZX_DEBUG_ASSERT_MSG(resource_count_ == 0, "Some resources outlived the session: %u",
                      resource_count_);
}
void Session::set_on_frame_presented_handler(OnFramePresentedCallback callback) {
  session_.events().OnFramePresented = std::move(callback);
}

uint32_t Session::AllocResourceId() {
  uint32_t resource_id = next_resource_id_++;
  ZX_DEBUG_ASSERT(resource_id);
  resource_count_++;
  return resource_id;
}

void Session::ReleaseResource(uint32_t resource_id) {
  resource_count_--;
  Enqueue(NewReleaseResourceCmd(resource_id));
}

void Session::Enqueue(fuchsia::ui::gfx::Command command) {
  Enqueue(NewCommand(std::move(command)));
}

void Session::Enqueue(fuchsia::ui::input::Command command) {
  Enqueue(NewCommand(std::move(command)));
}

void Session::Enqueue(fuchsia::ui::scenic::Command command) {
  auto size = measure_tape::fuchsia::ui::scenic::Measure(command);

  // If we would go over caps by adding this command, flush the commands we have
  // accumulated so far.
  if (commands_.size() > 0 &&
      (static_cast<int64_t>(ZX_CHANNEL_MAX_MSG_BYTES) < commands_num_bytes_ + size.num_bytes ||
       static_cast<int64_t>(ZX_CHANNEL_MAX_MSG_HANDLES) < commands_num_handles_ + size.num_handles)) {
    Flush();
  }

  commands_.push_back(std::move(command));
  commands_num_bytes_ += size.num_bytes;
  commands_num_handles_ += size.num_handles;

  // Eagerly flush all input commands.
  if (commands_.back().Which() == fuchsia::ui::scenic::Command::Tag::kInput) {
    Flush();
  }
}

void Session::EnqueueAcquireFence(zx::event fence) {
  ZX_DEBUG_ASSERT(fence);
  acquire_fences_.push_back(std::move(fence));
}

void Session::EnqueueReleaseFence(zx::event fence) {
  ZX_DEBUG_ASSERT(fence);
  release_fences_.push_back(std::move(fence));
}

void Session::Flush() {
  if (!commands_.empty()) {
    session_->Enqueue(std::move(commands_));

    // After being moved, |commands_| is in a "valid but unspecified state";
    // see http://en.cppreference.com/w/cpp/utility/move.  Calling clear() makes
    // it safe to continue using.
    commands_.clear();
    commands_num_bytes_ = kEnqueueRequestBaseNumBytes;
    commands_num_handles_ = 0;
  }
}

void Session::Present(uint64_t presentation_time, PresentCallback callback) {
  ZX_DEBUG_ASSERT(session_);
  Flush();

  session_->Present(presentation_time, std::move(acquire_fences_), std::move(release_fences_),
                    std::move(callback));
}

void Session::Present(zx::time presentation_time, PresentCallback callback) {
  Present(presentation_time.get(), std::move(callback));
}

void Session::Present2(zx_duration_t requested_presentation_time,
                       zx_duration_t requested_prediction_span,
                       Present2Callback immediate_callback) {
  ZX_DEBUG_ASSERT(session_);
  Flush();

  fuchsia::ui::scenic::Present2Args args;
  args.set_requested_presentation_time(requested_presentation_time);
  args.set_release_fences(std::move(release_fences_));
  args.set_acquire_fences(std::move(acquire_fences_));
  args.set_requested_prediction_span(requested_prediction_span);

  session_->Present2(std::move(args), std::move(immediate_callback));
}

void Session::RequestPresentationTimes(zx_duration_t requested_prediction_span,
                                       RequestPresentationTimesCallback callback) {
  session_->RequestPresentationTimes(requested_prediction_span, std::move(callback));
}

void Session::Unbind() {
  ZX_DEBUG_ASSERT(session_);
  ZX_DEBUG_ASSERT(!session_handle_);
  session_handle_ = session_.Unbind();
  session_ = nullptr;
}

void Session::Rebind() {
  ZX_DEBUG_ASSERT(!session_);
  ZX_DEBUG_ASSERT(session_handle_);
  session_ = fuchsia::ui::scenic::SessionPtr(session_handle_.Bind());
  session_handle_ = nullptr;
}

void Session::OnScenicError(std::string error) {
  FX_LOGF(ERROR, nullptr, "Scenic Session in client: %s", error.c_str());
}

void Session::OnScenicEvent(std::vector<fuchsia::ui::scenic::Event> events) {
  if (event_handler_)
    event_handler_(std::move(events));
}

void Session::SetDebugName(const std::string& debug_name) { session_->SetDebugName(debug_name); }

}  // namespace scenic
