/*
Copyright (C) 2026 ZFSM Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/* 
The ZFSM homepage mirrors the source code and has all the documentation. It is located at 

    https://mbaldamus.com/zfsm.
    
The ZFSM source code is also available at

    https://codeberg.com/zfsm.
*/

#if defined(ZFSM_ERRORS_ASSUME_NONE) && defined(ZFSM_ERRORS_ASSERT)
static_assert(false, "zfsm: ZFSM_ERRORS_ASSUME_NONE and ZFSM_ERRORS_ASSERT defined at the same time");
#endif

#ifndef INCLUDED_ZFSM_HPP
#define INCLUDED_ZFSM_HPP

#if defined(ZFSM_ERRORS_ASSERT)

#include <cassert>

#elif !defined(ZFSM_ERRORS_ASSUME_NONE)

#include <cstdio>
#include <exception>

#endif

#include <functional>
#include <type_traits>
#include <utility>

#if defined(ZFSM_ERRORS_ASSUME_NONE)
#define ZFSM_ERROR(_, _) ((void) 0)
#elif defined(ZFSM_ERRORS_ASSERT)
#define ZFSM_ERROR(condition, _) assert (!(condition))
#else
#define ZFSM_ERROR(condition, text) do { if (condition) { throw Exception(text); } } while (false)
#endif

namespace zfsm
{

namespace internal
{ 
    enum class ArrowType { REACT, CONTINUE, PREEMPT, IMMEDIATE_PREEMPT };
    enum class StateActionType { ON_ENTRY, ON_EXIT, DO_FRONT, DO_BACK };

    class ChainedSignal;
    class InjectOnEntry;
    class InjectOnExit;
    class InjectDoFront;
    class InjectDoBack;
    template <class Ctxt> class SubState;
    template <class Elem> class Context; 
    class RegionMixee;
    template <bool> class SignalMixIn;
    template <StateActionType, bool> class StateActionMixIn;
    template <ArrowType, bool> class ArrowMixIn;
    class AttachedArrow;
    class TopMixee;

} // namespace internal

#if !defined(ZFSM_ERRORS_ASSUME_NONE) && !defined(ZFSM_ERRORS_ASSERT) 
class Exception : public std::exception {
    friend class internal::ChainedSignal;
    template <typename T> friend class Carry;
    template <class Elem> friend class internal::Context; 
    friend class internal::InjectOnEntry;
    friend class internal::InjectOnExit;
    friend class internal::InjectDoFront;
    friend class internal::InjectDoBack;
    template <class Ctxt> friend class internal::SubState;
    friend class internal::RegionMixee;
    friend class internal::TopMixee;
    template <bool> friend class internal::SignalMixIn;
    template <internal::StateActionType, bool> friend class internal::StateActionMixIn;
    template <internal::ArrowType, bool> friend class internal::ArrowMixIn;
    friend class internal::AttachedArrow;

    Exception() = delete;
    Exception(Exception const&) noexcept = default;
    Exception(Exception&&) noexcept = default;
    Exception& operator=(Exception const&) = delete;
    Exception& operator=(Exception&&) = delete;

    static int constexpr BUF_CAPACITY = 80;
    char msg[BUF_CAPACITY];

    Exception(char const *text) noexcept { std::snprintf(msg, BUF_CAPACITY, "zfsm exception: %s", text); }

public:
    char const * what() const noexcept final { return msg; }
};
#endif

namespace internal
{
    template <class CRTP>
    class Chained {
        template <ArrowType, bool> friend class ArrowMixIn;
        template <StateActionType, bool> friend class StateActionMixIn;
        template <class Elem> friend class Context;
        template <class Ctxt> friend class SubState;
        template <class Ctxt> friend class HierarchicalState;

    public:
    
        Chained() = default;
        Chained(Chained const&) = delete;
        Chained(Chained&&) = delete;
        Chained& operator=(Chained const&) = delete;
        Chained& operator=(Chained&&) = delete;

        ~Chained() = default;

    private:
        CRTP *reverseElemChain() { 
            CRTP *prev = nullptr; 
            CRTP *cur = static_cast<CRTP *>(this); 
            for (;;) { CRTP *const nxt = cur->m_nxt; cur->m_nxt = prev; prev = cur; if (nxt == nullptr) { break; } cur = nxt; } 
            return prev; 
        }
    };

    class Scope;

} // namespace internal

template <typename T = void, class SFINAE = void> class Signal;

namespace internal
{
    class InitMixee;
    class FinalMixee;
    class BasicMixee;
    class SuperMixee;
    class RegionMixee;
    class CompositeMixee;
    class TopMixee;

    class ChainedSignal : Chained<ChainedSignal> {
        template <typename T, class SFINAE> friend class zfsm::Signal;
        template <bool> friend class SignalMixIn;

    public:
        class Raised { friend class ChainedSignal; };

        ChainedSignal() = delete;
        ChainedSignal(ChainedSignal const&) = delete;
        ChainedSignal(ChainedSignal&&) = delete;
        ChainedSignal& operator=(ChainedSignal const&) = delete;
        ChainedSignal& operator=(ChainedSignal&&) = delete;

        ~ChainedSignal() = default;

    private:
        bool m_isRaised = false;

        ChainedSignal *m_nxt = nullptr;
        void chain(ChainedSignal *nxtElem) { m_nxt = nxtElem; }

        void reset() { m_isRaised = false; }

        Raised raise() { m_isRaised = true; return Raised(); }

        ChainedSignal(internal::Scope *scope);

    public:
        bool operator()() const { return m_isRaised; }
    };

} // namespace internal

template <typename T>
class Signal<T, typename std::enable_if<std::is_void<T>::value>::type> : public internal::ChainedSignal {

public:
    Signal(internal::Scope *scope) : internal::ChainedSignal(scope) {} 

    ChainedSignal::Raised raise() { return internal::ChainedSignal::raise(); }
};

namespace internal
{
    template <typename T, class OnLeave, class SFINAE> class ActiveArrow;
    template <class Mark, class Inject, typename T, class SFINAE> class StateAction;
}

template <typename T>
class Carry {
    template <typename _T, class OnLeave, class SFINAE> friend class internal::ActiveArrow;
    template <class Mark, class Inject, typename _T, class SFINAE> friend class internal::StateAction;

public:
    Carry() = delete;
    Carry(Carry const&) = delete;
    Carry& operator=(Carry&& other) = default;
    Carry& operator=(Carry const&) = delete;

private:
    bool m_isFiring;
    typename std::aligned_storage<sizeof(T), alignof(T)>::type m_mem;

    T* ptr() { return reinterpret_cast<T*>(&m_mem); }
    T const* ptr() const { return reinterpret_cast<T const*>(&m_mem); }

    T&& takeValue() { return std::move(*ptr()); }

