#include <iostream>
#include <cstring>
#include <functional>
#include <memory>

using namespace std;
using namespace std::placeholders;

typedef enum { TCP, SERIAL, CONNECT_COUNT} CONNECT_TYPE;

// Define interface
class IConnector
{
public:
	virtual void open() = 0;
	virtual void recv(void* buffer, size_t size) = 0;
	virtual void send(void* buffer, size_t size) = 0;
	virtual void close() = 0;
};

// Define CSerial
class CSerial	/*: public IConnector*/ // From 3rd?
{
public:
	void open();
	void recv(void* buffer, size_t size);
	void send(void* buffer, size_t size);
	void close();
};

// Define CTcp
class CTcp	   /*: public IConnector*/ // From 3rd?
{
public:
	void open();
	void recv(void* buffer, size_t size);
	void send(void* buffer, size_t size);
	void close();
};

typedef void (OPEN_FUNC)();
typedef void (RECV_FUNC)(void*, size_t);
typedef void (SEND_FUNC)(void*, size_t);
typedef void (CLOSE_FUNC)();

// Define CConnector
class CConnector: public IConnector
{
public:
	CConnector();
	void open();
	void recv(void* buffer, size_t size);
	void send(void* buffer, size_t size);
	void close();
	void setType(CONNECT_TYPE type);

private:
	template <class T>
		void bindConnector(T* connector);
	CONNECT_TYPE mType;
	CTcp mTcp;
	CSerial mSerial;
	std::function<OPEN_FUNC> openFunc;
	std::function<RECV_FUNC> recvFunc;
	std::function<SEND_FUNC> sendFunc;
	std::function<CLOSE_FUNC> closeFunc;
};

// Implement CSerial
void CSerial::open()
{
	cout <<	"CSerial::" <<  __func__ << endl;
}

void CSerial::recv(void* buffer, size_t size)
{
	cout << "CSerial::" << __func__ << endl;
}

void CSerial::send(void* buffer, size_t size)
{
	cout << "CSerial::" << __func__ << endl;
}

void CSerial::close()
{
	cout << "CSerial::" << __func__ << endl;
}

// Implement CTcp
void CTcp::open()
{
	cout << "CTcp::" <<  __func__ << endl;
}

void CTcp::recv(void* buffer, size_t size)
{
	cout << "CTcp::" << __func__ << endl;
}

void CTcp::send(void* buffer, size_t size)
{
	cout << "CTcp::" << __func__ << endl;
}

void CTcp::close()
{
	cout << "CTcp::" << __func__ << endl;
}

// Implement CConnector
CConnector::CConnector(): mTcp(), mSerial(), openFunc(), recvFunc(), sendFunc(), closeFunc()
{
}

void CConnector::open()
{
	if(openFunc != NULL)
		openFunc();
}

void CConnector::recv(void* buffer, size_t size)
{
	if(recvFunc != NULL)
		recvFunc(buffer, size);
}

void CConnector::send(void* buffer, size_t size)
{
	if(sendFunc != NULL)
		sendFunc(buffer, size);
}

void CConnector::close()
{
	if(closeFunc != NULL)
		closeFunc();
}

template <class T>
void CConnector::bindConnector(T* connector)
{
	openFunc = std::bind(&T::open, connector);
	recvFunc = std::bind(&T::recv, connector, _1, _2);
	sendFunc = std::bind(&T::send, connector, _1, _2);
	closeFunc = std::bind(&T::close, connector);
}

void CConnector::setType(CONNECT_TYPE type)
{
	mType = type;
	switch(mType)
	{
		case CONNECT_TYPE::SERIAL:
			bindConnector(&mTcp);
			break;
		case CONNECT_TYPE::TCP:
			bindConnector(&mTcp);
			break;
		default:
			throw "error";
	}
}

void testTCP()
{
	CConnector* conector = new CConnector();
	conector->setType(CONNECT_TYPE::TCP);
	conector->open();
	conector->recv(NULL, 0);
	conector->send(NULL, 0);
	conector->close();
	delete conector;
	cout << endl;
}

void testSerial()
{
	CConnector* conector = new CConnector();
	conector->setType(CONNECT_TYPE::SERIAL);
	conector->open();
	conector->recv(NULL, 0);
	conector->send(NULL, 0);
	conector->close();
	delete conector;
	cout << endl;
}

int main(int argc, char* argv[])
{
	testTCP();
	testSerial();

	return 0;
}