// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2008
//
// Distributed under 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)

#ifndef MOCK_ROOT_HPP_INCLUDED
#define MOCK_ROOT_HPP_INCLUDED

#include "../config.hpp"
#include "parent.hpp"
#include "group.hpp"
#include "context.hpp"
#include "child.hpp"
#include "mutex.hpp"
#include "singleton.hpp"
#include <boost/optional.hpp>
#include <ostream>
#include <map>

namespace mock
{
namespace detail
{
    class root_t : public singleton< root_t >, public context
    {
    public:
        virtual void add( const void* p, verifiable& v,
            boost::unit_test::const_string instance,
            boost::optional< type_name > type,
            boost::unit_test::const_string name )
        {
            scoped_lock _( mutex_ );
            children_t::iterator it = children_.lower_bound( &v );
            if( it == children_.end() ||
                children_.key_comp()( &v, it->first ) )
                it = children_.insert( it,
                    std::make_pair( &v, counter_child( parents_, p ) ) );
            it->second.update( instance, type, name );
        }
        virtual void add( verifiable& v )
        {
            scoped_lock _( mutex_ );
            group_.add( v );
        }

        virtual void remove( verifiable& v )
        {
            scoped_lock _( mutex_ );
            group_.remove( v );
            children_.erase( &v );
        }

        bool verify() const
        {
            scoped_lock _( mutex_ );
            return group_.verify();
        }
        void reset()
        {
            scoped_lock _( mutex_ );
            group_.reset();
        }

        virtual void serialize( std::ostream& s, const verifiable& v ) const
        {
            scoped_lock _( mutex_ );
            children_cit it = children_.find( &v );
            if( it != children_.end() )
                s << it->second;
            else
                s << "?";
        }

    private:
        typedef std::map< const void*,
            std::pair< parent, std::size_t > > parents_t;

        class counter_child
        {
        public:
            counter_child( parents_t& parents, const void* p )
                : parents_( &parents )
                , it_( parents.insert(
                    std::make_pair( p, parents_t::mapped_type() ) ).first )
            {
                ++it_->second.second;
            }
            counter_child( const counter_child& rhs )
                : parents_( rhs.parents_ )
                , it_( rhs.it_ )
                , child_( rhs.child_ )
            {
                ++it_->second.second;
            }
            ~counter_child()
            {
                if( --it_->second.second == 0 )
                    parents_->erase( it_ );
            }
            void update( boost::unit_test::const_string instance,
                boost::optional< type_name > type,
                boost::unit_test::const_string name )
            {
                child_.update( it_->second.first, instance, type, name );
            }
            friend std::ostream& operator<<( std::ostream& s,
                const counter_child& c )
            {
                return s << c.child_;
            }

        private:
            counter_child& operator=( const counter_child& );

            parents_t* parents_;
            parents_t::iterator it_;
            child child_;
        };

        typedef std::map< const verifiable*, counter_child > children_t;
        typedef children_t::const_iterator children_cit;

        parents_t parents_;
        children_t children_;
        group group_;
        mutable mutex mutex_;

        MOCK_SINGLETON_CONS( root_t );
    };
    MOCK_SINGLETON_INST( root )
}
} // mock

#endif // MOCK_ROOT_HPP_INCLUDED