    void reset() noexcept { if (m_isFiring) { ptr()->~T(); } m_isFiring = false; }

public:
    Carry(bool isFiring) : m_isFiring(isFiring) { ZFSM_ERROR(m_isFiring, "missing carry value"); }
    Carry(bool isFiring, T const& value) : m_isFiring(isFiring) { if (m_isFiring) { new (&m_mem) T(value); } }
    Carry(bool isFiring, T&& value) : m_isFiring(isFiring) { if (m_isFiring) {new (&m_mem) T(std::move(value)); } }
    Carry(Carry&& other) noexcept(std::is_nothrow_move_constructible<T>::value) : m_isFiring(other.m_isFiring) {
        if (m_isFiring) { new (&m_mem) T(std::move(*other.ptr())); other.reset(); }
    }

    ~Carry() { reset(); }
};

template <typename T>
class Signal<T, typename std::enable_if<!std::is_void<T>::value>::type> : public internal::ChainedSignal {

    T m_value;

public:
    Signal() = delete;
    Signal(Signal const&) = delete;
    Signal(Signal&&) = delete;
    Signal& operator=(Signal const&) = delete;
    Signal& operator=(Signal&&) = delete;

    Signal(internal::Scope *scope) : internal::ChainedSignal(scope) {}

    ~Signal() = default;

    ChainedSignal::Raised raise(T const &value) { m_value = value; return internal::ChainedSignal::raise(); }
    ChainedSignal::Raised raise(T &&value) { m_value = std::move(value); return internal::ChainedSignal::raise(); }

    T const &getValue() const { return m_value; }
    T&& takeValue() { return std::move(m_value); }
};

namespace internal
{
    class ChainedAction : public Chained<ChainedAction> {
        friend class Chained<ChainedAction>;
        template <StateActionType, bool> friend class StateActionMixIn;

        ChainedAction *m_nxt = nullptr;
        void chain(ChainedAction *nxtElem) { m_nxt = nxtElem; }

        virtual void chainedAction_evalExec() const = 0;
    };

    class ChainedArrow : public Chained<ChainedArrow> {
        friend class Chained<ChainedArrow>;
        template <ArrowType, bool> friend class ArrowMixIn;
        friend class InjectContinue;

        ChainedArrow *m_nxt = nullptr;
        void chain(ChainedArrow *nxtElem) { m_nxt = nxtElem; }

        virtual bool chainedArrow_evalExec(bool immediatePreempt = false) const = 0;
    };

    class MarkOnEntry : public ChainedAction {};
    class MarkOnExit : public ChainedAction {};
    class MarkDoFront : public ChainedAction {};
    class MarkDoBack : public ChainedAction {};


    class Scope {
        friend class Exception;
        template <class Elem> friend class Context;
        friend class ChainedSignal;
        friend class InjectOnEntry;
        friend class InjectOnExit;
        friend class InjectDoFront;
        friend class InjectDoBack;
        friend class Sequential;
        friend class SuperMixee;
        friend class RegionMixee;
        friend class CompositeMixee;
        friend class TopMixee;
        friend class Nextifier;

        virtual void injectSignal(ChainedSignal *signal) = 0;
        virtual void asScope_nextify() const = 0;

        virtual void injectEntry(MarkOnEntry *onEntry) = 0;
        virtual void fuseEntries() = 0;
        virtual void onEntry() const = 0;

        virtual void injectExit(MarkOnExit *onExit) = 0;
        virtual void fuseExits() = 0;
        virtual void onExit() const = 0;

        virtual void injectDoFront(MarkDoFront *doFront) = 0;
        virtual void fuseDoFronts() = 0;
        virtual void doFront() const = 0;

        virtual void injectDoBack(MarkDoBack *doBack) = 0;
        virtual void fuseDoBacks() = 0;
        virtual void doBack() const = 0;

        void fuse() { fuseEntries(); fuseExits(); fuseDoFronts(); fuseDoBacks(); }
    };

    inline ChainedSignal::ChainedSignal(Scope *scope) : m_isRaised(false) { ZFSM_ERROR(scope == nullptr, "scope pointer on signal is null"); scope->injectSignal(this); }

    template <class Ctxt>
    class SubState : Chained<SubState<Ctxt>> {
        template <class CRTP> friend class Chained;
        template <class Elem> friend class Context;
        friend class Sequential;
        template <class _Ctxt> friend class HierarchicalState;
        friend class Ground;
        friend class SuperMixee;
        friend class RegionMixee;
        friend class CompositeMixee;
        friend class AttachedArrow;
        friend class OnLeaveByMove;
        friend class OnLeaveByAbort;
        friend class OnLeaveBySuspend;
        template <class T, class OnLeave, class SFINAE> friend class ActiveArrow;
        template <typename T, class OnLeave, class Inject, class SFINAE> friend class Move;
        template <class T = void, class OnLeave = void, class SFINAE = void> class ImmediatePreempt;

    public:
        SubState() = delete;
        SubState(SubState const&) = delete;
        SubState(SubState&&) = delete;
        SubState& operator=(SubState const&) = delete;
        SubState& operator=(SubState&&) = delete;

        ~SubState() = default;

    private:
        Ctxt *const m_ctxt;

        SubState *m_nxt = nullptr;
        void injectNxtElem(SubState *nxtElem) { m_nxt = nxtElem; }

        virtual void injectReact(ChainedArrow *react) = 0;
        virtual void fuseReacts() = 0;
        virtual bool react() = 0;

        virtual void asContextElem_fuse() { fuseReacts(); }

        virtual bool asSubState_isInit() const { return false; }

        virtual bool asSubState_isFinal() const { return false; }

        virtual bool asSubState_react() { return react(); }

        virtual bool asSubState_continue() { ZFSM_ERROR(true, "internal error in asSubState_continue()"); }

        virtual void asSubState_nextify() {}

        virtual void asSource_exit() {}

        virtual void asTarget_entry() {}

        virtual void asSubState_abort() { ZFSM_ERROR(true, "internal error asSubState_abort()"); }

        virtual void asSubState_suspend() { ZFSM_ERROR(true, "internal error asSubState_suspend()"); } 

        virtual void asSubState_reset() {}

        virtual void asSubState_deepReset() {}

    protected:
        SubState(Ctxt *ctxt) : m_ctxt(ctxt) { ZFSM_ERROR(ctxt == nullptr, "context pointer in sub-state is null"); ctxt->injectElem(this); }
    };

    template <class Elem>
    class Context : public Scope {
        friend class Sequential;
        template <class Context> friend class SubState;
        friend class CompositeMixee;

        Elem *m_fstElem = nullptr;
        void injectElem(Elem *elem) { elem->injectNxtElem(m_fstElem); m_fstElem = elem; }

        virtual void asContext_fuse() {
            Scope::fuse();
            ZFSM_ERROR(m_fstElem == nullptr, "missing context element(s)");
            m_fstElem = m_fstElem->reverseElemChain();
            { auto elem = m_fstElem; do { elem->asContextElem_fuse(); elem = elem->m_nxt; } while (elem != nullptr); }
        }
    };

    class Sequential : public Context<SubState<Sequential>> {
        friend class SuperMixee;
        friend class RegionMixee;
        friend class CompositeMixee;
        template <class T, class OnLeave, class SFINAE> friend class ActiveArrow;
        friend class TopMixee;

