    // Copyright (C) 2003  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #ifndef DLIB_SOCKStREAMBUF_Hh_
    #define DLIB_SOCKStREAMBUF_Hh_

    #include <iosfwd>
    #include <streambuf>
    #include "../sockets.h"
    #include "sockstreambuf_abstract.h"
    #include "sockstreambuf_unbuffered.h"

    namespace dlib
    {

    // ----------------------------------------------------------------------------------------

        class sockstreambuf : public std::streambuf
        {
            /*!
                INITIAL VALUE
                    - con == a connection
                    - in_buffer == an array of in_buffer_size bytes
                    - out_buffer == an array of out_buffer_size bytes

                CONVENTION
                    - in_buffer == the input buffer used by this streambuf
                    - out_buffer == the output buffer used by this streambuf
                    - max_putback == the maximum number of chars to have in the put back buffer.
            !*/

        public:

            // These typedefs are here for backwards compatibility with previous versions of
            // dlib.
            typedef sockstreambuf_unbuffered kernel_1a;
            typedef sockstreambuf kernel_2a;

            sockstreambuf (
                connection* con_
            ) :
                con(*con_),
                out_buffer(0),
                in_buffer(0),
                autoflush(false)
            {
                init();
            }

            sockstreambuf (
                const std::unique_ptr<connection>& con_
            ) :
                con(*con_),
                out_buffer(0),
                in_buffer(0),
                autoflush(false)
            {
                init();
            }

            virtual ~sockstreambuf (
            )
            {
                sync();
                delete [] out_buffer;
                delete [] in_buffer;
            }

            connection* get_connection (
            ) { return &con; }

            void flush_output_on_read()
            {
                autoflush = true;
            }

            bool flushes_output_on_read() const
            {
                return autoflush;
            }

            void do_not_flush_output_on_read()
            {
                autoflush = false;
            }

        protected:

            void init (
            )
            {
                try
                {
                    out_buffer = new char[out_buffer_size];
                    in_buffer = new char[in_buffer_size];
                }
                catch (...)
                {
                    if (out_buffer) delete [] out_buffer;
                    throw;
                }
                setp(out_buffer, out_buffer + (out_buffer_size-1));
                setg(in_buffer+max_putback,
                     in_buffer+max_putback,
                     in_buffer+max_putback);
            }

            int flush_out_buffer (
            )
            {
                int num = static_cast<int>(pptr()-pbase());
                if (con.write(out_buffer,num) != num)
                {
                    // the write was not successful so return EOF
                    return EOF;
                }
                pbump(-num);
                return num;
            }

            // output functions
            int_type overflow (
                int_type c
            );

            int sync (
            )
            {
                if (flush_out_buffer() == EOF)
                {
                    // an error occurred
                    return -1;
                }
                return 0;
            }

            std::streamsize xsputn (
                const char* s,
                std::streamsize num
            );

            // input functions
            int_type underflow(
            );

            std::streamsize xsgetn (
                char_type* s,
                std::streamsize n
            );

        private:

            // member data
            connection&  con;
            static const std::streamsize max_putback = 4;
            static const std::streamsize out_buffer_size = 10000;
            static const std::streamsize in_buffer_size = 10000;
            char* out_buffer;
            char* in_buffer;
            bool autoflush;

        };

    // ----------------------------------------------------------------------------------------

    }

    #ifdef NO_MAKEFILE
    #include "sockstreambuf.cpp"
    #endif

    #endif // DLIB_SOCKStREAMBUF_Hh_