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

    #include "cmd_line_parser_kernel_abstract.h"
    #include "../algs.h"
    #include "../assert.h"
    #include <string>
    #include "../interfaces/cmd_line_parser_option.h"
    #include "../string.h"

    namespace dlib
    {

        template <
            typename clp_base
            >
        class cmd_line_parser_kernel_c : public clp_base
        {
        public:

            typedef typename clp_base::char_type char_type;
            typedef typename clp_base::string_type string_type;
            typedef typename clp_base::option_type option_type;

            void add_option (
                const string_type& name,
                const string_type& description,
                unsigned long number_of_arguments = 0
            );

            const option_type& option (
                const string_type& name
            ) const;

            unsigned long number_of_arguments(
            ) const;

            const option_type& element (
            ) const;

            option_type& element (
            );

            const string_type& operator[] (
                unsigned long N
            ) const;

        };

        template <
            typename clp_base
            >
        inline void swap (
            cmd_line_parser_kernel_c<clp_base>& a,
            cmd_line_parser_kernel_c<clp_base>& b
        ) { a.swap(b); }

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

        template <
            typename clp_base
            >
        const typename clp_base::string_type& cmd_line_parser_kernel_c<clp_base>::
        operator[] (
            unsigned long N
        ) const
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( this->parsed_line() == true && N < number_of_arguments(),
                     "\tvoid cmd_line_parser::operator[](unsigned long N)"
                     << "\n\tYou must specify a valid index N and the parser must have run already."
                     << "\n\tthis:                      " << this
                     << "\n\tN:                         " << N
                     << "\n\tparsed_line():             " << this->parsed_line()
                     << "\n\tnumber_of_arguments():     " << number_of_arguments()
            );

            return clp_base::operator[](N);
        }

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

        template <
            typename clp_base
            >
        void cmd_line_parser_kernel_c<clp_base>::
        add_option (
            const string_type& name,
            const string_type& description,
            unsigned long number_of_arguments
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( this->parsed_line() == false &&
                     name.size() > 0 &&
                     this->option_is_defined(name) == false &&
                     name.find_first_of(_dT(char_type," \t\n=")) == string_type::npos &&
                     name[0] != '-',
                     "\tvoid cmd_line_parser::add_option(const string_type&,const string_type&,unsigned long)"
                     << "\n\tsee the requires clause of add_option()"
                     << "\n\tthis:                   " << this
                     << "\n\tname.size():            " << static_cast<unsigned long>(name.size())
                     << "\n\tname:                  \"" << narrow(name) << "\""
                     << "\n\tparsed_line():          " << (this->parsed_line()? "true" : "false")
                     << "\n\tis_option_defined(\"" << narrow(name) << "\"): " << (this->option_is_defined(name)? "true" : "false")
            );

            clp_base::add_option(name,description,number_of_arguments);
        }

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

        template <
            typename clp_base
            >
        const typename clp_base::option_type& cmd_line_parser_kernel_c<clp_base>::
        option (
            const string_type& name
        ) const
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( this->option_is_defined(name) == true,
                     "\toption cmd_line_parser::option(const string_type&)"
                     << "\n\tto get an option it must be defined by a call to add_option()"
                     << "\n\tthis:   " << this
                     << "\n\tname:  \"" << narrow(name) << "\""
            );

            return clp_base::option(name);
        }

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

        template <
            typename clp_base
            >
        unsigned long cmd_line_parser_kernel_c<clp_base>::
        number_of_arguments(
        ) const
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( this->parsed_line() == true ,
                     "\tunsigned long cmd_line_parser::number_of_arguments()"
                     << "\n\tyou must parse the command line before you can find out how many arguments it has"
                     << "\n\tthis:            " << this
            );

            return clp_base::number_of_arguments();
        }

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

        template <
            typename clp_base
            >
        const typename clp_base::option_type& cmd_line_parser_kernel_c<clp_base>::
        element (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(this->current_element_valid() == true,
                    "\tconst cmd_line_parser_option& cmd_line_parser::element()"
                    << "\n\tyou can't access the current element if it doesn't exist"
                    << "\n\tthis: " << this
            );

            // call the real function
            return clp_base::element();
        }

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

        template <
            typename clp_base
            >
        typename clp_base::option_type& cmd_line_parser_kernel_c<clp_base>::
        element (
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(this->current_element_valid() == true,
                    "\tcmd_line_parser_option& cmd_line_parser::element()"
                    << "\n\tyou can't access the current element if it doesn't exist"
                    << "\n\tthis: " << this
            );

            // call the real function
            return clp_base::element();
        }

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

    }

    #endif // DLIB_CMD_LINE_PARSER_KERNEl_C_