    public:
        Sequential() = delete;
        Sequential(Sequential const&) = delete;
        Sequential(Sequential&&) = delete;
        Sequential& operator=(Sequential const&) = delete;
        Sequential& operator=(Sequential&&) = delete;

        ~Sequential() = default;

    private:
        InitMixee &m_init;
        SubState<Sequential> *m_current;

        void updateCurrent(SubState<Sequential> *newCurrent) { m_current = newCurrent; }

        void asContext_fuse() final;

        bool asSequential_isFinal() const { return m_current->asSubState_isFinal(); }

        void asSequential_exit();

        void asSequential_entry() { if (m_current->asSubState_isInit()) { onEntry(); asSequential_continue(); } }

        bool asSequential_coreReact() {
            bool const hasReacted = m_current->asSubState_react();
            if (hasReacted) { asSequential_continue(); }
            return hasReacted;
        }

        bool asSequential_react() {
            if (asSequential_isFinal()) { return false; }
            doFront();
            bool const hasReacted = asSequential_coreReact();
            doBack();
            return hasReacted;
        }

        void asSequential_continue() { while (!m_current->asSubState_isFinal()) { if (!m_current->asSubState_continue()) { return; } } }

        void asSequential_reset();

        void asSequential_deepReset();

        void asSequential_suspend() { auto sequential = m_fstElem; do { sequential->asSubState_reset(); sequential = sequential->m_nxt; } while (sequential != nullptr); }

    protected:
        Sequential(InitMixee &init);
    };

    class Continueable {
        friend class Ground;
        template <class Ctxt> friend class HierarchicalState;

        virtual void injectContinue(ChainedArrow *_continue) = 0;
        virtual void fuseContinues()  = 0;
        virtual bool _continue() = 0;
    };

    class Ground : public SubState<Sequential>, public Continueable {

        void asContextElem_fuse() final { SubState<Sequential>::asContextElem_fuse(); fuseContinues(); }
        bool asSubState_continue() final { return this->_continue(); }

    protected:
        Ground(internal::Sequential *ctxt) : SubState<Sequential>(ctxt) {}
    };

    class InitMixee : public internal::Ground {

        bool asSubState_isInit() const final { return true; }

    public:
        InitMixee(internal::Sequential *ctxt) : internal::Ground(ctxt) {}
    };

    class FinalMixee : public internal::SubState<internal::Sequential> {

        bool asSubState_isFinal() const final { return true; }

    public:
        FinalMixee(internal::Sequential *ctxt) : internal::SubState<internal::Sequential>(ctxt) {}
    };

    class BasicMixee : public internal::Ground {

    public:
        BasicMixee(internal::Sequential* ctxt) : internal::Ground(ctxt) {}
    };

    inline Sequential::Sequential(InitMixee &init) : m_init(init) {}
    
    inline void Sequential::asContext_fuse() {
        m_current = &m_init;
        Context<SubState<Sequential>>::asContext_fuse();
    }

    inline void Sequential::asSequential_exit() {
        onExit();
        m_current = &m_init;
    }

    inline void Sequential::asSequential_reset() {
        if (!m_current->asSubState_isInit()) {
            { SubState<Sequential> *subState = m_fstElem; do { subState->asSubState_deepReset(); subState = subState->m_nxt; } while (subState != nullptr); }
            onExit();
            m_current = &m_init;
        }
    }

    inline void Sequential::asSequential_deepReset() {
        if (!m_current->asSubState_isInit()) {
            { SubState<Sequential> *subState = m_fstElem; do { subState->asSubState_deepReset(); subState = subState->m_nxt; } while (subState != nullptr); }
            onExit();
            asScope_nextify();
            m_current = &m_init;
        }
    }

    template <class Ctxt>
    class HierarchicalState : public SubState<Ctxt>, public Continueable {
        friend class SuperMixee;
        friend class CompositeMixee;

    public:
        HierarchicalState() = delete;
        HierarchicalState(HierarchicalState const&) = delete;
        HierarchicalState(HierarchicalState&&) = delete;
        HierarchicalState& operator=(HierarchicalState const&) = delete;
        HierarchicalState& operator=(HierarchicalState&&) = delete;

        ~HierarchicalState() = default;

    private:
        virtual void injectImmediatePreempt(ChainedArrow *immediatePreempt) = 0;
        virtual void fuseImmediatePreempts() = 0;
        virtual bool immediatePreempt() = 0;

        virtual void injectPreempt(ChainedArrow *preempt) = 0;
        virtual void fusePreempts() = 0;
        virtual bool preempt() = 0;

        void asContextElem_fuse() override {
            SubState<Ctxt>::asContextElem_fuse();
            fuseContinues();
            fuseImmediatePreempts();
            fusePreempts();
        }

        bool asSubState_continue() final { return _continue(); }

        bool asHierarchicalState_immediatePreempt() { return immediatePreempt(); }

        bool asHierarchicalState_preempt() { return preempt(); }

    protected:
        HierarchicalState(Ctxt *ctxt) : SubState<Ctxt>(ctxt) {}
    };

    class Nextifier {
        friend class SuperMixee;
        friend class CompositeMixee;

    public:
        Nextifier() = delete;
        Nextifier(Nextifier const&) = delete;
        Nextifier(Nextifier&&) = delete;
        Nextifier& operator=(Nextifier const&) = delete;
        Nextifier& operator=(Nextifier&&) = delete;

    private:
        Scope *ctxt;
        Nextifier(Scope*_ctxt) : ctxt(_ctxt) {}
        ~Nextifier() { ctxt->asScope_nextify(); }
    };

    class SuperMixee : public internal::Sequential, public internal::HierarchicalState<internal::Sequential> {
        friend class Nextifier;

    public:
        SuperMixee() = delete;
        SuperMixee(SuperMixee const&) = delete;
        SuperMixee(SuperMixee&&) = delete;
        SuperMixee& operator=(SuperMixee const&) = delete;
        SuperMixee& operator=(SuperMixee&&) = delete;

        ~SuperMixee() = default;

    private:
        void asContextElem_fuse() final { internal::HierarchicalState<internal::Sequential>::asContextElem_fuse(); asContext_fuse(); }

        bool asSubState_react() final {
            if (asSequential_isFinal()) { return internal::SubState<internal::Sequential>::asSubState_react(); }

            internal::Nextifier nextify{this};

            if (asHierarchicalState_immediatePreempt()) { return true; }

            bool const hasReacted = asSequential_react();
            
            bool const hasPreempted = [&]{ if (asSequential_isFinal()) { return false; } else { return asHierarchicalState_preempt(); } }();

            return hasReacted || hasPreempted;
        }

        void asSubState_nextify() final { asScope_nextify(); }

        void asSource_exit() final { asSequential_exit(); }

        void asTarget_entry() final { asSequential_entry(); }

        void asSubState_abort() final { asSubState_reset(); }

        void asSubState_suspend() final { asSequential_suspend(); }

