#ifndef BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED
#define BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED
//////////////////////////////////////////////////////////////////////////////
// Copyright 2002-2010 Andreas Huber Doenni
// Distributed under the Boost Software License, Version 1.0. (See accompany-
// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//////////////////////////////////////////////////////////////////////////////



#include <boost/statechart/event.hpp>
#include <boost/statechart/null_exception_translator.hpp>
#include <boost/statechart/result.hpp>

#include <boost/statechart/detail/rtti_policy.hpp>
#include <boost/statechart/detail/state_base.hpp>
#include <boost/statechart/detail/leaf_state.hpp>
#include <boost/statechart/detail/node_state.hpp>
#include <boost/statechart/detail/constructor.hpp>
#include <boost/statechart/detail/avoid_unused_warning.hpp>

#include <boost/mpl/list.hpp>
#include <boost/mpl/clear.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/integral_c.hpp>
#include <boost/mpl/minus.hpp>
#include <boost/mpl/equal_to.hpp>

#include <boost/intrusive_ptr.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/noncopyable.hpp>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/cast.hpp> // boost::polymorphic_downcast
// BOOST_NO_EXCEPTIONS, BOOST_MSVC, BOOST_MSVC_STD_ITERATOR
#include <boost/config.hpp>

#include <boost/detail/allocator_utilities.hpp>

#ifdef BOOST_MSVC
#  pragma warning( push )
#  pragma warning( disable: 4702 ) // unreachable code (in release mode only)
#endif

#include <map>

#ifdef BOOST_MSVC
#  pragma warning( pop )
#endif

#include <memory>   // std::allocator
#include <typeinfo> // std::bad_cast
#include <functional> // std::less
#include <iterator>



namespace boost
{
namespace statechart
{
namespace detail
{



//////////////////////////////////////////////////////////////////////////////
template< class StateBaseType, class EventBaseType, class IdType >
class send_function
{
  public:
    //////////////////////////////////////////////////////////////////////////
    send_function(
      StateBaseType & toState,
      const EventBaseType & evt,
      IdType eventType
    ) :
      toState_( toState ), evt_( evt ), eventType_( eventType )
    {
    }

    result operator()()
    {
      return detail::result_utility::make_result(
        toState_.react_impl( evt_, eventType_ ) );
    }

  private:
    //////////////////////////////////////////////////////////////////////////
    // avoids C4512 (assignment operator could not be generated)
    send_function & operator=( const send_function & );

    StateBaseType & toState_;
    const EventBaseType & evt_;
    IdType eventType_;
};


//////////////////////////////////////////////////////////////////////////////
struct state_cast_impl_pointer_target
{
  public:
    //////////////////////////////////////////////////////////////////////////
    template< class StateBaseType >
    static const StateBaseType * deref_if_necessary(
      const StateBaseType * pState )
    {
      return pState;
    }

    template< class Target, class IdType >
    static IdType type_id()
    {
      Target p = 0;
      return type_id_impl< IdType >( p );
    }

    static bool found( const void * pFound )
    {
      return pFound != 0;
    }

    template< class Target >
    static Target not_found()
    {
      return 0;
    }

  private:
    //////////////////////////////////////////////////////////////////////////
    template< class IdType, class Type >
    static IdType type_id_impl( const Type * )
    {
      return Type::static_type();
    }
};

struct state_cast_impl_reference_target
{
  template< class StateBaseType >
  static const StateBaseType & deref_if_necessary(
    const StateBaseType * pState )
  {
    return *pState;
  }

  template< class Target, class IdType >
  static IdType type_id()
  {
    return remove_reference< Target >::type::static_type();
  }

  template< class Dummy >
  static bool found( const Dummy & )
  {
    return true;
  }

  template< class Target >
  static Target not_found()
  {
    throw std::bad_cast();
  }
};

template< class Target >
struct state_cast_impl : public mpl::if_<
  is_pointer< Target >,
  state_cast_impl_pointer_target,
  state_cast_impl_reference_target
>::type {};


//////////////////////////////////////////////////////////////////////////////
template< class RttiPolicy >
class history_key
{
  public:
    //////////////////////////////////////////////////////////////////////////
    template< class HistorizedState >
    static history_key make_history_key()
    {
      return history_key(
        HistorizedState::context_type::static_type(),
        HistorizedState::orthogonal_position::value );
    }

