// Boost.Assign library
//
//  Copyright Thorsten Ottosen 2003-2004. Use, modification and
//  distribution is 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)
//
// For more information, see http://www.boost.org/libs/assign/
//


#include <boost/detail/workaround.hpp>

#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
###pragma warn -8091 // supress warning in Boost.Test
###pragma warn -8057 // unused argument argc/argv in Boost.Test
#endif

#include <boost/assign/list_inserter.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <vector>
#include <map>

namespace ba = boost::assign;

class email
{
public:
    enum address_option
    {
        check_addr_book,
        dont_check_addr_book
    };
    
    typedef std::pair<std::string,address_option> bcc_type;
    typedef std::vector< bcc_type >               bcc_map;
    typedef std::map<std::string,address_option>  address_map;
    
    
private:

    mutable address_map      cc_list;
    mutable address_map      to_list;
    bcc_map                  bcc_list;
            
    struct add_to_map
    {
        address_map& m;
    
        add_to_map( address_map& m ) : m(m)        
        {}
    
        void operator()( const std::string& name, address_option ao )
        {
            m[ name ] = ao; 
        }
        
        void operator()( const std::string& name )
        {
            m[ name ] = check_addr_book;
        }
    };

    struct add_to_vector
    {
        bcc_map& m;
        
        add_to_vector( bcc_map& m ) : m(m)
        {}
        
        void operator()( const bcc_type& r )
        {
            m.push_back( r );
        }
    };

public:
    
    ba::list_inserter< add_to_map >
    add_cc( std::string name, address_option ao )
    {
        return ba::make_list_inserter( add_to_map( cc_list ) )( name, ao );
    }

    ba::list_inserter< add_to_map >
    add_to( const std::string& name )
    {
        return ba::make_list_inserter( add_to_map( to_list ) )( name );
    }
    
    ba::list_inserter< add_to_vector, bcc_type >
    add_bcc( const bcc_type& bcc )
    {
        return ba::make_list_inserter( add_to_vector( bcc_list ) )( bcc );     
    }
    
    address_option
    cc_at( const std::string& name ) const
    {
        return cc_list[ name ];
    }
    
    address_option 
    to_at( const std::string& name ) const
    {
        return to_list[ name ];
    }
    
    address_option
    bcc_at( unsigned index ) const
    {
        return bcc_list.at( index ).second;
    }
};



void check_list_inserter()
{
    using namespace boost::assign;

    email e;
    e.add_cc( "franz", email::dont_check_addr_book )
            ( "hanz", email::check_addr_book )
            ( "betty", email::dont_check_addr_book );
    BOOST_CHECK_EQUAL( e.cc_at( "franz" ), email::dont_check_addr_book );
    BOOST_CHECK_EQUAL( e.cc_at( "hanz" ), email::check_addr_book );
    BOOST_CHECK_EQUAL( e.cc_at( "betty" ), email::dont_check_addr_book );

    e.add_to( "betsy" )( "peter" );
    BOOST_CHECK_EQUAL( e.cc_at( "betsy" ), email::check_addr_book );
    BOOST_CHECK_EQUAL( e.cc_at( "peter" ), email::check_addr_book );
    
    e.add_bcc( email::bcc_type( "Mr. Foo", email::check_addr_book ) )
             ( "Mr. Bar", email::dont_check_addr_book );
    BOOST_CHECK_EQUAL( e.bcc_at( 0 ), email::check_addr_book );
    BOOST_CHECK_EQUAL( e.bcc_at( 1 ), email::dont_check_addr_book );
    
}



#include <boost/test/included/unit_test_framework.hpp> 

using boost::unit_test_framework::test_suite;

test_suite* init_unit_test_suite( int argc, char* argv[] )
{
    test_suite* test = BOOST_TEST_SUITE( "List Test Suite" );

    test->add( BOOST_TEST_CASE( &check_list_inserter ) );

    return test;
}