        void asSubState_reset() final { asSequential_reset(); }

        void asSubState_deepReset() final { asSequential_deepReset(); }

    public:
        SuperMixee(internal::Sequential *ctxt, InitMixee &init) : internal::Sequential(init), internal::HierarchicalState<internal::Sequential>(ctxt) {}
    };

    class CompositeMixee;

    class RegionMixee : public internal::Sequential, public internal::Chained<RegionMixee> {
        template <class CRTP> friend class internal::Chained;
        template <class Elem> friend class internal::Context;
        friend class CompositeMixee;

    public:
        RegionMixee() = delete;
        RegionMixee(RegionMixee const&) = delete;
        RegionMixee(RegionMixee&&) = delete;
        RegionMixee& operator=(RegionMixee const&) = delete;
        RegionMixee& operator=(RegionMixee&&) = delete;

        ~RegionMixee() = default;

    private:
        CompositeMixee *const m_ctxt;

        RegionMixee *m_nxt = nullptr;
        void injectNxtElem(RegionMixee *nxtElem) { m_nxt = nxtElem; }

        void asContextElem_fuse() { asContext_fuse(); }

    public:
        RegionMixee(CompositeMixee *ctxt, InitMixee &init);
    };

    class CompositeMixee : public internal::Context<RegionMixee>, public internal::HierarchicalState<internal::Sequential> {
        friend class RegionMixee;

    public:
        CompositeMixee() = delete;
        CompositeMixee(CompositeMixee const&) = delete;
        CompositeMixee(CompositeMixee&&) = delete;
        CompositeMixee& operator=(CompositeMixee const&) = delete;
        CompositeMixee& operator=(CompositeMixee&&) = delete;

        ~CompositeMixee() = default;

    private:
        void injectRegion(RegionMixee *region) { Context<RegionMixee>::injectElem(region); }

        void asContextElem_fuse() final { internal::HierarchicalState<internal::Sequential>::asContextElem_fuse(); asContext_fuse(); }

        bool asSubState_react() final {
            auto const isFinal = [&]{
                bool isFinal = true;
                { auto const *region = m_fstElem; do { isFinal &= region->asSequential_isFinal(); region = region->m_nxt; } while (region != nullptr); }
                return isFinal;
            };

            if (isFinal()) { return internal::SubState<internal::Sequential>::asSubState_react(); }

            internal::Nextifier nextify{this};

            if (asHierarchicalState_immediatePreempt()) { return true; };

            doFront();
            bool const hasReacted = [&]{
                bool hasReacted = false;
                { auto region = m_fstElem; do { hasReacted |= region->asSequential_react(); region = region->m_nxt; } while (region != nullptr); }
                return hasReacted;
            }();
            doBack();

            bool const hasPreempted = [&]{ if (isFinal()) { return false; } else { return asHierarchicalState_preempt(); } }();

            return hasReacted || hasPreempted;
        }

        void asSubState_nextify() final {
            { auto region = m_fstElem; do { region->asScope_nextify(); region = region->m_nxt; } while (region != nullptr); }
            asScope_nextify();
        }

        void asSource_exit() final {
            { auto region = m_fstElem; do { region->asSequential_exit(); region = region->m_nxt; } while (region != nullptr); }
            onExit();
        }

        void asTarget_entry() final {
            onEntry();
            { auto region = m_fstElem; do { region->asSequential_entry(); region = region->m_nxt; } while (region != nullptr); }
        }

        void asSubState_abort() final { asSubState_reset(); }

        void asSubState_suspend() final {
            auto region = m_fstElem; do { region->asSequential_suspend(); region = region->m_nxt; } while (region != nullptr);
        }

        void asSubState_reset() final {
            { auto region = m_fstElem; do { region->asSequential_reset(); region = region->m_nxt; } while (region != nullptr); }
            onExit();
        }

        void asSubState_deepReset() final {
            { auto region = m_fstElem; do { region->asSequential_deepReset(); region = region->m_nxt; } while (region != nullptr); }
            onExit();
            asSubState_nextify();
        }

    public:
        CompositeMixee(internal::Sequential *ctxt) : internal::HierarchicalState<internal::Sequential>(ctxt) {}
    };

    inline RegionMixee::RegionMixee(CompositeMixee *ctxt, InitMixee &init) : internal::Sequential(init), m_ctxt(ctxt) {
        ZFSM_ERROR(ctxt == nullptr, "context pointer in region is null");
        m_ctxt->injectRegion(this); 
    }

    class TopMixee : public internal::Sequential {

    public:
        TopMixee() = delete;
        TopMixee(TopMixee const&) = delete;
        TopMixee(TopMixee&&) = delete;
        TopMixee& operator=(TopMixee const&) = delete;
        TopMixee& operator=(TopMixee&&) = delete;

        ~TopMixee() = default;

        void fuse() { ZFSM_ERROR(isFused, "state machine fused more than once"); asContext_fuse(); isFused = true; }

        bool tick() {
            ZFSM_ERROR(!isFused, "state machine not fused");
            if (isAtEntry) { 
                onEntry(); 
                asSequential_coreReact();
                isAtEntry = false; 
            } else {
                asSequential_react();
            }
            asScope_nextify();
            bool const isFinal = asSequential_isFinal();
            if (isFinal) { onExit(); isAtEntry = true; } 
            return !isFinal;
        }

        template<typename... Raised>
        bool tick(internal::ChainedSignal::Raised, Raised... signals) { return tick(signals...); }

        void exit() { ZFSM_ERROR(!isFused, "state machine not fused"); asSequential_deepReset(); isAtEntry = true; }

    protected:
        TopMixee(InitMixee &init) : internal::Sequential(init) {}

    private:
        bool isFused = false;
        bool isAtEntry = true;
    };

} // namespace internal

enum Capability { SIGNAL, ON_ENTRY, ON_EXIT, DO_FRONT, DO_BACK, REACT, CONTINUE, PREEMPT, IMMEDIATE_PREEMPT };

namespace internal
{
    template <bool> class SignalMixIn;

    template <>
    class SignalMixIn<false> {
        template <class Mixee, zfsm::Capability...> friend class ScopeMix;

        void inject(ChainedSignal *) { ZFSM_ERROR(true, "missing SIGNAL capability"); }
        void nextify() const {}
    };

    template <>
    class SignalMixIn<true> {
        template <class Mixee, zfsm::Capability...> friend class ScopeMix;

        ChainedSignal *m_fstSignal = nullptr;

        void inject(ChainedSignal *signal) { signal->chain(m_fstSignal); m_fstSignal = signal; }
        void nextify() const { 
            ZFSM_ERROR(m_fstSignal == nullptr, "missing signal(s)");
            { auto signal = m_fstSignal; do { signal->reset(); signal = signal->m_nxt; } while (signal != nullptr); }
        }
    };

    template <StateActionType, bool> class StateActionMixIn;

    template <StateActionType type>
    class StateActionMixIn<type, false> {
        template <class Mixee, zfsm::Capability...> friend class ScopeMix;

