#pragma once

#include "acl_cpp/acl_cpp_define.hpp"
#include "acl_cpp/stream/stream_hook.hpp"

struct ACL_VSTREAM;

namespace acl {

class polarssl_conf;

/**
 * stream/aio_stream 流对象底层 IO 处理过程的处理类，该类对象中的读写的过程将会替代
 * stream/aio_stream 流对象中 默认的底层 IO 过程；该类对象必须是动态创建的(即为堆对象)，
 * stream/aio_stream 流对象通过调用本类对象的 destroy()　方法释放本类对象
 */
class ACL_CPP_API polarssl_io : public stream_hook
{
public:
	/**
	 * 构造函数
	 * @param conf {polarssl_conf&} 对每一个 SSL 连接进行配置的类对象
	 * @param server_side {bool} 是否为服务端模式，因为客户端模式与服务端
	 *  模式的握手方法不同，所以通过此参数来进行区分
	 * @param aio_mode {bool} 是否为非阻塞模式
	 */
	polarssl_io(polarssl_conf& conf, bool server_side,
		bool non_block = false);

	virtual void destroy();

	/**
	 * 调用此方法进行 SSL 握手，在非阻塞 IO 模式下该函数需要与 handshake_ok()
	 * 函数组合使用来判断 SSL 握手是否成功
	 * @return {bool}
	 *  1、返回 false 表示握手失败，需要关闭连接；
	 *  2、当返回 true 时：
	 *  2.1、如果为阻塞 IO 模式则表示 SSL 握手成功
	 *  2.2、在非阻塞 IO 模式下仅代表本次握手过程中 IO 是成功的，还需要调用
	 *       handshake_ok() 函数判断 SSL 握手是否成功
	 */
	bool handshake(void);

	/**
	 * 判断 SSL 握手是否成功
	 * @return {bool}
	 */
	bool handshake_ok(void)
	{
		return handshake_ok_;
	}

	/**
	 * 设置套接字为阻塞模式/非阻塞模式
	 * @param yes {bool} 当为 false 时则设为阻塞模式，否则设为非阻塞模式
	 * @return {polarssl_io&}
	 */
	polarssl_io& set_non_blocking(bool yes);

	/**
	 * 判断当前设置的 SSL IO 是否阻塞模式还是非阻塞模式
	 * @return {bool} 返回 true 则表示为非阻塞模式，否则为阻塞模式
	 */
	bool is_non_blocking(void) const
	{
		return non_block_;
	}


	/**
	 * 检查对方证书是否有效（一般不必调用此函数）
	 * @return {bool}
	 */
	bool check_peer(void);

private:
	~polarssl_io();

	virtual bool open(ACL_VSTREAM* s);
	virtual bool on_close(bool alive);
	virtual int read(void* buf, size_t len);
	virtual int send(const void* buf, size_t len);

private:
	polarssl_conf& conf_;
	bool  server_side_;
	bool  non_block_;
	bool  handshake_ok_;
	void* ssl_;
	void* ssn_;
	void* rnd_;
	ACL_VSTREAM* stream_;

	static int sock_read(void *ctx, unsigned char *buf, size_t len);
	static int sock_send(void *ctx, const unsigned char *buf, size_t len);
};

} // namespace acl