    typename RttiPolicy::id_type history_context_type() const
    {
      return historyContextType_;
    }

    friend bool operator<(
      const history_key & left, const history_key & right )
    {
      return
        std::less< typename RttiPolicy::id_type >()( 
          left.historyContextType_, right.historyContextType_ ) ||
        ( ( left.historyContextType_ == right.historyContextType_ ) &&
          ( left.historizedOrthogonalRegion_ <
            right.historizedOrthogonalRegion_ ) );
    }

  private:
    //////////////////////////////////////////////////////////////////////////
    history_key(
      typename RttiPolicy::id_type historyContextType, 
      orthogonal_position_type historizedOrthogonalRegion
    ) :
      historyContextType_( historyContextType ),
      historizedOrthogonalRegion_( historizedOrthogonalRegion )
    {
    }

    // avoids C4512 (assignment operator could not be generated)
    history_key & operator=( const history_key & );

    const typename RttiPolicy::id_type historyContextType_;
    const orthogonal_position_type historizedOrthogonalRegion_;
};



} // namespace detail



//////////////////////////////////////////////////////////////////////////////
template< class MostDerived,
          class InitialState,
          class Allocator = std::allocator< void >,
          class ExceptionTranslator = null_exception_translator >
class state_machine : noncopyable
{
  public:
    //////////////////////////////////////////////////////////////////////////
    typedef Allocator allocator_type;
    typedef detail::rtti_policy rtti_policy_type;
    typedef event_base event_base_type;
    typedef intrusive_ptr< const event_base_type > event_base_ptr_type;

    void initiate()
    {
      terminate();

      {
        terminator guard( *this, 0 );
        detail::result_utility::get_result( translator_(
          initial_construct_function( *this ),
          exception_event_handler( *this ) ) );
        guard.dismiss();
      }

      process_queued_events();
    }

    void terminate()
    {
      terminator guard( *this, 0 );
      detail::result_utility::get_result( translator_(
        terminate_function( *this ),
        exception_event_handler( *this ) ) );
      guard.dismiss();
    }

    bool terminated() const
    {
      return pOutermostState_ == 0;
    }

    void process_event( const event_base_type & evt )
    {
      if ( send_event( evt ) == detail::do_defer_event )
      {
        deferredEventQueue_.push_back( evt.intrusive_from_this() );
      }

      process_queued_events();
    }

    template< class Target >
    Target state_cast() const
    {
      typedef detail::state_cast_impl< Target > impl;

      for ( typename state_list_type::const_iterator pCurrentLeafState =
              currentStates_.begin();
            pCurrentLeafState != currentStatesEnd_;
            ++pCurrentLeafState )
      {
        const state_base_type * pCurrentState(
          get_pointer( *pCurrentLeafState ) );

        while ( pCurrentState != 0 )
        {
          // The unnecessary try/catch overhead for pointer targets is
          // typically small compared to the cycles dynamic_cast needs
          #ifndef BOOST_NO_EXCEPTIONS
          try
          #endif
          {
            Target result = dynamic_cast< Target >(
              impl::deref_if_necessary( pCurrentState ) );

            if ( impl::found( result ) )
            {
              return result;
            }
          }
          #ifndef BOOST_NO_EXCEPTIONS
          // Intentionally swallow std::bad_cast exceptions. We'll throw one
          // ourselves when we fail to find a state that can be cast to Target
          catch ( const std::bad_cast & ) {}
          #endif

          pCurrentState = pCurrentState->outer_state_ptr();
        }
      }

      return impl::template not_found< Target >();
    }

    template< class Target >
    Target state_downcast() const
    {
      typedef detail::state_cast_impl< Target > impl;

      typename rtti_policy_type::id_type targetType =
        impl::template type_id< Target, rtti_policy_type::id_type >();

      for ( typename state_list_type::const_iterator pCurrentLeafState =
              currentStates_.begin();
            pCurrentLeafState != currentStatesEnd_;
            ++pCurrentLeafState )
      {
        const state_base_type * pCurrentState(
          get_pointer( *pCurrentLeafState ) );

        while ( pCurrentState != 0 )
        {
          if ( pCurrentState->dynamic_type() == targetType )
          {
            return static_cast< Target >(
              impl::deref_if_necessary( pCurrentState ) );
          }

          pCurrentState = pCurrentState->outer_state_ptr();
        }
      }

      return impl::template not_found< Target >();
    }