        void inject(ChainedAction *) { ZFSM_ERROR(true, "missing state action capability"); }
        void reverseActionChain() {}
        void enact() const {}
    };

    template <StateActionType type>
    class StateActionMixIn<type, true> {
        template <class Mixee, zfsm::Capability...> friend class ScopeMix;

        ChainedAction *m_fst = nullptr;

        void inject(ChainedAction *action) { action->chain(m_fst); m_fst = action; }
        void reverseActionChain() { ZFSM_ERROR(m_fst == nullptr, "missing state action(s)"); m_fst = m_fst->reverseElemChain(); }
        void enact() const { auto action = m_fst; do { action->chainedAction_evalExec(); action = action->m_nxt; } while (action != nullptr); }
    };

    template <ArrowType, bool> class ArrowMixIn;

    template <ArrowType type>
    class ArrowMixIn<type, false> {
        template <class Mixee, zfsm::Capability...> friend class SubStateMix;
        template <class Mixee, zfsm::Capability...> friend class GroundMix;
        template <class Mixee, zfsm::Capability...> friend class HierarchicalStateMix;

        void inject(ChainedArrow *) { ZFSM_ERROR(true, "missing arrow capability"); }
        void reverseArrowChain() {}
        bool enact(bool) const { return false; }
    };

    template <ArrowType type>
    class ArrowMixIn<type, true> {
        template <class Mixee, zfsm::Capability...> friend class SubStateMix;
        template <class Mixee, zfsm::Capability...> friend class GroundMix;
        template <class Mixee, zfsm::Capability...> friend class HierarchicalStateMix;

        ChainedArrow *m_fst = nullptr;

        void inject(ChainedArrow *arrow) { arrow->chain(m_fst); m_fst = arrow; }
        void reverseArrowChain() { ZFSM_ERROR(m_fst == nullptr, "missing arrow(s)"); m_fst = m_fst->reverseElemChain(); }
        bool enact(bool immediatePreempt) const {
            { auto *arrow = m_fst; do { if (arrow->chainedArrow_evalExec(immediatePreempt)) { return true; } arrow = arrow->m_nxt; } while (arrow != nullptr); }
            return false;
        }
    };

    template <Capability, Capability...> struct has;

    template <Capability capability>
    struct has<capability> { static constexpr bool value = false; };

    template <Capability capability, Capability first, Capability... rest>
    struct has<capability, first, rest...> { static constexpr bool value = (capability == first) || has<capability, rest...>::value; };

    template <class Mixee, Capability... capability>
    class ScopeMix :
        public Mixee,
        public SignalMixIn<has<SIGNAL, capability...>::value>,
        public StateActionMixIn<StateActionType::ON_ENTRY, has<ON_ENTRY, capability...>::value>,
        public StateActionMixIn<StateActionType::ON_EXIT, has<ON_EXIT, capability...>::value>,
        public StateActionMixIn<StateActionType::DO_FRONT, has<DO_FRONT, capability...>::value>,
        public StateActionMixIn<StateActionType::DO_BACK, has<DO_BACK, capability...>::value>
    {
        using _SignalMixIn = SignalMixIn<has<SIGNAL, capability...>::value>;
        using EntryMixIn = StateActionMixIn<StateActionType::ON_ENTRY, has<ON_ENTRY, capability...>::value>;
        using ExitMixIn = StateActionMixIn<StateActionType::ON_EXIT, has<ON_EXIT, capability...>::value>;
        using DoFrontMixIn = StateActionMixIn<StateActionType::DO_FRONT, has<DO_FRONT, capability...>::value>;
        using DoBackMixIn = StateActionMixIn<StateActionType::DO_BACK, has<DO_BACK, capability...>::value>;

        void injectSignal(ChainedSignal *signal) final { _SignalMixIn::inject(signal); }
        void asScope_nextify() const final { _SignalMixIn::nextify(); }

        void injectEntry(MarkOnEntry *onEntry) final { EntryMixIn::inject(onEntry); }
        void fuseEntries() final { EntryMixIn::reverseActionChain(); }
        void onEntry() const final { EntryMixIn::enact(); }

        void injectExit(MarkOnExit *onExit) final { ExitMixIn::inject(onExit); }
        void fuseExits() final { ExitMixIn::reverseActionChain(); }
        void onExit() const final { ExitMixIn::enact(); }

        void injectDoFront(MarkDoFront *doFront) final { DoFrontMixIn::inject(doFront); }
        void fuseDoFronts() final { DoFrontMixIn::reverseActionChain(); }
        void doFront() const final { DoFrontMixIn::enact(); }

        void injectDoBack(MarkDoBack *doBack) final { DoBackMixIn::inject(doBack); }
        void fuseDoBacks() final { DoBackMixIn::reverseActionChain(); }
        void doBack() const final { DoBackMixIn::enact(); }

    public:
        using Mixee::Mixee;
    };

    template <class Mixee, Capability... capability>
    class SubStateMix : public Mixee, public ArrowMixIn<ArrowType::REACT, has<REACT, capability...>::value>
    {
        friend class InjectReact;

        using ReactMixIn = ArrowMixIn<ArrowType::REACT, has<REACT, capability...>::value>;

        void injectReact(ChainedArrow *react) final { ReactMixIn::inject(react); }
        void fuseReacts() final { ReactMixIn::reverseArrowChain(); }
        bool react() final { return ReactMixIn::enact(false); }

    public:
        using Mixee::Mixee;
    };

    template <class Mixee, Capability... capability>
    class GroundMix : public Mixee, public ArrowMixIn<ArrowType::CONTINUE, has<CONTINUE, capability...>::value>
    {
        friend class InjectContinue;

        using ContinueMixIn = ArrowMixIn<ArrowType::CONTINUE, has<CONTINUE, capability...>::value>;

        void injectContinue(ChainedArrow *_continue) final { ContinueMixIn::inject(_continue); }
        void fuseContinues() final { ContinueMixIn::reverseArrowChain(); }
        bool _continue() final { return ContinueMixIn::enact(false); }

    public:
        using Mixee::Mixee;
    };

