#pragma once
#include <mutex>
#include <string>
namespace lsp
{
class stream
{
public:
    virtual ~stream() = default;
    virtual bool fail() = 0;
    virtual bool bad() = 0;
    virtual bool eof() = 0;
    virtual bool good() = 0;
    virtual void clear() = 0;
    virtual std::string what() = 0;
    virtual bool need_to_clear_the_state()
    {
        return false;
    }

    bool operator!()
    {
        return bad();
    }
};
class istream : public stream
{
public:
    virtual int get() = 0;
    virtual ~istream() = default;
    virtual istream& read(char* str, std::streamsize count) = 0;
};
template<class T>
class base_istream : public istream
{
public:
    explicit base_istream(T& _t) : _impl(_t)
    {
    }

    int get() override
    {
        return _impl.get();
    }
    bool fail() override
    {
        return _impl.fail();
    }
    bool bad() override
    {
        return _impl.bad();
    }
    bool eof() override
    {
        return _impl.eof();
    }
    bool good() override
    {
        return _impl.good();
    }
    istream& read(char* str, std::streamsize count) override
    {
        _impl.read(str, count);
        return *this;
    }

    void clear() override
    {
        _impl.clear();
    }
    T& _impl;
};
class ostream : public stream
{
public:
    virtual ~ostream() = default;

    virtual ostream& write(std::string const&) = 0;
    virtual ostream& write(std::streamsize) = 0;
    virtual ostream& flush() = 0;
};
template<class T>
class base_ostream : public ostream
{
public:
    explicit base_ostream(T& _t) : _impl(_t)
    {
    }

    bool fail() override
    {
        return _impl.fail();
    }
    bool good() override
    {
        return _impl.good();
    }
    bool bad() override
    {
        return _impl.bad();
    }
    bool eof() override
    {
        return _impl.eof();
    }

    ostream& write(std::string const& c) override
    {
        _impl << c;
        return *this;
    }

    ostream& write(std::streamsize _s) override
    {

        _impl << std::to_string(_s);
        return *this;
    }

    ostream& flush() override
    {
        _impl.flush();
        return *this;
    }

    void clear() override
    {
        _impl.clear();
    }

protected:
    T& _impl;
};

template<class T>
class base_iostream : public istream, public ostream
{
public:
    explicit base_iostream(T& _t) : _impl(_t)
    {
    }

    int get() override
    {
        return _impl.get();
    }
    bool fail() override
    {
        return _impl.fail();
    }
    bool bad() override
    {
        return _impl.bad();
    }
    bool eof() override
    {
        return _impl.eof();
    }
    bool good() override
    {
        return _impl.good();
    }
    istream& read(char* str, std::streamsize count) override
    {
        _impl.read(str, count);
        return *this;
    }
    ostream& write(std::string const& c) override
    {
        _impl << c;
        return *this;
    }

    ostream& write(std::streamsize _s) override
    {
        _impl << std::to_string(_s);
        return *this;
    }

    ostream& flush() override
    {
        _impl.flush();
        return *this;
    }

    void clear() override
    {
        _impl.clear();
    }

protected:
    T& _impl;
};
} // namespace lsp
