/**
 * @file
 * @ingroup <<<GROUP>>>
 * @brief   <<<BRIEF>>>
 *
 *          This code is Autogenerated from '<<<PYIFGENNAME>>>' with the MIT License.
 *          As such, please only hand-code within 'USER' tags.
 *
 * @author  <<<AUTHOR>>>
 */
/// {{{USER_PCH}}}
/// {{{USER_PCH}}}

#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_VECTOR_SIZE 50
#include <boost/mpl/vector.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

#include "I<<<STATEMACHINENAME>>>Controller.h"
#include "<<<STATEMACHINENAME>>>StateMachine.h"

#include <typeinfo>

#include "MultiThreading.h"

/// {{{USER_HEADER_INCLUDES}}}
/// {{{USER_HEADER_INCLUDES}}}

/// {{{USER_FORWARD_DECLARATIONS}}}
/// {{{USER_FORWARD_DECLARATIONS}}}

namespace <<<NAMESPACE>>>
{
    /// {{{USER_LOCALS}}}
    /// {{{USER_LOCALS}}}

    ////////////////////////////////////////////////////////////
    // C<<<STATEMACHINENAME>>>StateMachine
    ////////////////////////////////////////////////////////////

    namespace msm = boost::msm;
    namespace msmf = boost::msm::front;

    using namespace <<<STATEMACHINENAME>>>Events;

    /// @{ Flags
    <<<PER_STATE_BEGIN>>>
    struct FlagIs<<<STATENAME>>>{};
    <<<PER_STATE_END>>>
    /// @}

    /// @{ Guards
    <<<PER_GUARD_BEGIN>>>
    struct <<<GUARDNAME>>>
    {
        template <class Event, class Fsm, class SourceState, class TargetState>
        bool operator() (Event const& ev, Fsm& fsm, SourceState& s, TargetState& t)
        {
            if (auto& controller = fsm.m_controller.lock())
                return controller-><<<GUARDNAME>>>();
            return false;
        }
    };
    <<<PER_GUARD_END>>>
    /// @}

    /// @{ States
    <<<PER_STATE_BEGIN>>>
    struct <<<STATENAME>>>:msmf::state<> {
        typedef boost::mpl::vector1<FlagIs<<<STATENAME>>>> flag_list;

        /// {{{USER_<<<STATENAME>>>_DEFERRED_EVENTS}}}
        /// {{{USER_<<<STATENAME>>>_DEFERRED_EVENTS}}}

        template <class Event, class Fsm>
        void on_entry(Event const& ev, Fsm& fsm)
        {
            if (auto& controller = fsm.m_controller.lock())
                controller-><<<STATENAME>>>_on_entry();
        }
        template <class Event, class Fsm>
        void on_exit(Event const& ev, Fsm& fsm)
        {
            if (auto& controller = fsm.m_controller.lock())
                controller-><<<STATENAME>>>_on_exit();
        }
    };
    <<<PER_STATE_END>>>
    /// @{ Actions
    <<<PER_ACTION_BEGIN>>>
    struct <<<ACTIONNAME>>>
    {
        template <class Event, class Fsm, class SourceState, class TargetState>
        void operator() (Event const& data, Fsm& fsm, SourceState&, TargetState&) const
        {
            if (auto& controller = fsm.m_controller.lock())
                controller-><<<ACTIONNAME>>>(data);
        }
    };
    <<<PER_ACTION_END>>>
    /// @}

    CGEN_DECL_CLASS_PTR(C<<<STATEMACHINENAME>>>StateMachine);
    class /*<<<DLL_EXPORT>>>*/ C<<<STATEMACHINENAME>>>StateMachine : public msmf::state_machine_def<C<<<STATEMACHINENAME>>>StateMachine>
    {
    public:

        // when a transition is about to be taken, we already update our currently active state(s)
        typedef msm::active_state_switch_before_transition active_state_switch_policy;

        struct Termination:msmf::terminate_state<>
        {
            template <class Event, class Fsm>
            void on_entry(Event const& ev, Fsm& fsm)
            {
                std::cout << "<<<STATEMACHINENAME>>> State Machine : Unhandled : Terminate State entered." << std::endl;
            }
            template <class Event, class Fsm>
            void on_exit(Event const& ev, Fsm& fsm)
            {
                std::cout << "<<<STATEMACHINENAME>>> State Machine : Unhandled : Terminate State exited." << std::endl;
            }
        };
        /// }@

        typedef <<<STATE_0>>> initial_state;

        /// Transition table
        struct transition_table:boost::mpl::vector<
            <<<TTT_BOOST_MSM>>>
        > {};

        typedef msm::back::state_machine<C<<<STATEMACHINENAME>>>StateMachine> BackEnd;
        typedef boost::shared_ptr<BackEnd> BackEnd_ptr;

        C<<<STATEMACHINENAME>>>StateMachine(I<<<STATEMACHINENAME>>>Controller_ptr controller):m_controller(controller){};
        ~C<<<STATEMACHINENAME>>>StateMachine(){};

        /// {{{USER_SM_PUBLIC_MEMBERS}}}
        /// {{{USER_SM_PUBLIC_MEMBERS}}}

        I<<<STATEMACHINENAME>>>Controller_wptr m_controller;

