#pragma once

#define CONNECTING_STATE 0
#define READING_STATE 1
#define WRITING_STATE 2
#define INSTANCES 4
#define PIPE_TIMEOUT 5000
#define BUFSIZE 4096

// 命名管道在完成端口上投递的I/O操作的类型
typedef enum _OPERATION_TYPE
{
    OP_ACCEPT, // Accept操作;
    OP_SEND,   // 发送操作
    OP_RECV,   // 接收操作
    OP_MAX     // 上限;
} OPERATION_TYPE;

// 单个IO请求;
typedef struct _PER_IO_CONTEXT
{
    OVERLAPPED m_Overlapped;
    HANDLE m_PipeAccept;
    OPERATION_TYPE m_OpType;
    TCHAR chRequest[BUFSIZE];
    DWORD cbRead;
    TCHAR chReply[BUFSIZE];
    DWORD cbToWrite;
    // 管道状态;
    DWORD dwState;
    // IO是否在等待;
    BOOL fPendingIO;
    // 客户端进程窗口名称;
    TCHAR chClientName[255];
    // 客户端进程PID;
    DWORD dwProcessId;

    // 初始化
    _PER_IO_CONTEXT()
    {
        ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
        ZeroMemory(chRequest, BUFSIZE);
        ZeroMemory(chReply, BUFSIZE);
        ZeroMemory(chClientName, 255);
        m_PipeAccept = INVALID_HANDLE_VALUE;
        m_OpType = OP_ACCEPT;
        fPendingIO = FALSE;
        dwProcessId = 0;
        dwState = 0;
    }

    // 释放掉句柄
    ~_PER_IO_CONTEXT()
    {
        if (m_PipeAccept != INVALID_HANDLE_VALUE)
        {
            CloseHandle(m_PipeAccept);
            m_PipeAccept = INVALID_HANDLE_VALUE;
        }
    }

    // 重置缓冲区内容
    void ResetBuffer()
    {
        ZeroMemory(chRequest, BUFSIZE);
        ZeroMemory(chReply, BUFSIZE);
        ZeroMemory(chClientName, 255);
    }

} PER_IO_CONTEXT, *PPER_IO_CONTEXT;

//====================================================================================
//
//				CIOCPPipe类定义
//
//====================================================================================

// 工作者线程的线程参数
class CIOCPPipe;
typedef struct _tagThreadParams_WORKER
{
    CIOCPPipe *pIOCPModel; // 类指针，用于调用类中的函数
    int nThreadNo;          // 线程编号

} THREADPARAMS_WORKER, *PTHREADPARAM_WORKER;

// CIOCPPipe类
class CIOCPPipe
{
public:
    CIOCPPipe(void);
    ~CIOCPPipe(void);

public:
    // 启动服务器
    bool Start();

    //	停止服务器
    void Stop();

    // 设置主界面的指针，用于调用显示信息到界面中
    void SetMainDlg(CDialog *p) { m_pMain = p; }

protected:
    // 初始化IOCP
    bool _InitializeIOCP();

    // 最后释放资源
    void _DeInitialize();

    // 投递Accept请求
    bool _PostAccept();

    // 投递接收数据请求
    bool _PostRecv(PER_IO_CONTEXT *pIoContext);

    // 在有客户端连入的时候，进行处理
    bool _DoAccpet(PER_IO_CONTEXT *pIoContext);

    // 在有接收的数据到达的时候，进行处理
    bool _DoRecv(PER_IO_CONTEXT *pIoContext);

    // 将客户端的相关信息存储到数组中
    void _AddToContextList(PER_IO_CONTEXT *pIoContext);

    // 将客户端的信息从数组中移除
    void _RemoveContext(PER_IO_CONTEXT *pIoContext);

    // 清空客户端信息
    void _ClearContextList();

    // 将句柄绑定到完成端口中
    bool _AssociateWithIOCP(PER_IO_CONTEXT *pIoContext);

    // 处理完成端口上的错误
    bool HandleError(PER_IO_CONTEXT *pIoContext, const DWORD &dwErr);

    // 线程函数，为IOCP请求服务的工作者线程
    static DWORD WINAPI _WorkerThread(LPVOID lpParam);

    // 获得本机的处理器数量
    int _GetNoOfProcessors();

    // 判断客户端Socket是否已经断开
    bool _IsSocketAlive(SOCKET s);

    // 在主界面中显示信息
    void _ShowMessage(const CString szFormat, ...) const;

private:
    HANDLE m_hShutdownEvent; // 用来通知线程系统退出的事件，为了能够更好的退出线程

    HANDLE m_hIOCompletionPort; // 完成端口的句柄

    HANDLE *m_phWorkerThreads; // 工作者线程的句柄指针

    int m_nThreads; // 生成的线程数量

    CString m_strIP; // 服务器端的IP地址
    int m_nPort;     // 服务器端的监听端口

    CDialog *m_pMain; // 主界面的界面指针，用于在主界面中显示消息

    CRITICAL_SECTION m_csContextList; // 用于Worker线程同步的互斥量

    CArray<PER_IO_CONTEXT *> m_arrayClientContext; // 客户端Socket的Context信息

};
