#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;

extern void dprintf(TCHAR* pszStr, ...);
// 单个IO请求;
typedef struct _PER_IO_CONTEXT
{
    OVERLAPPED m_Overlapped;
    HANDLE m_PipeAccept;
    OPERATION_TYPE m_OpType;
	// 接收客户端的消息;
    TCHAR szBuffer[BUFSIZE];
    DWORD dwBufferLine;
	// 发送给客户的消息;
    //TCHAR chReply[BUFSIZE];
    //DWORD cbToWrite;
    // 管道状态;
    //DWORD dwState;
    // IO是否在等待;
    //BOOL fPendingIO;
	// 创建写IO;
	_PER_IO_CONTEXT *pWriteIoContext;
    
    // 初始化
    _PER_IO_CONTEXT()
    {
        ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
        ZeroMemory(szBuffer, BUFSIZE);
        //ZeroMemory(chReply, BUFSIZE);
		m_PipeAccept = INVALID_HANDLE_VALUE;
        m_OpType = OP_ACCEPT;
		pWriteIoContext = NULL;
        //fPendingIO = FALSE;
        //dwState = 0;
    }

    // 释放掉句柄
    ~_PER_IO_CONTEXT()
    {		
        if (m_PipeAccept != INVALID_HANDLE_VALUE)
        {
            //CloseHandle(m_PipeAccept);// 此处不能CloseHandle，因为m_PipeAccept在PER_PIPE_CONTEXT中已释放;
            m_PipeAccept = INVALID_HANDLE_VALUE;
        }

		if ( pWriteIoContext )
			delete pWriteIoContext;
		pWriteIoContext = NULL;
    }

    // 重置缓冲区内容
    void ResetBuffer()
    {
		dprintf(_T("ResetBuffer:%p"), &m_Overlapped);
        ZeroMemory(szBuffer, BUFSIZE);
        //ZeroMemory(chReply, BUFSIZE);
    }

} PER_IO_CONTEXT, *PPER_IO_CONTEXT;

typedef struct _PER_PIPE_CONTEXT
{
	HANDLE m_hPipe;
	// 客户端进程PID;
	DWORD dwProcessId;
	// 客户端进程窗口名称;
	TCHAR szClientName[255];
	// 该Pipe下的所有IO事件;
	CArray<_PER_IO_CONTEXT*> m_arrayIoContext;

	_PER_PIPE_CONTEXT()
	{
		m_hPipe = INVALID_HANDLE_VALUE;
		dwProcessId = 0;
		memset(szClientName, 0, sizeof(TCHAR)*255);
	}

	~_PER_PIPE_CONTEXT()
	{
		if ( m_hPipe != INVALID_HANDLE_VALUE )
		{
			CloseHandle(m_hPipe);
			m_hPipe = INVALID_HANDLE_VALUE;

			// 释放掉所有的IO上下文数据
			for( int i=0; i<m_arrayIoContext.GetCount(); i++ )
			{
				delete m_arrayIoContext.GetAt(i);
			}
			m_arrayIoContext.RemoveAll();
		}
	}

	// 设置客户端信息;
	void SetClientInfo(DWORD dwClientId, LPCTSTR lpszClientName)
	{
		dwProcessId = dwClientId;
		_stprintf_s(szClientName, _T("%s"), lpszClientName == NULL ? _T("Null") : lpszClientName);
	}

	// 获取一个新的IoContext
	_PER_IO_CONTEXT* GetNewIoContext()
	{
		_PER_IO_CONTEXT* p = new _PER_IO_CONTEXT;

		m_arrayIoContext.Add( p );

		return p;
	}

	// 从数组中移除一个指定的IoContext
	void RemoveContext( _PER_IO_CONTEXT* pContext )
	{
		ASSERT( pContext!=NULL );
		for( int i=0; i<m_arrayIoContext.GetCount(); i++ )
		{
			if( pContext == m_arrayIoContext.GetAt(i) )
			{
				if ( pContext->pWriteIoContext )
					delete pContext->pWriteIoContext;
				delete pContext;
				pContext = NULL;
				m_arrayIoContext.RemoveAt(i);				
				break;
			}
		}
	}
}PER_PIPE_CONTEXT, *PPER_PIPE_CONTEXT;

