#ifndef ZMQ_BZOOK_SOCKETS_H
#define ZMQ_BZOOK_SOCKETS_H

#include <zmq.h>
#include <chrono>
#include <string>

namespace bzook
{

// Forward declarations.
class Context;

enum class SocketType: int
{
   REQ = ZMQ_REQ,
   REP = ZMQ_REP,
   DEALER = ZMQ_DEALER,
   ROUTER = ZMQ_ROUTER,
   PUB = ZMQ_PUB,
   SUB = ZMQ_SUB,
   XPUB = ZMQ_XPUB,
   XSUB = ZMQ_XSUB,
   PUSH = ZMQ_PUSH,
   PULL = ZMQ_PULL,
   PAIR = ZMQ_PAIR,
};

class Socket
{
   friend class InputSelector;

public:
   Socket(bzook::SocketType socketType);

   Socket(const Socket&) = delete; // Can't share this resource.
   Socket(Socket &&other);

   void connect(std::string remote);
   void bind(std::string host);

   typedef std::chrono::duration<int, std::milli> milliseconds;
   void setLingerTimeout(milliseconds linger_timeout);
   void setIdentity(const std::string &identity);
   void setSendTimeout(milliseconds send_timeout);
   void setSendHWM(int messages);

   void setDefaultWait(bool should_wait);

   void subscribe(std::string subscription_id);

   void send(const std::string &str_data, bool send_more);
   void send(const char *data, size_t length, bool send_more);

   bool send_nowait(const std::string &str_data, bool send_more);
   bool send_nowait(const char *data, size_t length, bool send_more);

   int recv(char *buffer, size_t length);
   // Check if there are more frames.
   bool checkMore();
   // Flush any remaining frames. Usually after an error.
   void flushMessage();

   void close();

   bzook::SocketType socketType() const;

   virtual ~Socket();
private:
   bzook::SocketType _socket_type;
   void *_socket_handle;
   bool _default_wait;
};


}

#endif // ZMQ_BZOOK_SOCKETS_H
