#include <vector>
#include <string>
#include <memory>
#include <iostream>

using namespace std;

//abstrakcyjany komunikat
class Message {
public:
    Message(const std::string& msg) : msg_(msg) {}
    virtual ~Message() {}

    const string& get() { return msg_; }
private:
    string msg_;
};

using PMessage = shared_ptr<Message>;

class MessageSMTP : public Message {
public:
    MessageSMTP(const std::string& msg) : Message(msg) {}
};

class MessageTCP : public Message {
public:
    MessageTCP(const std::string& msg) : Message(msg) {}
};

//abstrakcyjana klasa nadajnika komunikatow
class Sender {
public:
    virtual void connect() = 0;
    virtual void send(PMessage m) = 0;
    virtual ~Sender() {}
};

using PSender = shared_ptr<Sender>;

class SenderSMTP : public Sender {
public:
    virtual void connect() { cout << "connect smtp" << endl; }
    virtual void send(PMessage m) { cout << "smtp send " << m->get() << endl; }
};

class SenderTCP : public Sender {
public:
    virtual void connect() { cout << "connect tcp" << endl; }
    virtual void send(PMessage m) { cout << "tcp send " << m->get() << endl; }
};

//abstrakcyjana klasa do potwierdzen
class Confirm {
public:
    virtual void connect() = 0;
    virtual int getNumberSent() = 0;
    virtual ~Confirm() {}
};

using PConfirm = shared_ptr<Confirm>;

class ConfirmSMTP : public Confirm {
public:
    virtual void connect() { cout << "connect smpt" << endl; }
    virtual int getNumberSent() { return 0; }
};

class ConfirmTCP : public Confirm {
public:
    virtual void connect() { cout << "connect tcp" << endl; }
    virtual int getNumberSent() { return 0; }
};


class AbstractFactory {
public:
    virtual PMessage createMessage(const std::string& msg) = 0;
    virtual PSender createSender() = 0;
    virtual PConfirm createConfirm() = 0;
};

using PFactory = shared_ptr<AbstractFactory>;

class SMTPFactory : public AbstractFactory {
public:
    virtual PMessage createMessage(const std::string& msg) { return PMessage(new MessageSMTP(msg) ); }
    virtual PSender createSender() { return PSender(new SenderSMTP); }
    virtual PConfirm createConfirm() { return PConfirm(new ConfirmSMTP); }
};

class TCPFactory : public AbstractFactory {
public:
    virtual PMessage createMessage(const std::string& msg) { return PMessage(new MessageTCP(msg) ); }
    virtual PSender createSender() { return PSender(new SenderTCP); }
    virtual PConfirm createConfirm() { return PConfirm(new ConfirmTCP); }
};



//wysyla kolekcje wiadomosci, zwraca informacje, czy wszystkie udalo sie wyslac
enum PROTOCOL { SMTP, TCP };

// bool send_messages(PROTOCOL protocol, const vector<string> msgs) {
//     PFactory factory;
//     switch(protocol) {
//     case SMTP:
//         factory = PFactory(new SMTPFactory);
//         break;
//     case TCP:
//         factory = PFactory(new TCPFactory);
//         break;
//     }

//     PSender sender = factory->createSender();
//     sender->connect();

//     for(std::string s : msgs) {
//         PMessage m = factory->createMessage(s);
//         sender->send(m);
//     }

//  PConfirm confirm = factory->createConfirm();
//  confirm->connect();

//  return confirm->getNumberSent() == msgs.size();
// }


bool send_messages(PROTOCOL protocol, const vector<string> msgs) {
    PSender sender;
    switch(protocol) {
    case SMTP:
        sender = PSender(new SenderSMTP);
        break;
    case TCP:
        sender = PSender(new SenderTCP);
        break;
    }

    for(std::string s : msgs) {
        PMessage m;
        switch(protocol) {
        case SMTP:
            m = PMessage(new MessageSMTP(s));
            break;
        case TCP:
            m = PMessage(new MessageTCP(s));
            break;
        }
        sender->send(m);
    }

    PConfirm confirm;
    switch(protocol) {
    case SMTP:
        confirm = PConfirm(new ConfirmSMTP);
        break;
    case TCP:
        confirm = PConfirm(new ConfirmTCP);
        break;
    }

    confirm->connect();

    if( confirm->getNumberSent() == msgs.size() )
        return true;
    else
        return false;
}

int main() {
    vector<string> v = { "ZPR1", "ZPR2", "ZPR3", "ZPR4" };

    send_messages( SMTP, v );
    send_messages( TCP, v );

    return 0;
}
