// Copyright (C) 2003  Davis E. King (davisking@users.sourceforge.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_C_
#define DLIB_CONDITIONING_CLASS_KERNEl_C_

#include "conditioning_class_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <iostream>

namespace dlib
{

    template <
        typename cc_base
        >
    class conditioning_class_kernel_c : public cc_base
    {
        const unsigned long alphabet_size;

    public:

        conditioning_class_kernel_c (
            typename cc_base::global_state_type& global_state
            ) : cc_base(global_state),alphabet_size(cc_base::get_alphabet_size()) {}

        bool increment_count (
            unsigned long symbol,
            unsigned short amount = 1
        );

        unsigned long get_count (
            unsigned long symbol
        ) const;

        unsigned long get_range (
            unsigned long symbol,
            unsigned long& low_count,
            unsigned long& high_count,
            unsigned long& total_count
        ) const;

        void get_symbol (
            unsigned long target,
            unsigned long& symbol,            
            unsigned long& low_count,
            unsigned long& high_count
        ) const;
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename cc_base
        >
    bool conditioning_class_kernel_c<cc_base>::
    increment_count (
        unsigned long symbol,
        unsigned short amount
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(symbol < alphabet_size &&
                0 < amount && amount < 32768,
                "\tvoid conditioning_class::increment_count()"
                << "\n\tthe symbol must be in the range 0 to alphabet_size-1. and"
                << "\n\tamount must be in the range 1 to 32767"
                << "\n\talphabet_size: " << alphabet_size
                << "\n\tsymbol:        " << symbol
                << "\n\tamount:        " << amount
                << "\n\tthis:          " << this
        );

        // call the real function
        return cc_base::increment_count(symbol,amount);
    }

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

    template <
        typename cc_base
        >
    unsigned long conditioning_class_kernel_c<cc_base>::
    get_count (
        unsigned long symbol
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(symbol < alphabet_size,
                "\tvoid conditioning_class::get_count()"
                << "\n\tthe symbol must be in the range 0 to alphabet_size-1"
                << "\n\talphabet_size: " << alphabet_size
                << "\n\tsymbol:        " << symbol
                << "\n\tthis:          " << this
        );

        // call the real function
        return cc_base::get_count(symbol);
    }

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

    template <
        typename cc_base
        >
    unsigned long conditioning_class_kernel_c<cc_base>::
    get_range (
        unsigned long symbol,
        unsigned long& low_count,
        unsigned long& high_count,
        unsigned long& total_count
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(symbol < alphabet_size,
                "\tvoid conditioning_class::get_range()"
                << "\n\tthe symbol must be in the range 0 to alphabet_size-1"
                << "\n\talphabet_size: " << alphabet_size
                << "\n\tsymbol:        " << symbol
                << "\n\tthis:          " << this
        );

        // call the real function
        return cc_base::get_range(symbol,low_count,high_count,total_count);
    }

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

    template <
        typename cc_base
        >
    void conditioning_class_kernel_c<cc_base>::
    get_symbol (
        unsigned long target,
        unsigned long& symbol,            
        unsigned long& low_count,
        unsigned long& high_count
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( target < this->get_total(),
                 "\tvoid conditioning_class::get_symbol()"
                 << "\n\tthe target must be in the range 0 to get_total()-1"
                 << "\n\tget_total(): " << this->get_total()
                 << "\n\ttarget:       " << target
                 << "\n\tthis:         " << this
        );

        // call the real function
        cc_base::get_symbol(target,symbol,low_count,high_count);
    }

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

}

#endif // DLIB_CONDITIONING_CLASS_KERNEl_C_