    typedef detail::state_base< allocator_type, rtti_policy_type >
      state_base_type;

    class state_iterator : public std::iterator<
      std::forward_iterator_tag,
      state_base_type, std::ptrdiff_t
      #ifndef BOOST_MSVC_STD_ITERATOR
      , const state_base_type *, const state_base_type &
      #endif
    >
    {
      public:
        //////////////////////////////////////////////////////////////////////
        explicit state_iterator(
          typename state_base_type::state_list_type::const_iterator 
            baseIterator
        ) : baseIterator_( baseIterator ) {}

        const state_base_type & operator*() const { return **baseIterator_; }
        const state_base_type * operator->() const
        {
          return &**baseIterator_;
        }

        state_iterator & operator++() { ++baseIterator_; return *this; }
        state_iterator operator++( int )
        {
          return state_iterator( baseIterator_++ );
        }

        bool operator==( const state_iterator & right ) const
        {
          return baseIterator_ == right.baseIterator_;
        }
        bool operator!=( const state_iterator & right ) const
        {
          return !( *this == right );
        }

      private:
        typename state_base_type::state_list_type::const_iterator
          baseIterator_;
    };

    state_iterator state_begin() const
    {
      return state_iterator( currentStates_.begin() );
    }

    state_iterator state_end() const
    {
      return state_iterator( currentStatesEnd_ );
    }

    void unconsumed_event( const event_base & ) {}

  protected:
    //////////////////////////////////////////////////////////////////////////
    state_machine() :
      currentStatesEnd_( currentStates_.end() ),
      pOutermostState_( 0 ),
      isInnermostCommonOuter_( false ),
      performFullExit_( true ),
      pTriggeringEvent_( 0 )
    {
    }

    // This destructor was only made virtual so that that
    // polymorphic_downcast can be used to cast to MostDerived.
    virtual ~state_machine()
    {
      terminate_impl( false );
    }

    void post_event( const event_base_ptr_type & pEvent )
    {
      post_event_impl( pEvent );
    }

    void post_event( const event_base & evt )
    {
      post_event_impl( evt );
    }

  public:
    //////////////////////////////////////////////////////////////////////////
    // The following declarations should be protected.
    // They are only public because many compilers lack template friends.
    //////////////////////////////////////////////////////////////////////////
    template<
      class HistoryContext,
      detail::orthogonal_position_type orthogonalPosition >
    void clear_shallow_history()
    {
      // If you receive a
      // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'" or
      // similar compiler error here then you tried to clear shallow history
      // for a state that does not have shallow history. That is, the state
      // does not pass either statechart::has_shallow_history or
      // statechart::has_full_history to its base class template.
      BOOST_STATIC_ASSERT( HistoryContext::shallow_history::value );

      typedef typename mpl::at_c<
        typename HistoryContext::inner_initial_list,
        orthogonalPosition >::type historized_state;

      store_history_impl(
        shallowHistoryMap_,
        history_key_type::make_history_key< historized_state >(),
        0 );
    }

    template<
      class HistoryContext,
      detail::orthogonal_position_type orthogonalPosition >
    void clear_deep_history()
    {
      // If you receive a
      // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'" or
      // similar compiler error here then you tried to clear deep history for
      // a state that does not have deep history. That is, the state does not
      // pass either statechart::has_deep_history or
      // statechart::has_full_history to its base class template
      BOOST_STATIC_ASSERT( HistoryContext::deep_history::value );

      typedef typename mpl::at_c<
        typename HistoryContext::inner_initial_list,
        orthogonalPosition >::type historized_state;

      store_history_impl(
        deepHistoryMap_,
        history_key_type::make_history_key< historized_state >(),
        0 );
    }

    const event_base_type * triggering_event() const
    {
        return pTriggeringEvent_;
    }

  public:
    //////////////////////////////////////////////////////////////////////////
    // The following declarations should be private.
    // They are only public because many compilers lack template friends.
    //////////////////////////////////////////////////////////////////////////
    typedef MostDerived inner_context_type;
    typedef mpl::integral_c< detail::orthogonal_position_type, 0 >
      inner_orthogonal_position;
    typedef mpl::integral_c< detail::orthogonal_position_type, 1 >
      no_of_orthogonal_regions;

