#pragma once
#include "acl_cpp/acl_cpp_define.hpp"
#include "acl_cpp/stdlib/noncopyable.hpp"

struct ACL_AIO;
struct ACL_EVENT;

namespace acl
{

// 事件引擎类型
typedef enum
{
	ENGINE_SELECT,  // select 模式(支持所有平台)
	ENGINE_POLL,    // poll 模式(仅 UNIX 平台)
	ENGINE_KERNEL,  // kernel 模式(win32: iocp, Linux: epoll, FreeBsd: kqueue, Solaris: devpoll
	ENGINE_WINMSG   // win32 GUI 消息模式
} aio_handle_type;

/**
 * 非阻塞IO的事件引擎类，该类封装了系统的 select/poll/epoll/kqueue/devpoll/iocp,
 */

class aio_timer_callback;
class aio_delay_free;
class aio_timer_delay_free;

class ACL_CPP_API aio_handle : private noncopyable
{
public:
	/**
	 * 构造函数，会自动创建IO事件引擎，并且在析构函数中会自动释放
	 * @param engine_type {aio_handle_type} 所采用的引擎类型
	 *  ENGINE_SELECT: select 方式，支持 win32/unix 平台
	 *  ENGINE_POLL: poll 方式，支持 unix 平台
	 *  ENGINE_KERNEL: 自动根据各个系统平台所支持的高效内核引擎进行设置
	 *  ENGINE_WINMSG: win32 界面消息方式，支持 win32 平台
	 * @param nMsg {unsigned int} 若 engine_type 为 ENGINE_WINMSG，当该值
	 *  大于 0 时，该异步句柄便与该消息绑定，否则与缺省消息绑定；
	 *  当 engine_type 为非 ENGINE_WINMSG 时，该值对其它异步句柄不起作用
	 *  
	 */
	aio_handle(aio_handle_type engine_type = ENGINE_SELECT,
		unsigned int nMsg = 0);

	/**
	 * 构造函数，调用者将 ACL_AIO 句柄传进，而在类的析构函数中并不会
	 * 自动释放该 ACL_AIO 句柄
	 * @param handle {ACL_AIO*} ACL_AIO 句柄
	 */
	aio_handle(ACL_AIO* handle);

	virtual ~aio_handle();

	/**
	 * 针对异步读流，设置是否是连续读，该配置项将会被所有的基于
	 * 该异步引擎句柄的异步读流所继承，一般 aio_handle 类对象在缺省
	 * 情况下是连续读的
	 * @param onoff {bool} 设置是否是连续读
	 */
	void keep_read(bool onoff);

	/**
	 * 获得异步引擎句柄是否设置了持续读数据的功能
	 * @return {bool}
	 */
	bool keep_read() const;

	/**
	 * 设置定时器
	 * @param callback {aio_timer_callback*} 定时器回调函数类对象
	 * @param delay {int64} 定时器时间间隔(微秒)
	 * @param id {unsigned int} 定时器某个任务的 ID 号
	 * @return {int64} 定时器生效时间(从1970.1.1以来的微秒数)
	 */
#if defined(_WIN32) || defined(_WIN64)
	__int64 set_timer(aio_timer_callback* callback,
		__int64 delay, unsigned int id = 0);
#else
	long long int set_timer(aio_timer_callback* callback,
		long long int delay, unsigned int id = 0);
#endif

	/**
	 * 删除定时器的所有定时任务事件
	 * @param callback {aio_timer_callback*} 定时器回调函数类对象
	 * @return {time_t} 定时器生效时间(从1970.1.1以来的微秒数)
	 */
#if defined(_WIN32) || defined(_WIN64)
	__int64 del_timer(aio_timer_callback* callback);
#else
	long long int del_timer(aio_timer_callback* callback);
#endif

	/**
	 * 删除定时器中某个指定 ID 号的定时任务
	 * @param callback {aio_timer_callback*} 定时器回调函数类对象
	 * @param id {unsigned int} 定时器某个任务的 ID 号
	 * @return {time_t} 定时器生效时间(从1970.1.1以来的微秒数)
	 */
#if defined(_WIN32) || defined(_WIN64)
	__int64 del_timer(aio_timer_callback* callback, unsigned int id);
#else
	long long del_timer(aio_timer_callback* callback, unsigned int id);
#endif

	/**
	 * 当定时器处于锁定状态时，用户因为无法释放该定时器而造成内存泄露，
	 * 通过此函数，可以将处于锁定状态的定时器当处于未锁定状态时被事件
	 * 引擎延期释放(调用 aio_delay_free::destroy())，从而可以避免
	 * 内存泄露问题
	 * @param callback {aio_delay_free*}
	 */
	void delay_free(aio_delay_free* callback);

	/**
	 * 获得 ACL_AIO 句柄
	 * @return {ACL_AIO*}
	 */
	ACL_AIO* get_handle(void) const;

	/**
	 * 获得异步引擎的类型
	 * @return {aio_handle_type}
	 */
	aio_handle_type get_engine_type(void) const;

	/**
	 * 获得当前处于监控的异步流的数量
	 * @return {int}
	 */
	int length() const;

	/**
	 * 检查所有异步流的状态，并触发准备的异步流的处理过程
	 * @return {bool} 是否应中止异步引擎
	 */
	bool check();

	/**
	 * 通知异步流引擎中止
	 */
	void stop();

	/**
	 * 重置异步引擎的内部状态
	 */
	void reset();

public:
	/**
	 * 设置异步引擎循环的等待时间中的秒级部分
	 * @param n {int} 设置用 select/poll/epoll/kqueue/devpoll
	 *  时的秒级等待时间
	 */
	void set_delay_sec(int n);

	/**
	 * 设置异步引擎循环的等待时间中的微秒级部分
	 * @param n {int} 设置用 select/poll/epoll/kqueue/devpoll
	 *  时的微秒级等待时间
	 */
	void set_delay_usec(int n);

	/**
	 * 设置事件循环过程中定时检查所有描述字状态的时间间隔，
	 * 内部缺省值 100 ms
	 */
	void set_check_inter(int n);

	/**
	 * 设置异步流的读缓存区大小
	 * @param n {int} 读缓冲区大小
	 */
	void set_rbuf_size(int n);

protected:
	friend class aio_stream;

	/**
	 * 异步流个数加 1
	 */
	void increase();

	/**
	 * 当异步流个数加 1 时的回调虚函数
	 */
	virtual void on_increase() {}

	/**
	 * 异步流个数减 1
	 */
	void decrease();

	/**
	 * 当异步流个数减 1 时的回调虚函数
	 */
	virtual void on_decrease() {}

private:
	ACL_AIO* aio_;
	bool inner_alloc_;
	bool stop_;
	int  nstream_;
	aio_handle_type engine_type_;
	aio_timer_delay_free* delay_free_timer_;

	void destroy_timer(aio_timer_callback* callback);
	static void on_timer_callback(int event_type, ACL_EVENT*,
		aio_timer_callback *callback);
};

} // namespace acl
