#ifndef _CNET_H
#define _CNET_H


#include "BlockSock.h"
#include "stdAfx.h"
#include <map>
#include <list>
#include <afxmt.h>



#define MAX_CONNECTION 20000;


struct NETOBJ_HEADER;
class NETOBJ;
struct RECVTHREADPARAM;
struct SOCKET_INFO;
class CNet;


struct NETOBJ_HEADER{
	NETOBJ_HEADER(){}
	NETOBJ_HEADER(int type,  unsigned int length) : m_type(type), m_length(length){}
	int m_type;
	unsigned int m_length;
};

class NETOBJ{
public:
	NETOBJ(){m_pBuf = NULL;}
	NETOBJ(int id, int type){
		m_pBuf = new char;
		m_header.m_type = type;
		m_header.m_length = 1;
		m_ID = id;
	}
	NETOBJ(int id, int type, CString *s){
		m_pBuf = (char *)s-> GetString();
		m_header.m_type = type;
		m_header.m_length = s-> GetLength() + 1;
		m_ID = id;
	}
	NETOBJ(int id, int type, int temp){
		m_pBuf = new char[4];
		m_pBuf[0] = ((char*)&temp)[0];
		m_pBuf[1] = ((char*)&temp)[1];
		m_pBuf[2] = ((char*)&temp)[2];
		m_pBuf[3] = ((char*)&temp)[3];
		m_header.m_type = type;
		m_header.m_length = 4;
		m_ID = id;
	}
	int m_ID;
	NETOBJ_HEADER m_header;
	char* m_pBuf;
};

struct RECVTHREADPARAM{
	WSAEVENT hEvent;
	SOCKET hSocket;
	int ID;
	CNet* pNet;
};

struct SOCKET_INFO{
	SOCKET m_hSocket;
	WSAEVENT m_hEvent;
	CWinThread* m_RecvThread;
};

class CNetHandler{
public:
	virtual int OnAccept(int ID) = 0;
	virtual void OnRecv(NETOBJ* pnetobj) = 0;
	virtual void OnClose(int ID) = 0;
};

typedef std::map<int, SOCKET_INFO> SOCKETMAP;
class CNet{

protected:
	bool m_Start;
public:
	int InitWinSock();
	int GetAnFreeID();
	int m_IDcounter;
	
public:
	CCriticalSection m_csSocketMap;
	CCriticalSection m_csRecvCallback;

	SOCKETMAP m_SocketMap;
	CWinThread *m_tListen;				// listening thread;
	CWinThread *m_tRefresh;
	CBlockingSocket g_listen;		// listening socket

	CNetHandler* m_pHandler;

public:
	CNet();
	~CNet();
	int Run(int port);
	void Stop();
	int Connect(CString* pAddr, int port);
	int DisConnect(int ID);
	int ErrorDisConnect(int id);
	int DisConnectInRecv(int id);
	int Send(NETOBJ*);
	int Send(NETOBJ & netobj);
	void SetHandler(CNetHandler* phandler);
	int GetAddr(int id, CString* pAddr, int * pPort);
	void Refresh();
	

};

#endif