    typedef MostDerived outermost_context_type;
    typedef state_machine outermost_context_base_type;
    typedef state_machine * inner_context_ptr_type;
    typedef typename state_base_type::node_state_base_ptr_type
      node_state_base_ptr_type;
    typedef typename state_base_type::leaf_state_ptr_type leaf_state_ptr_type;
    typedef typename state_base_type::state_list_type state_list_type;

    typedef mpl::clear< mpl::list<> >::type context_type_list;

    typedef mpl::bool_< false > shallow_history;
    typedef mpl::bool_< false > deep_history;
    typedef mpl::bool_< false > inherited_deep_history;

    void post_event_impl( const event_base_ptr_type & pEvent )
    {
      BOOST_ASSERT( get_pointer( pEvent ) != 0 );
      eventQueue_.push_back( pEvent );
    }

    void post_event_impl( const event_base & evt )
    {
      post_event_impl( evt.intrusive_from_this() );
    }

    detail::reaction_result react_impl(
      const event_base_type &,
      typename rtti_policy_type::id_type )
    {
      return detail::do_forward_event;
    }

    void exit_impl(
      inner_context_ptr_type &,
      typename state_base_type::node_state_base_ptr_type &,
      bool ) {}

    void set_outermost_unstable_state(
      typename state_base_type::node_state_base_ptr_type &
        pOutermostUnstableState )
    {
      pOutermostUnstableState = 0;
    }

    // Returns a reference to the context identified by the template
    // parameter. This can either be _this_ object or one of its direct or
    // indirect contexts.
    template< class Context >
    Context & context()
    {
      // As we are in the outermost context here, only this object can be
      // returned.
      return *polymorphic_downcast< MostDerived * >( this );
    }

    template< class Context >
    const Context & context() const
    {
      // As we are in the outermost context here, only this object can be
      // returned.
      return *polymorphic_downcast< const MostDerived * >( this );
    }

    outermost_context_type & outermost_context()
    {
      return *polymorphic_downcast< MostDerived * >( this );
    }

    const outermost_context_type & outermost_context() const
    {
      return *polymorphic_downcast< const MostDerived * >( this );
    }

    outermost_context_base_type & outermost_context_base()
    {
      return *this;
    }

    const outermost_context_base_type & outermost_context_base() const
    {
      return *this;
    }

    void terminate_as_reaction( state_base_type & theState )
    {
      terminate_impl( theState, performFullExit_ );
      pOutermostUnstableState_ = 0;
    }

    void terminate_as_part_of_transit( state_base_type & theState )
    {
      terminate_impl( theState, performFullExit_ );
      isInnermostCommonOuter_ = true;
    }

    void terminate_as_part_of_transit( state_machine & )
    {
      terminate_impl( *pOutermostState_, performFullExit_ );
      isInnermostCommonOuter_ = true;
    }


    template< class State >
    void add( const intrusive_ptr< State > & pState )
    {
      // The second dummy argument is necessary because the call to the
      // overloaded function add_impl would otherwise be ambiguous.
      node_state_base_ptr_type pNewOutermostUnstableStateCandidate =
        add_impl( pState, *pState );

      if ( isInnermostCommonOuter_ ||
        ( is_in_highest_orthogonal_region< State >() &&
        ( get_pointer( pOutermostUnstableState_ ) ==
          pState->State::outer_state_ptr() ) ) )
      {
        isInnermostCommonOuter_ = false;
        pOutermostUnstableState_ = pNewOutermostUnstableStateCandidate;
      }
    }


    void add_inner_state(
      detail::orthogonal_position_type position,
      state_base_type * pOutermostState )
    {
      BOOST_ASSERT( position == 0 );
      detail::avoid_unused_warning( position );
      pOutermostState_ = pOutermostState;
    }

    void remove_inner_state( detail::orthogonal_position_type position )
    {
      BOOST_ASSERT( position == 0 );
      detail::avoid_unused_warning( position );
      pOutermostState_ = 0;
    }


    void release_events()
    {
      eventQueue_.splice( eventQueue_.begin(), deferredEventQueue_ );
    }


    template< class HistorizedState >
    void store_shallow_history()
    {
      // 5.2.10.6 declares that reinterpret_casting a function pointer to a
      // different function pointer and back must yield the same value. The
      // following reinterpret_cast is the first half of such a sequence.
      store_history_impl(
        shallowHistoryMap_,
        history_key_type::make_history_key< HistorizedState >(),
        reinterpret_cast< void (*)() >( &HistorizedState::deep_construct ) );
    }

