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


#include <sstream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <dlib/iosockstream.h>
#include <dlib/server.h>
#include <vector>

#include "tester.h"

namespace  
{

    using namespace test;
    using namespace dlib;
    using namespace std;


    logger dlog("test.iosockstream");

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

    class serv : public server_iostream
    {
        virtual void on_connect (
            std::istream& in,
            std::ostream& out,
            const std::string& ,
            const std::string& ,
            unsigned short ,
            unsigned short ,
            uint64 
        )
        {
            try
            {
                dlog << LINFO << "serv1: serving connection";

                std::string temp;
                in >> temp;
                DLIB_TEST(temp == "word");
                in >> temp;
                DLIB_TEST(temp == "another");
                out << "yay words ";
                in >> temp;
                DLIB_TEST(temp == "yep");
            }
            catch (error& e)
            {
                error_string = e.what();
            }

        }


    public:
        std::string error_string;

    };

    class serv2 : public server_iostream
    {
        virtual void on_connect (
            std::istream& ,
            std::ostream& out,
            const std::string& ,
            const std::string& ,
            unsigned short ,
            unsigned short ,
            uint64 
        )
        {
            try
            {
                dlog << LINFO << "serv2: serving connection";

                out << "one two three four five";
            }
            catch (error& e)
            {
                error_string = e.what();
            }

        }


    public:
        std::string error_string;

    };

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

    void test1()
    {
        dlog << LINFO << "in test1()";
        serv theserv;
        theserv.set_listening_port(12345);
        theserv.start_async();

        // wait a little bit to make sure the server has started listening before we try 
        // to connect to it.
        dlib::sleep(500);

        for (int i = 0; i < 200; ++i)
        {
            dlog << LINFO << "i: " << i;
            print_spinner();
            iosockstream stream("localhost:12345");

            stream << "word another ";
            std::string temp;
            stream >> temp;
            DLIB_TEST(temp == "yay");
            stream >> temp;
            DLIB_TEST(temp == "words");
            stream << "yep ";
        }

        // Just to make sure the server finishes processing the last connection before
        // we kill it and accidentally trigger a DLIB_TEST().
        dlib::sleep(500);

        if (theserv.error_string.size() != 0)
            throw error(theserv.error_string);
    }

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

    void test2()
    {
        dlog << LINFO << "in test2()";
        serv2 theserv;
        theserv.set_listening_port(12345);
        theserv.start_async();

        // wait a little bit to make sure the server has started listening before we try 
        // to connect to it.
        dlib::sleep(500);

        for (int i = 0; i < 200; ++i)
        {
            dlog << LINFO << "i: " << i;
            print_spinner();
            iosockstream stream("localhost:12345");

            std::string temp;
            stream >> temp; DLIB_TEST(temp == "one");
            stream >> temp; DLIB_TEST(temp == "two");
            stream >> temp; DLIB_TEST(temp == "three");
            stream >> temp; DLIB_TEST(temp == "four");
            stream >> temp; DLIB_TEST(temp == "five");
        }
    }

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

    class test_iosockstream : public tester
    {
    public:
        test_iosockstream (
        ) :
            tester ("test_iosockstream",
                    "Runs tests on the iosockstream component.")
        {}

        void perform_test (
        )
        {
            test1();
            test2();
        }
    } a;

}