    template <class Mixee, Capability... capability>
    class HierarchicalStateMix :
        public Mixee,
        public ArrowMixIn<ArrowType::CONTINUE, has<CONTINUE, capability...>::value>,
        public ArrowMixIn<ArrowType::PREEMPT, has<PREEMPT, capability...>::value>,
        public ArrowMixIn<ArrowType::IMMEDIATE_PREEMPT, has<IMMEDIATE_PREEMPT, capability...>::value>
    {
        friend class InjectContinue;
        template <class T, class OnLeave, class SFINAE> friend class Preempt;
        template <class T, class OnLeave, class SFINAE> friend class ImmediatePreempt;

        using ContinueMixIn = ArrowMixIn<ArrowType::CONTINUE, has<CONTINUE, capability...>::value>;
        using PreemptMixIn = ArrowMixIn<ArrowType::PREEMPT, has<PREEMPT, capability...>::value>;
        using ImmediatePreemptMixIn = ArrowMixIn<ArrowType::IMMEDIATE_PREEMPT, has<IMMEDIATE_PREEMPT, capability...>::value>;

        void injectContinue(ChainedArrow *_continue) final { ContinueMixIn::inject(_continue); }
        void fuseContinues() final { ContinueMixIn::reverseArrowChain(); }
        bool _continue() final { return ContinueMixIn::enact(false); }

        void injectPreempt(ChainedArrow *preempt) final { PreemptMixIn::inject(preempt); }
        void fusePreempts() final { PreemptMixIn::reverseArrowChain(); }
        bool preempt() final { return PreemptMixIn::enact(false); }

        void injectImmediatePreempt(ChainedArrow *immediatePreempt) final { ImmediatePreemptMixIn::inject(immediatePreempt); }
        void fuseImmediatePreempts() final { ImmediatePreemptMixIn::reverseArrowChain(); }
        bool immediatePreempt() final { return ImmediatePreemptMixIn::enact(true); }

    public:
        using Mixee::Mixee;
    };

} // namespace internal

template <Capability... capability> using Init =      internal::GroundMix<internal::SubStateMix<zfsm::internal::InitMixee, capability...>, capability...>;
using Final =                                         internal::SubStateMix<zfsm::internal::FinalMixee>;
template <Capability... capability> using Basic =     internal::GroundMix<internal::SubStateMix<zfsm::internal::BasicMixee, capability...>, capability...>;
template <Capability... capability> using Super =     internal::HierarchicalStateMix<internal::SubStateMix<internal::ScopeMix<zfsm::internal::SuperMixee, capability...>, capability...>, capability...>;
template <Capability... capability> using Region =    internal::ScopeMix<zfsm::internal::RegionMixee, capability...>;
template <Capability... capability> using Composite = internal::HierarchicalStateMix<internal::SubStateMix<internal::ScopeMix<zfsm::internal::CompositeMixee, capability...>, capability...>, capability...>;
template <Capability... capability> using Top =       internal::ScopeMix<zfsm::internal::TopMixee, capability...>;

namespace internal
{
    class AttachedArrow : public ChainedArrow {
        template <class T, class OnLeave, class SFINAE> friend class ActiveArrow;

    public:
        AttachedArrow() = delete;
        AttachedArrow(AttachedArrow const&) = delete;
        AttachedArrow(AttachedArrow&&) = delete;
        AttachedArrow& operator=(AttachedArrow const&) = delete;
        AttachedArrow& operator=(AttachedArrow&&) = delete;

        ~AttachedArrow() = default;

    private:
        SubState<Sequential> &m_from;
        SubState<Sequential> &m_to;

        AttachedArrow(Ground &from, BasicMixee &to) : m_from(from), m_to(to) { 
            ZFSM_ERROR(m_from.m_ctxt != m_to.m_ctxt, "context mismatch on arrow from ground to basic state"); 
        }
        template <class Ctxt>
        AttachedArrow(Ground &from, HierarchicalState<Ctxt> &to) : m_from(from), m_to(to) { 
            ZFSM_ERROR(m_from.m_ctxt != m_to.m_ctxt, "context mismatch on arrow from ground to hierarchical state"); 
        }
        AttachedArrow(Ground &from, FinalMixee &to) : m_from(from), m_to(to) { 
            ZFSM_ERROR(m_from.m_ctxt != m_to.m_ctxt, "context mismatch on arrow from ground to final state"); 
        }
        template <class Ctxt>
        AttachedArrow(HierarchicalState<Ctxt> &from, BasicMixee &to) : m_from(from), m_to(to) { 
            ZFSM_ERROR(m_from.m_ctxt != m_to.m_ctxt, "context mismatch on arrow from hierarchical to basic state");
        }
        template <class Ctxt>
        AttachedArrow(HierarchicalState<Ctxt> &from, HierarchicalState<Ctxt> &to) : m_from(from), m_to(to) {
            ZFSM_ERROR(m_from.m_ctxt != m_to.m_ctxt, "context mismatch on arrow from hierarchical to hierarchical state");
        }
        template <class Ctxt>
        AttachedArrow(HierarchicalState<Ctxt> &from, FinalMixee &to) : m_from(from), m_to(to) {
            ZFSM_ERROR(m_from.m_ctxt != m_to.m_ctxt, "context mismatch on arrow from hierarchical to final state"); 
        }
     };

    template <typename T, class OnLeave, class SFINAE = void> class ActiveArrow;

    template <typename T, class OnLeave>
    class ActiveArrow<T, OnLeave, typename std::enable_if<std::is_void<T>::value>::type> : public AttachedArrow {

    public:
        ActiveArrow() = delete;
        ActiveArrow(ActiveArrow const&) = delete;
        ActiveArrow(ActiveArrow&&) = delete;
        ActiveArrow& operator=(ActiveArrow const&) = delete;
        ActiveArrow& operator=(ActiveArrow&&) = delete;

        ~ActiveArrow() = default;

    private:
        std::function<bool()> const m_guard;
        std::function<void()> const m_action;

        bool chainedArrow_evalExec(bool immediatePreempt) const final {
            if (!m_guard()) { return false; }

            OnLeave::doLeave(m_from);
            if (!immediatePreempt) { m_from.asSubState_nextify(); }
            m_action();
            m_to.m_ctxt->updateCurrent(&m_to);
            m_to.asTarget_entry();
            m_to.asSubState_nextify();
            return true;
        }

    protected:
        template <class From, class To>
        ActiveArrow(From &from, std::function<bool()> guard, To &to, std::function<void()> action)
            : AttachedArrow(from, to), m_guard(std::move(guard)), m_action(std::move(action)) {}
    };

    template <typename T, class OnLeave>
    class ActiveArrow<T, OnLeave, typename std::enable_if<!std::is_void<T>::value>::type> : public AttachedArrow {
        std::function<Carry<T>()> const m_guard;
        std::function<void(T)> const m_action;

    public:
        ActiveArrow() = delete;
        ActiveArrow(ActiveArrow const&) = delete;
        ActiveArrow(ActiveArrow&&) = delete;
        ActiveArrow& operator=(ActiveArrow const&) = delete;
        ActiveArrow& operator=(ActiveArrow&&) = delete;

        ~ActiveArrow() = default;

    private:
        bool chainedArrow_evalExec(bool immediatePreempt) const final {
            Carry<T> carry = m_guard();
            if (!carry.m_isFiring) { return false; }

            OnLeave::doLeave(m_from);
            if (!immediatePreempt) { m_from.asSubState_nextify(); }
            m_action(carry.takeValue());
            m_to.m_ctxt->updateCurrent(&m_to);
            m_to.asTarget_entry();
            m_to.asSubState_nextify();
            return true;
        }

    protected:
        template <class From, class To>
        ActiveArrow(From &from, std::function<Carry<T>()> guard, To &to, std::function<void(T)> action)
            : AttachedArrow(from, to), m_guard(std::move(guard)), m_action(std::move(action)) {}

