// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#include <sstream>
#include <string>
#include <ctime>
#include <cstdlib>
#include <dlib/entropy_encoder_model.h>
#include <dlib/entropy_decoder_model.h>
#include <dlib/entropy_encoder.h>
#include <dlib/entropy_decoder.h>
#include "tester.h"
namespace  
{
    using namespace test;
    using namespace std;
    using namespace dlib;
    logger dlog("test.entropy_coder_model");
    template <
        typename ee,
        typename ed
        >
    void entropy_encoder_model_kernel_test (
    )
    /*!
        requires
            - ee is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h            
              the alphabet_size for ee is 256
            - ed is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h            
              the alphabet_size for ed is 256
            - ee and ed must share the same kernel number
        ensures
            - runs tests on ee and ed for compliance with the specs 
    !*/
    {        
        print_spinner();
        srand(static_cast<unsigned int>(time(0)));
        typedef typename ee::entropy_encoder_type ee_type;
        typedef typename ed::entropy_decoder_type ed_type;
        {
            ee_type ecoder;
            ed_type dcoder;
            ee elen(ecoder);
            ed dlen(dcoder);
            ee elit(ecoder);
            ed dlit(dcoder);
            istringstream sin;
            ostringstream sout;
            ecoder.set_stream(sout);
            unsigned long temp;
            elen.encode(0);
            elit.encode(9);
            elen.encode(0);
            elit.encode(0);
            elen.encode(0);
            elit.encode(4);
            elen.encode(0);
            elit.encode(0);
            elen.encode(0);
            elit.encode(2);
            elen.encode(0);
            elit.encode(0);
            ecoder.clear();
            sin.str(sout.str());
            dcoder.set_stream(sin);
            dlen.decode(temp);
            DLIB_TEST(temp == 0);
            dlit.decode(temp);
            DLIB_TEST(temp == 9);
            dlen.decode(temp);
            DLIB_TEST(temp == 0);
            dlit.decode(temp);
            DLIB_TEST(temp == 0);
            dlen.decode(temp);
            DLIB_TEST(temp == 0);
            dlit.decode(temp);
            DLIB_TEST(temp == 4);
            dlen.decode(temp);
            DLIB_TEST(temp == 0);
            dlit.decode(temp);
            DLIB_TEST(temp == 0);
            dlen.decode(temp);
            DLIB_TEST(temp == 0);
            dlit.decode(temp);
            DLIB_TEST(temp == 2);
            dlen.decode(temp);
            DLIB_TEST(temp == 0);
            dlit.decode(temp);
            DLIB_TEST(temp == 0);
        }
    }
    class entropy_encoder_model_tester : public tester
    {
    public:
        entropy_encoder_model_tester (
        ) :
            tester ("test_entropy_coder_model",
                    "Runs tests on the entropy_encoder_model and entropy_decoder_model components.")
        {}
        void perform_test (
        )
        {
            typedef entropy_encoder::kernel_2a_c ee;
            typedef entropy_decoder::kernel_2a_c ed;
            dlog << LINFO << "testing kernel_1a";
            entropy_encoder_model_kernel_test<
                entropy_encoder_model<256,ee>::kernel_1a,
                entropy_decoder_model<256,ed>::kernel_1a>();
            dlog << LINFO << "testing kernel_2a";
            entropy_encoder_model_kernel_test<
                entropy_encoder_model<256,ee>::kernel_2a,
                entropy_decoder_model<256,ed>::kernel_2a>();
            dlog << LINFO << "testing kernel_3a";
            entropy_encoder_model_kernel_test<
                entropy_encoder_model<256,ee>::kernel_3a,
                entropy_decoder_model<256,ed>::kernel_3a>();
            dlog << LINFO << "testing kernel_4a";
            entropy_encoder_model_kernel_test<
                entropy_encoder_model<256,ee>::kernel_4a,
                entropy_decoder_model<256,ed>::kernel_4a>();
            dlog << LINFO << "testing kernel_4b";
            entropy_encoder_model_kernel_test<
                entropy_encoder_model<256,ee>::kernel_4b,
                entropy_decoder_model<256,ed>::kernel_4b>();
            dlog << LINFO << "testing kernel_5a";
            entropy_encoder_model_kernel_test<
                entropy_encoder_model<256,ee>::kernel_5a,
                entropy_decoder_model<256,ed>::kernel_5a>();
            dlog << LINFO << "testing kernel_5c";
            entropy_encoder_model_kernel_test<
                entropy_encoder_model<256,ee>::kernel_5c,
                entropy_decoder_model<256,ed>::kernel_5c>();
            dlog << LINFO << "testing kernel_6a";
            entropy_encoder_model_kernel_test<
                entropy_encoder_model<256,ee>::kernel_6a,
                entropy_decoder_model<256,ed>::kernel_6a>();
        }
    } a;
}