// Copyright 2016 The Chromium 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 UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OBJECT_H_
#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OBJECT_H_

#include <wayland-client-core.h>

#include <memory>

struct wl_buffer;
struct wl_compositor;
struct wl_output;
struct wl_pointer;
struct wl_registry;
struct wl_seat;
struct wl_shm;
struct wl_shm_pool;
struct wl_surface;
struct xdg_shell;
struct xdg_surface;

namespace wl {

template <typename T>
struct ObjectTraits;

template <>
struct ObjectTraits<wl_buffer> {
  static const wl_interface* interface;
  static void (*deleter)(wl_buffer*);
};

template <>
struct ObjectTraits<wl_compositor> {
  static const wl_interface* interface;
  static void (*deleter)(wl_compositor*);
};

template <>
struct ObjectTraits<wl_display> {
  static const wl_interface* interface;
  static void (*deleter)(wl_display*);
};

template <>
struct ObjectTraits<wl_output> {
  static const wl_interface* interface;
  static void (*deleter)(wl_output*);
};

template <>
struct ObjectTraits<wl_pointer> {
  static const wl_interface* interface;
  static void (*deleter)(wl_pointer*);
};

template <>
struct ObjectTraits<wl_registry> {
  static const wl_interface* interface;
  static void (*deleter)(wl_registry*);
};

template <>
struct ObjectTraits<wl_seat> {
  static const wl_interface* interface;
  static void (*deleter)(wl_seat*);
};

template <>
struct ObjectTraits<wl_shm> {
  static const wl_interface* interface;
  static void (*deleter)(wl_shm*);
};

template <>
struct ObjectTraits<wl_shm_pool> {
  static const wl_interface* interface;
  static void (*deleter)(wl_shm_pool*);
};

template <>
struct ObjectTraits<wl_surface> {
  static const wl_interface* interface;
  static void (*deleter)(wl_surface*);
};

template <>
struct ObjectTraits<xdg_shell> {
  static const wl_interface* interface;
  static void (*deleter)(xdg_shell*);
};

template <>
struct ObjectTraits<xdg_surface> {
  static const wl_interface* interface;
  static void (*deleter)(xdg_surface*);
};

struct Deleter {
  template <typename T>
  void operator()(T* obj) {
    ObjectTraits<T>::deleter(obj);
  }
};

template <typename T>
class Object : public std::unique_ptr<T, Deleter> {
 public:
  Object() {}
  explicit Object(T* obj) : std::unique_ptr<T, Deleter>(obj) {}

  uint32_t id() {
    return wl_proxy_get_id(
        reinterpret_cast<wl_proxy*>(std::unique_ptr<T, Deleter>::get()));
  }
};

template <typename T>
wl::Object<T> Bind(wl_registry* registry, uint32_t name, uint32_t version) {
  return wl::Object<T>(static_cast<T*>(
      wl_registry_bind(registry, name, ObjectTraits<T>::interface, version)));
}

}  // namespace wl

#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OBJECT_H_