    template< class DefaultState >
    void construct_with_shallow_history(
      const typename DefaultState::context_ptr_type & pContext )
    {
      construct_with_history_impl< DefaultState >(
        shallowHistoryMap_, pContext );
    }


    template< class HistorizedState, class LeafState >
    void store_deep_history()
    {
      typedef typename detail::make_context_list<
        typename HistorizedState::context_type,
        LeafState >::type history_context_list;
      typedef detail::constructor< 
        history_context_list, outermost_context_base_type > constructor_type;
      // 5.2.10.6 declares that reinterpret_casting a function pointer to a
      // different function pointer and back must yield the same value. The
      // following reinterpret_cast is the first half of such a sequence.
      store_history_impl(
        deepHistoryMap_, 
        history_key_type::make_history_key< HistorizedState >(),
        reinterpret_cast< void (*)() >( &constructor_type::construct ) );
    }

    template< class DefaultState >
    void construct_with_deep_history(
      const typename DefaultState::context_ptr_type & pContext )
    {
      construct_with_history_impl< DefaultState >(
        deepHistoryMap_, pContext );
    }

  private: // implementation
    //////////////////////////////////////////////////////////////////////////
    void initial_construct()
    {
      InitialState::initial_deep_construct(
        *polymorphic_downcast< MostDerived * >( this ) );
    }

    class initial_construct_function
    {
      public:
        //////////////////////////////////////////////////////////////////////
        initial_construct_function( state_machine & machine ) :
          machine_( machine )
        {
        }

        result operator()()
        {
          machine_.initial_construct();
          return detail::result_utility::make_result(
            detail::do_discard_event ); // there is nothing to be consumed
        }

      private:
        //////////////////////////////////////////////////////////////////////
        // avoids C4512 (assignment operator could not be generated)
        initial_construct_function & operator=(
          const initial_construct_function & );

        state_machine & machine_;
    };
    friend class initial_construct_function;

    class terminate_function
    {
      public:
        //////////////////////////////////////////////////////////////////////
        terminate_function( state_machine & machine ) : machine_( machine ) {}

        result operator()()
        {
          machine_.terminate_impl( true );
          return detail::result_utility::make_result(
            detail::do_discard_event ); // there is nothing to be consumed
        }

      private:
        //////////////////////////////////////////////////////////////////////
        // avoids C4512 (assignment operator could not be generated)
        terminate_function & operator=( const terminate_function & );

        state_machine & machine_;
    };
    friend class terminate_function;

    template< class ExceptionEvent >
    detail::reaction_result handle_exception_event(
      const ExceptionEvent & exceptionEvent,
      state_base_type * pCurrentState )
    {
      if ( terminated() )
      {
        // there is no state that could handle the exception -> bail out
        throw;
      }

      // If we are stable, an event handler has thrown.
      // Otherwise, either a state constructor, a transition action or an exit
      // function has thrown and the state machine is now in an invalid state.
      // This situation can be resolved by the exception event handler
      // function by orderly transiting to another state or terminating.
      // As a result of this, the machine must not be unstable when this
      // function is left.
      state_base_type * const pOutermostUnstableState =
        get_pointer( pOutermostUnstableState_ );
      state_base_type * const pHandlingState = pOutermostUnstableState == 0 ?
        pCurrentState : pOutermostUnstableState;

      BOOST_ASSERT( pHandlingState != 0 );
      terminator guard( *this, &exceptionEvent );
      // There is another scope guard up the call stack, which will terminate
      // the machine. So this guard only sets the triggering event.
      guard.dismiss();

      // Setting a member variable to a special value for the duration of a
      // call surely looks like a kludge (normally it should be a parameter of
      // the call). However, in this case it is unavoidable because the call
      // below could result in a call to user code where passing through an
      // additional bool parameter is not acceptable.
      performFullExit_ = false;
      const detail::reaction_result reactionResult = pHandlingState->react_impl(
        exceptionEvent, exceptionEvent.dynamic_type() );
      // If the above call throws then performFullExit_ will obviously not be
      // set back to true. In this case the termination triggered by the
      // scope guard further up in the call stack will take care of this.
      performFullExit_ = true;

      if ( ( reactionResult != detail::do_discard_event ) ||
        ( get_pointer( pOutermostUnstableState_ ) != 0 ) )
      {
        throw;
      }

      return detail::do_discard_event;
    }

