//  (C) Copyright Gennadiy Rozental 2005-2007.

//  Use, modification, and distribution are subject to the

//  Boost Software License, Version 1.0. (See accompanying file

//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)



//  See http://www.boost.org/libs/test for the library home page.

//

//  File        : $RCSfile$

//

//  Version     : $Revision: 43798 $

//

//  Description : implements models configuration file, it's parameter and parameter namespaces

// ***************************************************************************



// Boost.Runtime.Parameter

#include <boost/test/utils/runtime/config.hpp>



#include <boost/test/utils/runtime/file/config_file.hpp>

#include <boost/test/utils/runtime/validation.hpp>



// Boost.Test

#include <boost/test/utils/foreach.hpp>

#include <boost/test/utils/basic_cstring/basic_cstring.hpp>

#include <boost/test/utils/basic_cstring/io.hpp>

#include <boost/test/utils/iterator/token_iterator.hpp>



namespace boost {



namespace BOOST_RT_PARAM_NAMESPACE {



namespace file {



// ************************************************************************** //

// **************           runtime::file::parameter           ************** //

// ************************************************************************** //



parameter::parameter( cstring name, cstring value, param_namespace const& parent )

: m_parent( parent )

{

    assign_op( p_name.value, name, 0 );

    assign_op( p_value.value, value, 0 );

}



//____________________________________________________________________________//



std::ostream&

operator<<( std::ostream& os, parameter const& p )

{

    p.m_parent.print_full_name( os );



    return os << p.p_name << " = \"" << p.p_value << "\"";

}



//____________________________________________________________________________//



// ************************************************************************** //

// **************        runtime::file::param_namespace        ************** //

// ************************************************************************** //



param_namespace::param_namespace( cstring name, param_namespace const* parent )

: p_parent( parent )

{

    assign_op( p_name.value, name );

}



//____________________________________________________________________________//



void

param_namespace::insert_param( cstring param_name, cstring param_value )

{

    BOOST_TEST_FOREACH( parameter const&, p, m_parameters )

        BOOST_RT_PARAM_VALIDATE_LOGIC( p.p_name != param_name,

                                       BOOST_RT_PARAM_LITERAL( "Duplicate parameter " ) << param_name );



    m_parameters.push_back( parameter( param_name, param_value, *this ) );

}



//____________________________________________________________________________//



param_namespace&

param_namespace::subnamespace( cstring namespace_name )

{

    BOOST_TEST_FOREACH( param_namespace&, subns, m_subnamespaces )

        if( subns.p_name == namespace_name )

            return subns;



    m_subnamespaces.push_back( param_namespace( namespace_name, this ) );



    return m_subnamespaces.back();

}



//____________________________________________________________________________//



void

param_namespace::clear()

{

    m_parameters.clear();

    m_subnamespaces.clear();

}



//____________________________________________________________________________//



void

param_namespace::print_full_name( std::ostream& os ) const

{

    if( !p_parent )

        return;



    p_parent.get()->print_full_name( os );



    os << p_name << "::";

}



//____________________________________________________________________________//



boost::optional<cstring>

get_param_value( param_namespace const& where_from,

                 cstring                name_part1,

                 cstring                name_part2,

                 cstring                name_part3,

                 cstring                name_part4,

                 cstring                name_part5 )

{

    if( name_part2.is_empty() ) {

        boost::optional<cstring> res;



        BOOST_TEST_FOREACH( parameter const&, p, where_from ) {

            if( p.p_name == name_part1 ) {

                res = cstring( p.p_value );

                break;

            }

        }



        return res;

    }

    

    param_namespace const* sns = get_param_subns( where_from, name_part1 );



    return sns ? get_param_value( *sns, name_part2, name_part3, name_part4, name_part5 )

               : boost::optional<cstring>();

}



//____________________________________________________________________________//



cstring

get_requ_param_value( param_namespace const& where_from,

                      cstring                name_part1,

                      cstring                name_part2,

                      cstring                name_part3,

                      cstring                name_part4,

                      cstring                name_part5 )

{

    boost::optional<cstring> v = get_param_value( where_from, name_part1, name_part2, name_part3, name_part4, name_part5 );



#define APPEND_PART( part ) (part.is_empty() ? "" : "::") << (part.is_empty() ? cstring() : part)

    BOOST_RT_PARAM_VALIDATE_LOGIC( !!v, BOOST_RT_PARAM_LITERAL( "Required parameter " ) 

                                        << name_part1 

                                        << APPEND_PART( name_part2 )

                                        << APPEND_PART( name_part3 )

                                        << APPEND_PART( name_part4 )

                                        << APPEND_PART( name_part5 )

                                        << BOOST_RT_PARAM_LITERAL( " value is missing" ) );

#undef APPEND_PART



    return *v;

}



//____________________________________________________________________________//



param_namespace const*

get_param_subns( param_namespace const& where_from, cstring namespace_name )

{

    param_namespace::sub_ns_const_iterator it   = where_from.sub_ns_begin();

    param_namespace::sub_ns_const_iterator end  = where_from.sub_ns_end();



    while( it != end ) {

        if( it->p_name == namespace_name )

            return &*it;



        ++it;

    }



    return 0;

}



//____________________________________________________________________________//



void

param_namespace::load_impl( config_file_iterator cf_it, 

                            cstring value_marker, cstring value_delimeter, cstring namespace_delimeter )

{

    using namespace unit_test;



    while( cf_it != config_file_iterator() ) {

        string_token_iterator ti( *cf_it, (max_tokens = 2,kept_delimeters = dt_none, dropped_delimeters = value_delimeter) );



        cstring param_name  = *ti;

        cstring param_value = *(++ti);



        param_value.trim( value_marker );



        param_namespace* targ_ns = this;



        while( !param_name.is_empty() ) {

            cstring::size_type pos = param_name.find( namespace_delimeter );

            cstring            subname( param_name.begin(), pos == cstring::npos ? param_name.size() : pos );



            if( subname.size() == param_name.size() ) {

                targ_ns->insert_param( param_name, param_value );

                break;

            }

            else {

                targ_ns = &targ_ns->subnamespace( subname );



                param_name.trim_left( subname.size() + namespace_delimeter.size() );

            }

        }

        ++cf_it;

    }

}



//____________________________________________________________________________//



// ************************************************************************** //

// **************          runtime::file::config_file          ************** //

// ************************************************************************** //



config_file::config_file()

: param_namespace( cstring() )

{

}



//____________________________________________________________________________//



config_file::config_file( cstring file_name )

: param_namespace( cstring() )

{

    load( file_name );

}



//____________________________________________________________________________//



} // namespace file



} // namespace BOOST_RT_PARAM_NAMESPACE



} // namespace boost



// EOF

