#include <iostream>
#include <string>
#include <map>
#include <memory>

using namespace std;


/**
 * Server Interface
 */
class IServer {
protected:
string protocol;
public:
virtual void reponse() = 0;
virtual void accept(string message) = 0;
};

/**
 * Server Factory
 */
class Factory
{
public:
//virtual IServer* create() = 0;
virtual std::shared_ptr<IServer> create(string s) = 0;
};

template <class aServer>
class ServerFactory : public Factory
{
public:
//IServer* create() { return new aServer(); }
std::shared_ptr<IServer> create(string s) { return std::make_shared<aServer>(s); }
};



/**
 * A server
 */
class Server1 : public IServer {
public:
Server1(string protocol_) {
// does not work as normal constructor variable
protocol = protocol_;
cout << "Server1 constructor with protocol: " << protocol << endl;

}
void reponse(){
cout << "Server1 Responding with protocol: " << protocol << endl;
}
void accept(string message){
cout << "Server1 accepted message with protocol: " << protocol << endl;
cout << "Message: " << message << endl;
}
};


/**
 * The client
 */
class Client {
private:
string id;
std::shared_ptr<IServer> server;
public:
Client(string clientId) : id(clientId){
cout << "Client constructor with id: " << clientId << endl;
}
void setServer(std::shared_ptr<IServer> server_){
server = server_;
}
void request(string message) {
server->accept(message);
server->reponse();
}
};

int main (void) {
// register server 1 in the::make_shared(1); factory
std::map<string, std::shared_ptr<Factory> > factoryMap;
factoryMap["Server1"] = std::make_shared< ServerFactory<Server1> >();

//Server1 s("DummyProtocol");
auto s = factoryMap["Server1"]->create("DummyProtocol");

Client c("Dummy Client");
c.setServer(s);
c.request("Dummy Message!");

return 0;
}