    class exception_event_handler
    {
      public:
        //////////////////////////////////////////////////////////////////////
        exception_event_handler(
          state_machine & machine,
          state_base_type * pCurrentState = 0
        ) :
          machine_( machine ),
          pCurrentState_( pCurrentState )
        {
        }

        template< class ExceptionEvent >
        result operator()(
          const ExceptionEvent & exceptionEvent )
        {
          return detail::result_utility::make_result(
            machine_.handle_exception_event(
              exceptionEvent, pCurrentState_ ) );
        }

      private:
        //////////////////////////////////////////////////////////////////////
        // avoids C4512 (assignment operator could not be generated)
        exception_event_handler & operator=(
          const exception_event_handler & );

        state_machine & machine_;
        state_base_type * pCurrentState_;
    };
    friend class exception_event_handler;

    class terminator
    {
      public:
        //////////////////////////////////////////////////////////////////////
        terminator(
          state_machine & machine, const event_base * pNewTriggeringEvent ) :
          machine_( machine ),
          pOldTriggeringEvent_(machine_.pTriggeringEvent_),
          dismissed_( false )
        {
            machine_.pTriggeringEvent_ = pNewTriggeringEvent;
        }

        ~terminator()
        {
          if ( !dismissed_ ) { machine_.terminate_impl( false ); }
          machine_.pTriggeringEvent_ = pOldTriggeringEvent_;
        }

        void dismiss() { dismissed_ = true; }

      private:
        //////////////////////////////////////////////////////////////////////
        // avoids C4512 (assignment operator could not be generated)
        terminator & operator=( const terminator & );

        state_machine & machine_;
        const event_base_type * const pOldTriggeringEvent_;
        bool dismissed_;
    };
    friend class terminator;


    detail::reaction_result send_event( const event_base_type & evt )
    {
      terminator guard( *this, &evt );
      BOOST_ASSERT( get_pointer( pOutermostUnstableState_ ) == 0 );
      const typename rtti_policy_type::id_type eventType = evt.dynamic_type();
      detail::reaction_result reactionResult = detail::do_forward_event;
      
      for (
        typename state_list_type::iterator pState = currentStates_.begin();
        ( reactionResult == detail::do_forward_event ) &&
          ( pState != currentStatesEnd_ );
        ++pState )
      {
        // CAUTION: The following statement could modify our state list!
        // We must not continue iterating if the event was consumed
        reactionResult = detail::result_utility::get_result( translator_(
          detail::send_function<
            state_base_type, event_base_type, rtti_policy_type::id_type >(
              **pState, evt, eventType ),
          exception_event_handler( *this, get_pointer( *pState ) ) ) );
      }

      guard.dismiss();

      if ( reactionResult == detail::do_forward_event )
      {
        polymorphic_downcast< MostDerived * >( this )->unconsumed_event( evt );
      }

      return reactionResult;
    }


    void process_queued_events()
    {
      while ( !eventQueue_.empty() )
      {
        event_base_ptr_type pEvent = eventQueue_.front();
        eventQueue_.pop_front();

        if ( send_event( *pEvent ) == detail::do_defer_event )
        {
          deferredEventQueue_.push_back( pEvent );
        }
      }
    }


    void terminate_impl( bool performFullExit )
    {
      performFullExit_ = true;

      if ( !terminated() )
      {
        terminate_impl( *pOutermostState_, performFullExit );
      }

      eventQueue_.clear();
      deferredEventQueue_.clear();
      shallowHistoryMap_.clear();
      deepHistoryMap_.clear();
    }