// 回调客户端接入时;
typedef BOOL(CALLBACK *OnConnectCallback)(PER_IO_CONTEXT* pIoContext);
// 回调客户端断开时;
typedef BOOL(CALLBACK* OnDisconnectCallback)(PER_IO_CONTEXT* pIoContext);
// 回调客户端消息到来时;
typedef BOOL(CALLBACK *OnReciveCallback)(PER_PIPE_CONTEXT *pPipeContext, PPER_IO_CONTEXT *pIoContext);

// 工作者线程的线程参数
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; }
	// 向客户端发送消息;
	bool SendMessage();
	// SetCallback;
	static void SetCallBack(LPVOID lpOnConnect, LPVOID lpOnDisconnect, LPVOID lpOnRecive)
	{
		if ( lpOnConnectCallback == NULL )
			lpOnConnectCallback = (OnConnectCallback)lpOnConnect;

		if ( lpOnDisconnectCallback == NULL )
			lpOnDisconnectCallback = (OnDisconnectCallback)lpOnDisconnect;

		if ( lpOnReciveCallback == NULL )
			lpOnReciveCallback = (OnReciveCallback)lpOnRecive;
	}
protected:
    // 初始化IOCP
    bool InitIOCP();
    // 最后释放资源
    void DeInitialize();
    // 投递Accept请求
    bool PostAccept();
    // 投递接收数据请求
    bool PostRecv(PER_IO_CONTEXT *pIoContext);
    // 在有客户端连入的时候，进行处理
    bool DoAccpet(PER_PIPE_CONTEXT *pPipeContext, PER_IO_CONTEXT *pIoContext);
    // 在有接收的数据到达的时候，进行处理
    bool DoRecv(PER_PIPE_CONTEXT *pPipeContext, PER_IO_CONTEXT *pIoContext);
    // 将客户端的相关信息存储到数组中
    void AddToContextList(PER_PIPE_CONTEXT *pPipeContext);
    // 将客户端的信息从数组中移除
    void RemoveContext(PER_PIPE_CONTEXT *pPipeContext);
    // 清空客户端信息
    void ClearContextList();
    // 将句柄绑定到完成端口中
    bool AssociateWithIOCP(PER_IO_CONTEXT *pIoContext);
    // 处理完成端口上的错误
    bool HandleError(PER_PIPE_CONTEXT *pPipeContext, const DWORD &dwErr);
    // 线程函数，为IOCP请求服务的工作者线程
    static DWORD WINAPI _WorkerThread(LPVOID lpParam);
    // 获得本机的处理器数量
    int GetNoOfProcessors();
    // 判断客户端Socket是否已经断开
    bool IsSocketAlive(SOCKET s);
    // 在主界面中显示信息
    void ShowMessage(const CString szFormat, ...) const;
	// 处理返回值;
	void RecvProcess(PER_PIPE_CONTEXT* pPipeContext, PER_IO_CONTEXT* pIoContext);

private:
	static OnConnectCallback lpOnConnectCallback;
	static OnDisconnectCallback lpOnDisconnectCallback;
	static OnReciveCallback lpOnReciveCallback;
    HANDLE m_hShutdownEvent; // 用来通知线程系统退出的事件，为了能够更好的退出线程
    HANDLE m_hIOCompletionPort; // 完成端口的句柄
    HANDLE *m_phWorkerThreads; // 工作者线程的句柄指针
    int m_nThreads; // 生成的线程数量
    CDialog *m_pMain; // 主界面的界面指针，用于在主界面中显示消息
    CRITICAL_SECTION m_csContextList; // 用于Worker线程同步的互斥量
    CArray<PER_PIPE_CONTEXT *> m_arrayClientContext; // 客户端Socket的Context信息
};