        template <class From, class To>
        ActiveArrow(From &from, To &to) : ActiveArrow(from, []()->Carry<T>{ return {true, T{}}; }, to, [] {}) {}
    };

    template <class ActiveArrow, typename T, class SFINAE = void> class Arrow;

    template <class ActiveArrow, typename T>
    class Arrow<ActiveArrow, T, typename std::enable_if<std::is_void<T>::value>::type> : public ActiveArrow {

    public:
        Arrow() = delete;
        Arrow(Arrow const&) = delete;
        Arrow(Arrow&&) = delete;
        Arrow& operator=(Arrow const&) = delete;
        Arrow& operator=(Arrow&&) = delete;

        ~Arrow() = default;

        template <class From, class To>
        Arrow(From &from, std::function<bool()> guard, To &to, std::function<void()> action)
            : ActiveArrow(from, std::move(guard), to, std::move(action)) {}

        template <class From, class To> Arrow(From &from, To &to) : Arrow(from, []{ return true; }, to, [] {}) {}
        template <class From, class To>
        Arrow(From &from, std::function<bool()> guard, To &to) : Arrow(from, std::move(guard), to, [] {}) {}
        template <class From, class To>
        Arrow(From &from, Signal<void> &signal, To &to) : Arrow(from, [&]{ return signal(); }, to, [] {}) {}
        template <class From, class To, typename _T>
        Arrow(From &from, Signal<_T> &signal, To &to) : Arrow(from, [&]{ return signal(); }, to, [] {}) {}
        template <class From, class To>
        Arrow(From &from, Signal<void> &signal, To &to, std::function<void()> action)
            : Arrow(from, [&]{ return signal(); }, to, std::move(action)) {}
        template <class From, class To, typename _T>
        Arrow(From &from, Signal<_T> &signal, To &to, std::function<void()> action)
            : Arrow(from, [&]{ return signal(); }, to, std::move(action)) {}
        template <class From, class To>
        Arrow(From &from, To &to, std::function<void()> action) : Arrow(from, []{ return true; }, to, std::move(action)) {}
    };

    template <class ActiveArrow, typename T>
    class Arrow<ActiveArrow, T, typename std::enable_if<!std::is_void<T>::value>::type> : public ActiveArrow {

    public:
        Arrow() = delete;
        Arrow(Arrow const&) = delete;
        Arrow(Arrow&&) = delete;
        Arrow& operator=(Arrow const&) = delete;
        Arrow& operator=(Arrow&&) = delete;

        ~Arrow() = default;

        template <class From, class To>
        Arrow(From &from, std::function<Carry<T>()> guard, To &to, std::function<void(T)> action)
            : ActiveArrow(from, std::move(guard), to, std::move(action)) {}
        template <class From, class To>
        Arrow(From &from, Signal<T> &signal, To &to) 
            : Arrow(from, [&]()->Carry<T>{ if (signal()) { return {true, signal.getValue()}; } else { return false; } }, to, [](T) {}) {}
        template <class From, class To>
        Arrow(From &from, Signal<T> &signal, To &to, std::function<void(T)> action)
            : Arrow(from, [&]()->Carry<T>{ if (signal()) { return {true, signal.getValue()}; } else { return false; } }, to, std::move(action)) {}
    };

    template <typename T, class Inject, class OnLeave, class SFINAE = void> class Move;

    template <typename T, class Inject, class OnLeave>
    class Move<T, Inject, OnLeave, typename std::enable_if<std::is_void<T>::value>::type> : public ActiveArrow<void, OnLeave> {

    public:
        Move() = delete;
        Move(Move const&) = delete;
        Move(Move&&) = delete;
        Move& operator=(Move const&) = delete;
        Move& operator=(Move&&) = delete;

        ~Move() = default;

    protected:
        template <class From, class To>
        Move(From &from, std::function<bool()> guard, To &to, std::function<void()> action)
            : ActiveArrow<void, OnLeave>(from, std::move(guard), to, std::move(action)) {
            Inject::doInject(from, this);
        }
    };

    template <typename T, class Inject, class OnLeave>
    class Move<T, Inject, OnLeave, typename std::enable_if<!std::is_void<T>::value>::type> : public ActiveArrow<T, OnLeave> {

    public:
        Move() = delete;
        Move(Move const&) = delete;
        Move(Move&&) = delete;
        Move& operator=(Move const&) = delete;
        Move& operator=(Move&&) = delete;

        ~Move() = default;

    protected:
        template <class From, class To>
        Move(From &from, std::function<Carry<T>()> guard, To &to, std::function<void(T)> action)
            : ActiveArrow<T, OnLeave>(from, std::move(guard), to, std::move(action)) {
            Inject::doInject(from, this);
        }
    };

    class OnLeaveByMove {
        template <class T, class OnLeave, class SFINAE> friend class ActiveArrow;

        static void doLeave(SubState<Sequential> &from) { from.asSource_exit(); }
    };

    class InjectReact {
        template <typename T, class Inject, class OnLeave, class SFINAE> friend class Move;

        template <class From>
        static void doInject(From &from, AttachedArrow *react) { from.injectReact(react); }
    };

    class InjectContinue {
        template <typename T, class Inject, class OnLeave, class SFINAE> friend class Move;

        template <class From>
        static void doInject(From &from, AttachedArrow *_continue) { from.injectContinue(_continue); }
    };

} // namespace internal

template <typename T = void> using React = internal::Arrow<internal::Move<T, internal::InjectReact, internal::OnLeaveByMove>, T>;
template <typename T = void> using Continue = internal::Arrow<internal::Move<T, internal::InjectContinue, internal::OnLeaveByMove>, T>;

namespace internal
{
    template <class T = void, class OnLeave = void, class SFINAE = void> class Preempt;

    template <typename T, class OnLeave>
    class Preempt<T, OnLeave, typename std::enable_if<std::is_void<T>::value>::type> :  public ActiveArrow<void, OnLeave> {

    public:
        Preempt() = delete;
        Preempt(Preempt const&) = delete;
        Preempt(Preempt&&) = delete;
        Preempt& operator=(Preempt const&) = delete;
        Preempt& operator=(Preempt&&) = delete;

        ~Preempt() = default;

    protected:
        template <class From, class To>
        Preempt(From &from, std::function<bool()> guard, To &to, std::function<void()> action)
            : ActiveArrow<void, OnLeave>(from, std::move(guard), to, std::move(action)) {
            from.injectPreempt(this);
        }
    };

    template <typename T, class OnLeave>
    class Preempt<T, OnLeave, typename std::enable_if<!std::is_void<T>::value>::type> :  public ActiveArrow<T, OnLeave> {

    public:
        Preempt() = delete;
        Preempt(Preempt const&) = delete;
        Preempt(Preempt&&) = delete;
        Preempt& operator=(Preempt const&) = delete;
        Preempt& operator=(Preempt&&) = delete;

        ~Preempt() = default;

    protected:
        template <class From, class To>
        Preempt(From &from, std::function<Carry<T>()> guard, To &to, std::function<void(T)> action)
            : ActiveArrow<T, OnLeave>(from, std::move(guard), to, std::move(action)) {
            from.injectPreempt(this);
        }
    };

