#include <vector>
#include <memory>

/** Reprezentuje nutę, implementacja nieistotna. */
struct Note {};

//Rozwiazanie: wzorzec mostu

//tutaj dla wygody używam sprytnych wskaźników (shared_ptr), ale nie jest to częścią zadania


class Instrument { //klasa bazowa implementacji - rozne rodzaje instrumentow
public:
    virtual void play(Note n) = 0;
};

using PInstrument = std::shared_ptr<Instrument>;


class Piano : public Instrument {
    //implementacja nie ma znaczenia w tym zadaniu
    void play(Note n) override { }
};

class Violin : public Instrument {
    //implementacja nie ma znaczenia w tym zadaniu
    void play(Note n) override { }
};


class Trumpet : public Instrument {
    //implementacja nie ma znaczenia w tym zadaniu
    void play(Note n) override { }
};

//klasa bazowa abstrakcji - rozne melodie
class Song {
public:
    Song(PInstrument ii) : instrument_(ii) {}

    virtual void play() = 0;
protected:
    void play(Note n) {
        return instrument_->play(n);
    }
private:
    PInstrument instrument_;
};

//melodia 1
class YankeeDoodle : public Song {
public:
    YankeeDoodle(PInstrument i) : Song(i) {}
    //implementacja nie ma znaczenia w tym zadaniu
    void play() override { }
};

//melodia 2
class HungarianDance : public Song {
public:
    HungarianDance(PInstrument i) : Song(i) {}
    //implementacja nie ma znaczenia w tym zadaniu
    void play() override { }
};


int main() {
    //przyklad obiektu - HungarianDance na pianino
    std::shared_ptr<Song> hungarian_dance_piano = std::make_shared<HungarianDance>(std::make_shared<Piano>() );
    hungarian_dance_piano->play();
    return 0;
}

//STARY, NADMIAROWY KOD

class Song2 {
    virtual void play() = 0;
};


class YankeeDoodlePiano : public Song2 {
public:
    YankeeDoodlePiano();
    //implementacja nie ma znaczenia w tym zadaniu
    void play() override { }
};

class HungarianDancePiano : public Song2 {
public:
    HungarianDancePiano();
    //implementacja nie ma znaczenia w tym zadaniu
    void play() override { }
};

class YankeeDoodleViolin : public Song2 {
public:
    YankeeDoodleViolin();
    //implementacja nie ma znaczenia w tym zadaniu
    void play() override { }
};

class HungarianDanceViolin : public Song2 {
public:
    HungarianDanceViolin();
    //implementacja nie ma znaczenia w tym zadaniu
    void play() override { }
};

class YankeeDoodleTrumpet : public Song2 {
public:
    YankeeDoodleTrumpet();
    //implementacja nie ma znaczenia w tym zadaniu
    void play() override { }
};

class HungarianDanceTrumpet : public Song2 {
public:
    HungarianDanceTrumpet();
    //implementacja nie ma znaczenia w tym zadaniu
    void play() override { }
};
