// vi:set ft=cpp: -*- Mode: C++ -*-
/*
 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
 *               Alexander Warg <warg@os.inf.tu-dresden.de>
 *     economic rights: Technische Universität Dresden (Germany)
 *
 * License: see LICENSE.spdx (in this directory or the directories above)
 */

#pragma once

#include <l4/re/event_enums.h>
#include <l4/re/event>
#include <l4/re/event-sys.h>
#include <l4/re/util/icu_svr>
#include <l4/cxx/minmax>

#include <l4/sys/cxx/ipc_legacy>

namespace L4Re { namespace Util {

/**
 * Convenience wrapper for implementing an event server.
 *
 * \see L4Re::Event, L4Re::Util::Event_t
 */
template< typename SVR >
class Event_svr : public Icu_cap_array_svr<SVR>
{
private:
  typedef Icu_cap_array_svr<SVR> Icu_svr;

protected:
  L4::Cap<L4Re::Dataspace> _ds;
  typename Icu_svr::Irq _irq;

public:
  Event_svr() : Icu_svr(1, &_irq) {}

  L4_RPC_LEGACY_DISPATCH(L4Re::Event);
  L4_RPC_LEGACY_USING(Icu_svr);

  /// Handle L4Re::Event protocol
  long op_get_buffer(L4Re::Event::Rights, L4::Ipc::Cap<L4Re::Dataspace> &ds)
  {
    static_cast<SVR*>(this)->reset_event_buffer();
    ds = L4::Ipc::Cap<L4Re::Dataspace>(_ds, L4_CAP_FPAGE_RW);
    return 0;
  }

  long op_get_num_streams(L4Re::Event::Rights)
  { return static_cast<SVR*>(this)->get_num_streams(); }

  long op_get_stream_info(L4Re::Event::Rights, int idx, Event_stream_info &info)
  { return static_cast<SVR*>(this)->get_stream_info(idx, &info); }

  long op_get_stream_info_for_id(L4Re::Event::Rights, l4_umword_t id,
                                 Event_stream_info &info)
  { return static_cast<SVR*>(this)->get_stream_info_for_id(id, &info); }

  long op_get_axis_info(L4Re::Event::Rights, l4_umword_t id,
                        L4::Ipc::Array_in_buf<unsigned, unsigned long> const &axes,
                        L4::Ipc::Array_ref<Event_absinfo, unsigned long> &info)
  {
    unsigned naxes = cxx::min<unsigned>(L4RE_ABS_MAX, axes.length);

    info.length = 0;

    Event_absinfo _info[L4RE_ABS_MAX];
    int r = static_cast<SVR*>(this)->get_axis_info(id, naxes, axes.data, _info);
    if (r < 0)
      return r;

    for (unsigned i = 0; i < naxes; ++i)
      info.data[i] = _info[i];

    info.length = naxes;
    return r;
  }

  long op_get_stream_state_for_id(L4Re::Event::Rights, l4_umword_t stream_id,
                                  Event_stream_state &state)
  { return static_cast<SVR*>(this)->get_stream_state_for_id(stream_id, &state); }

  int get_num_streams() const { return 0; }
  int get_stream_info(int, L4Re::Event_stream_info *)
  { return -L4_EINVAL; }
  int get_stream_info_for_id(l4_umword_t, L4Re::Event_stream_info *)
  { return -L4_EINVAL; }
  int get_axis_info(l4_umword_t, unsigned /*naxes*/, unsigned const * /*axes*/,
                    L4Re::Event_absinfo *)
  { return -L4_EINVAL; }
  int get_stream_state_for_id(l4_umword_t, L4Re::Event_stream_state *)
  { return -L4_EINVAL; }
};

}}