    template <class T = void, class OnLeave = void, class SFINAE = void> class ImmediatePreempt;

    template <typename T, class OnLeave>
    class ImmediatePreempt<T, OnLeave, typename std::enable_if<std::is_void<T>::value>::type> :  public ActiveArrow<void, OnLeave> {

    public:
        ImmediatePreempt() = delete;
        ImmediatePreempt(ImmediatePreempt const&) = delete;
        ImmediatePreempt(ImmediatePreempt&&) = delete;
        ImmediatePreempt& operator=(ImmediatePreempt const&) = delete;
        ImmediatePreempt& operator=(ImmediatePreempt&&) = delete;

        ~ImmediatePreempt() = default;

    protected:
        template <class From, class To>
        ImmediatePreempt(From &from, std::function<bool()> guard, To &to, std::function<void()> action)
            : ActiveArrow<void, OnLeave>(from, std::move(guard), to, std::move(action)) {
            from.injectImmediatePreempt(this);
        }
    };

    template <typename T, class OnLeave>
    class ImmediatePreempt<T, OnLeave, typename std::enable_if<!std::is_void<T>::value>::type> :  public ActiveArrow<T, OnLeave> {

    public:
        ImmediatePreempt() = delete;
        ImmediatePreempt(ImmediatePreempt const&) = delete;
        ImmediatePreempt(ImmediatePreempt&&) = delete;
        ImmediatePreempt& operator=(ImmediatePreempt const&) = delete;
        ImmediatePreempt& operator=(ImmediatePreempt&&) = delete;

        ~ImmediatePreempt() = default;

    protected:
        template <class From, class To>
        ImmediatePreempt(From &from, std::function<Carry<T>()> guard, To &to, std::function<void(T)> action)
            : ActiveArrow<T, OnLeave>(from, std::move(guard), to, std::move(action)) {
            from.injectImmediatePreempt(this);
        }
    };

    class OnLeaveByAbort {
        template <class T, class OnLeave, class SFINAE> friend class ActiveArrow;

        static void doLeave(SubState<Sequential> &from) { from.asSubState_abort(); }
    };

} // namespace internal

template <typename T = void> using Abort = internal::Arrow<internal::Preempt<T, internal::OnLeaveByAbort>, T>;
template <typename T = void> using ImmediateAbort = internal::Arrow<internal::ImmediatePreempt<T, internal::OnLeaveByAbort>, T>;

namespace internal
{
    class OnLeaveBySuspend {
        template <class T, class OnLeave, class SFINAE> friend class ActiveArrow;

        static void doLeave(SubState<Sequential> &) {}
    };

} // namespace internal

template <typename T = void> using Suspend = internal::Arrow<internal::Preempt<T, internal::OnLeaveBySuspend>, T>;
template <typename T = void> using ImmediateSuspend = internal::Arrow<internal::ImmediatePreempt<T, internal::OnLeaveBySuspend>, T>;

namespace internal
{
    template <class Mark, class Inject, typename T, class SFINAE = void> class StateAction;

    template <class Mark, class Inject, typename T>
    class StateAction<Mark, Inject, T, typename std::enable_if<std::is_void<T>::value>::type> : public Mark {

    public:
        StateAction() = delete;
        StateAction(StateAction const&) = delete;
        StateAction(StateAction&&) = delete;
        StateAction& operator=(StateAction const&) = delete;
        StateAction& operator=(StateAction&&) = delete;

        ~StateAction() = default;

    private:
        std::function<bool()> const m_guard;
        std::function<void()> const m_action;

        void chainedAction_evalExec() const final { if (m_guard()) { m_action(); } }

    public:
        StateAction(Scope *scope, std::function<bool()> guard, std::function<void()> action)
            : m_guard(std::move(guard)), m_action(std::move(action)) { Inject::doInject(scope, this); }

        StateAction(Scope *scope, std::function<void()> action)
            : StateAction(scope, []{ return true; }, std::move(action)) {}
        StateAction(Scope *scope, Signal<void> &signal, std::function<void()> action)
            : StateAction(scope, [&]{ return signal(); }, std::move(action)) {}
        template <typename _T>
        StateAction(Scope *scope, Signal<_T> &signal, std::function<void()> action)
            : StateAction(scope, [&]{ return signal(); }, std::move(action)) {}
    };

    template <class Mark, class Inject, typename T>
    class StateAction<Mark, Inject, T, typename std::enable_if<!std::is_void<T>::value>::type> : public Mark {

    public:
        StateAction() = delete;
        StateAction(StateAction const&) = delete;
        StateAction(StateAction&&) = delete;
        StateAction& operator=(StateAction const&) = delete;
        StateAction& operator=(StateAction&&) = delete;

        ~StateAction() = default;

    private:
        std::function<Carry<T>()> const m_guard;
        std::function<void(T)> const m_action;

        void chainedAction_evalExec() const final { Carry<T> carry = m_guard(); if (carry.m_isFiring) { m_action(carry.takeValue()); } }

    public:
        StateAction(Scope *scope, std::function<Carry<T>()> guard, std::function<void(T)> action)
            : m_guard(std::move(guard)), m_action(std::move(action)) {  Inject::doInject(scope, this); }
            
        StateAction(Scope *scope, Signal<T> &signal, std::function<void(T)> action)
            : StateAction(scope, [&]()->Carry<T>{ if (signal()) { return {true, signal.getValue()}; } else { return false; } }, std::move(action)) {}
    };

    class InjectOnEntry { public: static void doInject(Scope *scope, MarkOnEntry *onEntry) { ZFSM_ERROR(scope == nullptr, "scope pointer on entry action is null"); scope->injectEntry(onEntry); } };
    class InjectOnExit { public: static void doInject(Scope *scope, MarkOnExit *onExit) { ZFSM_ERROR(scope == nullptr, "scope pointer on exit action is null"); scope->injectExit(onExit); } };
    class InjectDoFront { public: static void doInject(Scope *scope, MarkDoFront *doFront) { ZFSM_ERROR(scope == nullptr, "scope pointer on do-front action is null"); scope->injectDoFront(doFront); } };
    class InjectDoBack { public: static void doInject(Scope *scope, MarkDoBack *doBack) { ZFSM_ERROR(scope == nullptr, "scope pointer on do-back action null"); scope->injectDoBack(doBack); } };

} // namespace internal

template <typename T = void> using OnEntry = internal::StateAction<internal::MarkOnEntry, internal::InjectOnEntry, T>;
template <typename T = void> using OnExit = internal::StateAction<internal::MarkOnExit, internal::InjectOnExit, T>;
template <typename T = void> using DoFront = internal::StateAction<internal::MarkDoFront, internal::InjectDoFront, T>;
template <typename T = void> using DoBack = internal::StateAction<internal::MarkDoBack, internal::InjectDoBack, T>;

} // namespace zfsm

#undef ZFSM_ERROR

#endif // INCLUDED_ZFSM_HPP
