#pragma once
#include "../Behavior.h"

/**
 * @brief Utility class for a state which wraps another behavior. Inheritors must supply a createSubBehavior() method that returns a Behavior *. 
 * WrappedState will call zombifyOnTerminate() on said behavior, and then start it.
 * When the wrapped behavior terminates, the state will then transition to a DestinationState.
 */
template<class DerivedBehavior, class OriginState, class TransitionAction, class DestinationState>
class WrapperState : public BehaviorStateT<DerivedBehavior, OriginState>
{
public:
  WrapperState(DerivedBehavior& behavior, TransitionAction action, DestinationState &destinationState) 
    : BehaviorStateT(behavior),
      m_subBehavior(NULL),
      m_onSubBehaviorTerminated(*static_cast<OriginState *>(this)), 
      m_transitions(m_transitionToDestination), 
      m_transitionToDestination(*static_cast<OriginState *>(this), NoCondition(), action, destinationState) {}
  
  void onEnter()
  {
    m_subBehavior = static_cast<OriginState *>(this)->createSubBehavior();
    assert(m_subBehavior != NULL);

    m_subBehavior->zombifyOnTerminate();

    m_subscriberId = m_subBehavior->getTerminateEvent().subscribe(&m_onSubBehaviorTerminated, m_context.getUnit());

    m_subBehavior->start();
  }
  void onExit()
  {
    if(m_subBehavior != NULL)
    {
      m_subBehavior->getTerminateEvent().unsubscribe(m_subscriberId);
      m_subBehavior->externalTerminate(); 
      m_subBehavior = NULL;
    }
  }
  void onSubBehaviorTerminated()
  {
    m_transitionToDestination.testTransition(boost::make_tuple());
  }

  typedef boost::tuple<
        > Events;
	Events m_events;
  
	typedef boost::tuple<
        Transition<OriginState, NoCondition, TransitionAction, DestinationState>&
	  > Transitions;
	Transitions m_transitions;

protected:

  void onSubBehaviorTerminatedT(void*)
  {
    static_cast<OriginState*>(this)->onSubBehaviorTerminated();
  }

	Transition<OriginState, NoCondition, TransitionAction, DestinationState> m_transitionToDestination;
  Behavior* m_subBehavior;
  typename DerivedBehavior::OnTerminate::SubscriberID m_subscriberId;
  EVENT_HANDLER(OriginState, onSubBehaviorTerminatedT) m_onSubBehaviorTerminated;
};