    void terminate_impl( state_base_type & theState, bool performFullExit )
    {
      isInnermostCommonOuter_ = false;

      // If pOutermostUnstableState_ == 0, we know for sure that
      // currentStates_.size() > 0, otherwise theState couldn't be alive any
      // more
      if ( get_pointer( pOutermostUnstableState_ ) != 0 )
      {
        theState.remove_from_state_list(
          currentStatesEnd_, pOutermostUnstableState_, performFullExit );
      }
      // Optimization: We want to find out whether currentStates_ has size 1
      // and if yes use the optimized implementation below. Since
      // list<>::size() is implemented quite inefficiently in some std libs
      // it is best to just decrement the currentStatesEnd_ here and
      // increment it again, if the test failed.
      else if ( currentStates_.begin() == --currentStatesEnd_ )
      {
        // The machine is stable and there is exactly one innermost state.
        // The following optimization is only correct for a stable machine
        // without orthogonal regions.
        leaf_state_ptr_type & pState = *currentStatesEnd_;
        pState->exit_impl(
          pState, pOutermostUnstableState_, performFullExit );
      }
      else
      {
        BOOST_ASSERT( currentStates_.size() > 1 );
        // The machine is stable and there are multiple innermost states
        theState.remove_from_state_list(
          ++currentStatesEnd_, pOutermostUnstableState_, performFullExit );
      }
    }


    node_state_base_ptr_type add_impl(
      const leaf_state_ptr_type & pState,
      detail::leaf_state< allocator_type, rtti_policy_type > & )
    {
      if ( currentStatesEnd_ == currentStates_.end() )
      {
        pState->set_list_position( 
          currentStates_.insert( currentStatesEnd_, pState ) );
      }
      else
      {
        *currentStatesEnd_ = pState;
        pState->set_list_position( currentStatesEnd_ );
        ++currentStatesEnd_;
      }

      return 0;
    }

    node_state_base_ptr_type add_impl(
      const node_state_base_ptr_type & pState,
      state_base_type & )
    {
      return pState;
    }

    template< class State >
    static bool is_in_highest_orthogonal_region()
    {
      return mpl::equal_to<
        typename State::orthogonal_position,
        mpl::minus< 
          typename State::context_type::no_of_orthogonal_regions,
          mpl::integral_c< detail::orthogonal_position_type, 1 > >
      >::value;
    }


    typedef detail::history_key< rtti_policy_type > history_key_type;

    typedef std::map<
      history_key_type, void (*)(),
      std::less< history_key_type >,
      typename boost::detail::allocator::rebind_to<
        allocator_type, std::pair< const history_key_type, void (*)() >
      >::type
    > history_map_type;

    void store_history_impl(
      history_map_type & historyMap,
      const history_key_type & historyId,
      void (*pConstructFunction)() )
    {
      historyMap[ historyId ] = pConstructFunction;
    }

    template< class DefaultState >
    void construct_with_history_impl(
      history_map_type & historyMap,
      const typename DefaultState::context_ptr_type & pContext )
    {
      typename history_map_type::iterator pFoundSlot = historyMap.find(
        history_key_type::make_history_key< DefaultState >() );
      
      if ( ( pFoundSlot == historyMap.end() ) || ( pFoundSlot->second == 0 ) )
      {
        // We have never entered this state before or history was cleared
        DefaultState::deep_construct(
          pContext, *polymorphic_downcast< MostDerived * >( this ) );
      }
      else
      {
        typedef void construct_function(
          const typename DefaultState::context_ptr_type &,
          typename DefaultState::outermost_context_base_type & );
        // 5.2.10.6 declares that reinterpret_casting a function pointer to a
        // different function pointer and back must yield the same value. The
        // following reinterpret_cast is the second half of such a sequence.
        construct_function * const pConstructFunction =
          reinterpret_cast< construct_function * >( pFoundSlot->second );
        (*pConstructFunction)(
          pContext, *polymorphic_downcast< MostDerived * >( this ) );
      }
    }

    typedef std::list<
      event_base_ptr_type,
      typename boost::detail::allocator::rebind_to<
        allocator_type, event_base_ptr_type >::type
    > event_queue_type;

    typedef std::map<
      const state_base_type *, event_queue_type,
      std::less< const state_base_type * >,
      typename boost::detail::allocator::rebind_to<
        allocator_type,
        std::pair< const state_base_type * const, event_queue_type >
      >::type
    > deferred_map_type;


    event_queue_type eventQueue_;
    event_queue_type deferredEventQueue_;
    state_list_type currentStates_;
    typename state_list_type::iterator currentStatesEnd_;
    state_base_type * pOutermostState_;
    bool isInnermostCommonOuter_;
    node_state_base_ptr_type pOutermostUnstableState_;
    ExceptionTranslator translator_;
    bool performFullExit_;
    history_map_type shallowHistoryMap_;
    history_map_type deepHistoryMap_;
    const event_base_type * pTriggeringEvent_;
};



} // namespace statechart
} // namespace boost



#endif