    protected:
        // Overridden no-transition handler.
        template <class FSM,class Event>
        void no_transition(Event const& ev,FSM& sm, int state)
        {
            std::stringstream ss;
            ss << "<<<STATEMACHINENAME>>> State Machine : NO transition (" << typeid(ev).name() << " in state " << state << ")";
#ifdef _DEBUG
            std::cout << ss.str() << std::endl;
#endif
            /// {{{USER_SM_NO_TRANSITION}}}
            /// {{{USER_SM_NO_TRANSITION}}}
        }
        // Overridden exception handler.
        template <class FSM,class Event>
        void exception_caught (Event const& ev,FSM& fsm,std::exception& e)
        {
            std::stringstream ss;
            ss << "<<<STATEMACHINENAME>>> State Machine : Exception caught : " << e.what() << " : (" << typeid(ev).name() << ")";
            std::cout << ss.str() << std::endl;
            /// {{{USER_SM_EXCEPTION_HANDLER}}}
            /// {{{USER_SM_EXCEPTION_HANDLER}}}
        }
    };

    ////////////////////////////////////////////////////////////
    // C<<<STATEMACHINENAME>>>StateMachineImpl
    ////////////////////////////////////////////////////////////

    // Forward declare base event class
    namespace <<<STATEMACHINENAME>>>Events
    {
        CGEN_DECL_STRUCT_PTR(EventData);
    }

    CGEN_DECL_CLASS_PTR(I<<<STATEMACHINENAME>>>Controller);
    CGEN_DECL_CLASS_PTR(C<<<STATEMACHINENAME>>>StateMachineImpl);
    class /*<<<DLL_EXPORT>>>*/ C<<<STATEMACHINENAME>>>StateMachineImpl
        : public I<<<STATEMACHINENAME>>>StateMachine
         ,public MultiThreading::IQueueThread<EventData>
    {
    public:
        static C<<<STATEMACHINENAME>>>StateMachineImpl_ptr Create(const I<<<STATEMACHINENAME>>>Controller_ptr& controller, const bool& run_ctrlr_async = false)
        {
            C<<<STATEMACHINENAME>>>StateMachineImpl_ptr result(new C<<<STATEMACHINENAME>>>StateMachineImpl());
            result->m_backend.reset(new C<<<STATEMACHINENAME>>>StateMachine::BackEnd(controller));
            result->m_is_asynchronous = run_ctrlr_async;
            result->m_controller = controller;
            return result;
        }

        virtual ~C<<<STATEMACHINENAME>>>StateMachineImpl(){};

        // Flag check
        <<<PER_STATE_BEGIN>>>
        virtual bool Is<<<STATENAME>>>() const override
        {
            return m_backend->is_flag_active<FlagIs<<<STATENAME>>>>();
        }
        <<<PER_STATE_END>>>

        // Event triggering
        <<<PER_EVENT_BEGIN>>>
        virtual void Trigger<<<EVENTNAME>>>(<<<SIGNATURE>>>) override
        {
            <<<EVENTNAME>>>_ptr data(new <<<EVENTNAME>>>());
            <<<MEMBERSINSTANTIATE>>>
            if(m_is_asynchronous)
                Add(data);
            else
                Process(data);
        }
        <<<PER_EVENT_END>>>

        /// {{{USER_SMIMPL_PUBLIC_MEMBERS}}}
        /// {{{USER_SMIMPL_PUBLIC_MEMBERS}}}

        // For threaded SM's.
        virtual void Interrupt() override
        {
            MultiThreading::IQueueThread<EventData>::Interrupt();
        }
        virtual bool IsThisThread(const boost::thread::id& thread_id) override
        {
            return MultiThreading::IQueueThread<EventData>::IsThisThread(thread_id);
        }

    protected:
        C<<<STATEMACHINENAME>>>StateMachineImpl()
            :MultiThreading::IQueueThread<EventData>(-1, "<<<STATEMACHINENAME>>> SM")
        {
        }

        void Process(EventData_ptr next_event)
        {
            /// {{{USER_SMIMPL_EVENT_PROCESS}}}
            /// {{{USER_SMIMPL_EVENT_PROCESS}}}
            <<<PER_EVENT_BEGIN>>>
            if (auto& data = boost::dynamic_pointer_cast<<<<EVENTNAME>>>>(next_event)){
                m_backend->process_event(*data.get());
                return;
            }
            <<<PER_EVENT_END>>>
        }

        C<<<STATEMACHINENAME>>>StateMachine::BackEnd_ptr m_backend;

        /// {{{USER_SMIMPL_PROTECTED_MEMBERS}}}
        /// {{{USER_SMIMPL_PROTECTED_MEMBERS}}}
    };

    ////////////////////////////////////////////////////////////
    // I<<<STATEMACHINENAME>>>StateMachine
    ////////////////////////////////////////////////////////////
    I<<<STATEMACHINENAME>>>StateMachine_ptr I<<<STATEMACHINENAME>>>StateMachine::Create(const I<<<STATEMACHINENAME>>>Controller_ptr& controller, const bool& run_ctrlr_async)
    {
        I<<<STATEMACHINENAME>>>StateMachine_ptr result = C<<<STATEMACHINENAME>>>StateMachineImpl::Create(controller, run_ctrlr_async);
        return result;
    }
}