#include "display_manager_service.h"

#include <pdx/channel_handle.h>
#include <pdx/default_transport/service_endpoint.h>
#include <private/dvr/display_rpc.h>
#include <sys/poll.h>

#include <array>

using android::pdx::Channel;
using android::pdx::LocalChannelHandle;
using android::pdx::Message;
using android::pdx::default_transport::Endpoint;
using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::rpc::IfAnyOf;

namespace {

// As a first line of defense, the display manager endpoint is only accessible
// to the user and group.

// TODO(dnicoara): Remove read/write permission for others. This is in here just
// to allow us to experiment with cast functionality from a plain old app.
constexpr mode_t kDisplayManagerEndpointFileMode =
    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;

constexpr size_t kMaxSurfacesPerRequest = 32;

}  // anonymous namespace

namespace android {
namespace dvr {

void DisplayManager::SetNotificationsPending(bool pending) {
  int ret = service_->ModifyChannelEvents(channel_id_, pending ? 0 : POLLIN,
                                          pending ? POLLIN : 0);
  ALOGE_IF(ret < 0,
           "DisplayManager::SetNotificationPending: Failed to modify channel "
           "events: %s",
           strerror(-ret));
}

DisplayManagerService::DisplayManagerService(
    const std::shared_ptr<DisplayService>& display_service)
    : BASE("DisplayManagerService",
           Endpoint::Create(DisplayManagerRPC::kClientPath,
                            kDisplayManagerEndpointFileMode)),
      display_service_(display_service) {
  display_service_->SetDisplayConfigurationUpdateNotifier(
      std::bind(&DisplayManagerService::OnDisplaySurfaceChange, this));
}

std::shared_ptr<pdx::Channel> DisplayManagerService::OnChannelOpen(
    pdx::Message& message) {
  // Prevent more than one display manager from registering at a time.
  if (display_manager_)
    REPLY_ERROR_RETURN(message, EPERM, nullptr);

  display_manager_ =
      std::make_shared<DisplayManager>(this, message.GetChannelId());
  return display_manager_;
}

void DisplayManagerService::OnChannelClose(
    pdx::Message& /*message*/, const std::shared_ptr<pdx::Channel>& channel) {
  // Unregister the display manager when the channel closes.
  if (display_manager_ == channel)
    display_manager_ = nullptr;
}

int DisplayManagerService::HandleMessage(pdx::Message& message) {
  auto channel = std::static_pointer_cast<DisplayManager>(message.GetChannel());

  switch (message.GetOp()) {
    case DisplayManagerRPC::GetSurfaceList::Opcode:
      DispatchRemoteMethod<DisplayManagerRPC::GetSurfaceList>(
          *this, &DisplayManagerService::OnGetSurfaceList, message);
      return 0;

    case DisplayManagerRPC::GetSurfaceBuffers::Opcode:
      DispatchRemoteMethod<DisplayManagerRPC::GetSurfaceBuffers>(
          *this, &DisplayManagerService::OnGetSurfaceBuffers, message);
      return 0;

    case DisplayManagerRPC::UpdateSurfaces::Opcode:
      DispatchRemoteMethod<DisplayManagerRPC::UpdateSurfaces>(
          *this, &DisplayManagerService::OnUpdateSurfaces, message);
      return 0;

    default:
      return Service::DefaultHandleMessage(message);
  }
}

std::vector<DisplaySurfaceInfo> DisplayManagerService::OnGetSurfaceList(
    pdx::Message& /*message*/) {
  std::vector<DisplaySurfaceInfo> items;

  display_service_->ForEachDisplaySurface([&items](
      const std::shared_ptr<DisplaySurface>& surface) mutable {
    DisplaySurfaceInfo item;

    item.surface_id = surface->surface_id();
    item.process_id = surface->process_id();
    item.type = surface->type();
    item.flags = 0;  // TODO(eieio)
    item.client_attributes = DisplaySurfaceAttributes{
        {DisplaySurfaceAttributeEnum::Visible,
         DisplaySurfaceAttributeValue{surface->client_visible()}},
        {DisplaySurfaceAttributeEnum::ZOrder,
         DisplaySurfaceAttributeValue{surface->client_z_order()}},
        {DisplaySurfaceAttributeEnum::Blur, DisplaySurfaceAttributeValue{0.f}}};
    item.manager_attributes = DisplaySurfaceAttributes{
        {DisplaySurfaceAttributeEnum::Visible,
         DisplaySurfaceAttributeValue{surface->manager_visible()}},
        {DisplaySurfaceAttributeEnum::ZOrder,
         DisplaySurfaceAttributeValue{surface->manager_z_order()}},
        {DisplaySurfaceAttributeEnum::Blur,
         DisplaySurfaceAttributeValue{surface->manager_blur()}}};

    items.push_back(item);
  });

  // The fact that we're in the message handler implies that display_manager_ is
  // not nullptr. No check required, unless this service becomes multi-threaded.
  display_manager_->SetNotificationsPending(false);

  return items;
}

std::vector<LocalChannelHandle> DisplayManagerService::OnGetSurfaceBuffers(
    pdx::Message& message, int surface_id) {
  std::shared_ptr<DisplaySurface> surface =
      display_service_->GetDisplaySurface(surface_id);
  if (!surface)
    REPLY_ERROR_RETURN(message, ENOENT, {});

  std::vector<LocalChannelHandle> consumers;
  int ret = surface->GetConsumers(&consumers);
  if (ret < 0) {
    ALOGE(
        "DisplayManagerService::OnGetDisplaySurfaceBuffers: Failed to get "
        "consumers for surface %d: %s",
        surface_id, strerror(-ret));
    REPLY_ERROR_RETURN(message, -ret, {});
  }

  return consumers;
}

int DisplayManagerService::OnUpdateSurfaces(
    pdx::Message& /*message*/,
    const std::map<int, DisplaySurfaceAttributes>& updates) {
  for (const auto& surface_update : updates) {
    const int surface_id = surface_update.first;
    const DisplaySurfaceAttributes& attributes = surface_update.second;

    std::shared_ptr<DisplaySurface> surface =
        display_service_->GetDisplaySurface(surface_id);

    if (!surface)
      return -ENOENT;

    for (const auto& attribute : attributes) {
      const auto& key = attribute.first;
      const auto* variant = &attribute.second;
      bool invalid_value = false;
      switch (key) {
        case DisplaySurfaceAttributeEnum::ZOrder:
          invalid_value =
              !IfAnyOf<int32_t>::Call(variant, [&surface](const auto& value) {
                surface->ManagerSetZOrder(value);
              });
          break;
        case DisplaySurfaceAttributeEnum::Visible:
          invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
              variant, [&surface](const auto& value) {
                surface->ManagerSetVisible(value);
              });
          break;
        case DisplaySurfaceAttributeEnum::Blur:
          invalid_value = !IfAnyOf<int32_t, int64_t, float>::Call(
              variant, [&surface](const auto& value) {
                surface->ManagerSetBlur(value);
              });
          break;
        default:
          ALOGW(
              "DisplayManagerService::OnUpdateSurfaces: Attempt to set invalid "
              "attribute %u on surface %d",
              key, surface_id);
          break;
      }

      if (invalid_value) {
        ALOGW(
            "DisplayManagerService::OnUpdateSurfaces: Failed to set display "
            "surface attribute '%s' because of incompatible type: %d",
            DisplaySurfaceAttributeEnum::ToString(key).c_str(),
            variant->index());
      }
    }
  }

  // Reconfigure the display layers for any active surface changes.
  display_service_->UpdateActiveDisplaySurfaces();
  return 0;
}

void DisplayManagerService::OnDisplaySurfaceChange() {
  if (display_manager_) {
    display_manager_->SetNotificationsPending(true);
  } else {
    // If there isn't a display manager registered, default all display surfaces
    // to visible.
    display_service_->ForEachDisplaySurface(
        [](const std::shared_ptr<DisplaySurface>& surface) {
          surface->ManagerSetVisible(true);
        });
    display_service_->UpdateActiveDisplaySurfaces();
  }
}

}  // namespace dvr
}  // namespace android
