//
// channel
// ~~~~~~~
// A channel of values.
//
// Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef EXECUTORS_EXPERIMENTAL_CHANNEL_HEADER
#define EXECUTORS_EXPERIMENTAL_CHANNEL_HEADER

#include <deque>
#include <system_error>
#include <experimental/executor>
#include <experimental/bits/channel_base.h>

namespace std {
namespace experimental {
inline namespace concurrency_v1 {

template <class _T,
  class _Cont = typename conditional<is_same<_T, void>::value, void, deque<_T>>::type>
class channel
  : private __channel_base
{
public:
  typedef typename _Cont::value_type value_type;

  // construct / copy / destroy:

  channel();
  explicit channel(size_t __capacity);
  explicit channel(execution_context& __c);
  channel(execution_context& __c, size_t __capacity);
  channel(const channel&) = delete;
  channel(channel&& __c);

  channel& operator=(const channel&) = delete;
  channel& operator=(channel&& __c);

  ~channel();

  // channel operations:

  execution_context& context();

  size_t capacity() const;
  bool is_open() const;
  void reset();
  void close();
  void cancel();
  bool ready() const;

  template <class _U> void put(_U&& __u);
  template <class _U> void put(_U&& __u, error_code& __ec);
  template <class _U, class _CompletionToken> auto put(_U&& __u, _CompletionToken&& __token);

  value_type get();
  value_type get(error_code& __ec);
  template <class _CompletionToken> auto get(_CompletionToken&& __token);

private:
  class _Op;
  template <class> class _PutOp;
  template <class> class _GetOp;
  void _Start_put(_Op* __op);
  void _Start_get(_Op* __op);
  _Cont _M_buffer;
};

template <class _Cont>
class channel<void, _Cont>
  : private __channel_base
{
public:
  typedef void value_type;

  // construct / copy / destroy:

  channel();
  explicit channel(size_t __capacity);
  explicit channel(execution_context& __c);
  channel(execution_context& __c, size_t __capacity);
  channel(const channel&) = delete;
  channel(channel&& __c);

  channel& operator=(const channel&) = delete;
  channel& operator=(channel&& __c);

  ~channel();

  // channel operations:

  execution_context& context();

  size_t capacity() const;
  bool is_open() const;
  void reset();
  void close();
  void cancel();
  bool ready() const;

  void put();
  void put(error_code& __ec);
  template <class _CompletionToken> auto put(_CompletionToken&& __token);

  void get();
  void get(error_code& __ec);
  template <class _CompletionToken> auto get(_CompletionToken&& __token);

private:
  template <class> class _Op;
  void _Start_put(__channel_op* __op);
  void _Start_get(__channel_op* __op);
  size_t _M_buffered;
};

} // inline namespace concurrency_v1
} // namespace experimental
} // namespace std

#include <experimental/bits/channel.h>
#include <experimental/bits/channel_void.h>

#endif
