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

using namespace std;

/** klasa bazowa, wzorzec kompozytu */
class Element {
public:
	Element(const string& n) : name_(n) {}
	virtual ~Element() = default;

	const string& getName() const { return name_; }
private:
	string name_;
};
using PElement = shared_ptr<Element>;

/** kompozyt, klasa prosta; produkt abstrakcyjny w fabryce abstrakcyjnej */
class File : public Element {
public:
	File(const string& n) : Element(n) {}
};

using PFile = shared_ptr<File>;

/** kompozyt, klasa zlozona; produkt abstrakcyjny w fabryce abstrakcyjnej */
class Dir : public Element {
public:
	Dir(const string& n) : Element(n) {}
    vector<PElement> children_;
};

using PDir = shared_ptr<Dir>;

/** produkt konkretny w fabryce abstrakcyjnej */
class FileFat16 : public File {
public:
    FileFat16(const string& name) : File(name) { cout << "C-tor FileFat16" << endl; }
};
/** produkt konkretny w fabryce abstrakcyjnej */
class DirFat16 : public Dir {
public:
    DirFat16(const string& name) : Dir(name) { cout << "C-tor DirFat16" << endl; }
};
/** produkt konkretny w fabryce abstrakcyjnej */
class FileNTFS : public File {
public:
    FileNTFS(const string& name) : File(name) { cout << "C-tor FileNTFS" << endl; }
};
/** produkt konkretny w fabryce abstrakcyjnej */
class DirNTFS : public Dir {
public:
    DirNTFS(const string& name) : Dir(name) { cout << "C-tor DirNTFS" << endl; }
};
/** produkt konkretny w fabryce abstrakcyjnej */
class FileExt4 : public File {
public:
    FileExt4(const string& name) : File(name) { cout << "C-tor FileExt4" << endl; }
};
/** produkt konkretny w fabryce abstrakcyjnej */
class DirExt4 : public Dir {
public:
    DirExt4(const string& name) : Dir(name) { cout << "C-tor DirExt4" << endl; }
};


class AbsFactory {
public:
	virtual ~AbsFactory() = default;
    virtual PFile createFile(const string& name) = 0;
    virtual PDir createDir(const string& name) = 0;
};
/** fabryka konkretna */
class Fat16Factory : public AbsFactory {
public:
    virtual PFile createFile(const string& name) {
        return PFile(new FileFat16(name));
    }
    virtual PDir createDir(const string& name) {
        return PDir(new DirFat16(name));
    }
};
/** fabryka konkretna */
class NTFSFactory : public AbsFactory {
public:
    virtual PFile createFile(const string& name) {
        return make_shared<FileNTFS>(name);
    }
    virtual PDir createDir(const string& name) {
        return make_shared<DirNTFS>(name);
    }
};
/** fabryka konkretna */
class Ext4Factory : public AbsFactory {
public:
    virtual PFile createFile(const string& name) {
        return make_shared<FileExt4>(name);
    }
    virtual PDir createDir(const string& name) {
        return make_shared<DirExt4>(name);
    }
};

int main() {
    AbsFactory* f = new Fat16Factory();
    f->createFile("file");
    f->createDir("dir");

    delete f;
    return 0;
}
