/*
 * Copyright © Canonical Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef MIR_WAYLANDRS_CLIENT
#define MIR_WAYLANDRS_CLIENT

#include "ffi_fwd.h"

#include <cstdint>
#include <memory>
#include <optional>

class MirEvent;

namespace mir
{
namespace scene { class Session; }

namespace wayland_rs
{
/// The raw Rust client handle that arrives over the FFI boundary.
using RawWlClient = rust::Box<WaylandClient>;

/// An opaque, comparable identity for a `RawWlClient`. Unlike `RawWlClient` this
/// can outlive the connection and is used to resolve/remove a `Client`.
using RawWlClientId = rust::Box<WaylandClientId>;

/// A C++ interface wrapping a connected Wayland client (the Rust
/// `WaylandClient`). Every generated Wayland object holds a
/// `std::shared_ptr<Client>` so that it — and any user-written derived class —
/// can interact with the client it serves without touching the raw FFI type.
///
/// This is the analogue of `mir::wayland::Client`, but built on the wayland_rs
/// (Rust) backend rather than libwayland's `wl_client`. It is abstract:
/// concrete subclasses supply the session/serial state and are created
/// elsewhere (e.g. by the frontend), then stored in a `WaylandClientRegistry`.
class Client
{
public:
    Client() = default;
    virtual ~Client() = default;

    Client(Client const&) = delete;
    Client& operator=(Client const&) = delete;

    /// The underlying raw Rust client.
    virtual auto raw_client() const -> RawWlClient const& = 0;

    /// True if the client's destroy listener has fired. The client object
    /// continues to exist after this until all resources have been cleaned up.
    virtual auto is_being_destroyed() const -> bool = 0;

    /// The Mir session associated with this client. Be careful when using this
    /// that it's actually the session you want. All clients have a session but
    /// the surfaces they create may get associated with additional sessions.
    virtual auto client_session() const -> std::shared_ptr<scene::Session> = 0;

    /// Generate a new serial, and keep track of it attached to the given event.
    /// Event may be null.
    virtual auto next_serial(std::shared_ptr<MirEvent const> event) -> uint32_t = 0;

    /// Returns the event associated with the given serial. Returns
    /// optional{nullptr} if the serial is known, but not associated with an
    /// event. Returns nullopt if the serial is unknown/invalid.
    virtual auto event_for(uint32_t serial) -> std::optional<std::shared_ptr<MirEvent const>> = 0;

    /// The XDG output protocol implementation sends the Mir-internal logical
    /// position and scale of outputs multiplied by this. It's currently just
    /// used by XWayland.
    /// @{
    virtual void set_output_geometry_scale(float scale) = 0;
    virtual auto output_geometry_scale() -> float = 0;
    /// @}
};
}
}

#endif // MIR_WAYLANDRS_CLIENT
