MODE: INLINE
#include <iostream>

/* is able to hold only files in WAV-format */
struct WAVFile {
    WAVFile(const char* name): name_{name} {}
    const char* name() const noexcept { return name_; }
private:
    const char* name_;
};

/* is able to hold any files only in ogg, mp3 and aac formats */
struct MultimediaFile {
    MultimediaFile(const char* name, const char* format): name_{name}, format_{format} {}
    const char* name() const noexcept { return name_; }
    const char* format() const noexcept { return format_; }
private:
    const char* name_;
    const char* format_;
};

struct WAVPlayer {
  WAVPlayer(double preferred_bitrate): preferred_bitrate_{preferred_bitrate} {}
  ~WAVPlayer() { std::cout << "~WAVPlayer\n"; }
  std::string play_wav(WAVFile* file) {
    std::string result = "wav-player is playing ";
    result += file->name();
    result += " with bitrate ";
    result += std::to_string(preferred_bitrate_);
    return result;
  }
  double preferred_bitrate() const noexcept { return preferred_bitrate_; }
  WAVPlayer* clone() const noexcept { return new WAVPlayer(preferred_bitrate_); }
private:
  double preferred_bitrate_;
};

struct MultimediaPlayer {
  MultimediaPlayer(int quality): quality_{quality} {}
  ~MultimediaPlayer() { std::cout << "~MultimediaPlayer\n"; }
  std::string play_file(MultimediaFile* file) {
    std::string result = "player is playing ";
    result += file->name();
    result += " (";
    result += file->format();
    result += ")";
    result += " with quality ";
    result += std::to_string(quality_);
    return result;
  }
  int quality() const noexcept { return quality_; }
  MultimediaPlayer* clone() const noexcept { return new MultimediaPlayer(quality_); }
private:
  int quality_;
};


namespace xs {
    template <>
    struct Typemap<WAVFile*> : TypemapObject<WAVFile*, WAVFile*, ObjectTypePtr, ObjectStorageMG> {
        static std::string package () { return "MyTest::Cookbook::WAVFile"; }
    };

    template <>
    struct Typemap<MultimediaFile*> : TypemapObject<MultimediaFile*, MultimediaFile*, ObjectTypePtr, ObjectStorageMG> {
        static std::string package () { return "MyTest::Cookbook::MultimediaFile"; }
    };

    template <>
    struct Typemap<WAVPlayer*> : TypemapObject<WAVPlayer*, WAVPlayer*, ObjectTypePtr, ObjectStorageMG> {
        static std::string package () { return "MyTest::Cookbook::WAVPlayer"; }
    };

    template <>
    struct Typemap<MultimediaPlayer*> : TypemapObject<MultimediaPlayer*, MultimediaPlayer*, ObjectTypePtr, ObjectStorageMG> {
        static std::string package () { return "MyTest::Cookbook::MultimediaPlayer"; }
    };
}

MODULE = MyTest::Cookbook                PACKAGE = MyTest::Cookbook::WAVFile
PROTOTYPES: DISABLE

void WAVFile::name()

WAVFile* WAVFile::new(const char* name)

MODULE = MyTest::Cookbook                PACKAGE = MyTest::Cookbook::MultimediaFile
PROTOTYPES: DISABLE

void MultimediaFile::name()

void MultimediaFile::format()

MultimediaFile* MultimediaFile::new(const char* name, const char* format)

MODULE = MyTest::Cookbook                PACKAGE = MyTest::Cookbook::WAVPlayer
PROTOTYPES: DISABLE

std::string WAVPlayer::play_wav(WAVFile* file)

double WAVPlayer::preferred_bitrate()

WAVPlayer* WAVPlayer::clone() {
    Object self{ST(0)};
    PROTO = self.stash();
    RETVAL = THIS->clone();
}

WAVPlayer* WAVPlayer::new(double preferred_bitrate)

MODULE = MyTest::Cookbook                PACKAGE = MyTest::Cookbook::MultimediaPlayer
PROTOTYPES: DISABLE

MultimediaPlayer* MultimediaPlayer::new(double preferred_bitrate, int quality) {
    (void)preferred_bitrate;    // silence warning
    PROTO = Stash::from_name(CLASS).call_next(cv, &ST(1), 1);
    if (!PROTO.defined()) XSRETURN_UNDEF;
    RETVAL = new MultimediaPlayer(quality);
}

std::string MultimediaPlayer::play_file(MultimediaFile* file)

int MultimediaPlayer::quality()

MultimediaPlayer* MultimediaPlayer::clone() {
    Object self{ST(0)};
    PROTO = self.call_next(cv);
    RETVAL = THIS->clone();
}

BOOT {
    auto stash = Stash(__PACKAGE__, GV_ADD);
    stash.inherit("MyTest::Cookbook::WAVPlayer");
}