#pragma once
#include "CEventBase.h"
#include "SystemResources.h"

namespace ns_mess
{
    class __declspec(dllexport) bond_stop_key {};  // ����ֹͣ�̾�����Ϣ
    class __declspec(dllexport) step_run_error {};  // ����Stepִ�г����׳���Ϣ
    
    template<typename PreviousDispatcher, typename Msg, typename Func>
    class __declspec(dllexport) CTemplateDispatcher
    {
        CMyQueue* m_Queue;
        PreviousDispatcher* prev;
        string m_chDescribe;
        Func func;
        string m_chClass;
        string m_chState;
        bool m_bChained;

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

        template<typename Dispatcher, typename OtherMsg, typename OtherFunc>
        friend class CTemplateDispatcher;  // �����ػ���TemplateDispatcher����ʵ��������Ԫ��
        
        std::string  GetClassName(std::string cls)
        {
            std::string className = cls;
            int firstSpaceIndex = (int)className.find_first_of(" ") + 1;
            int lastSpaceIndex = (int)className.find_last_of(" ");
            int nameLength = lastSpaceIndex - firstSpaceIndex - 2;
            return className.substr(firstSpaceIndex, nameLength);
        }

        void WaitAndDispatch()
        {
            for (;;)
            {
                auto msg = m_Queue->WaitMessage();
                if (DispatchMessage(msg))
                   break;
            }
        }

        template<typename step>
        long LocalFunctionRun(wrapped_message<Msg>* wm)
        {
            auto f1 = [&](step const& msg)->bool
            {
                string n = GetClassName(typeid(msg).name());
                return wm->contents.EventRun(m_chDescribe, m_chClass,m_chState,n);
            };

            return f1(wm->contents);
        }

        bool DispatchMessage(std::shared_ptr<MESSAGE_BASE> const& msg)
        {
            if (dynamic_cast<wrapped_message<bond_stop_key>*>(msg.get()))
            {
                throw bond_stop_key();
            } 
            else
            {
                wrapped_message<Msg>* wrapper = dynamic_cast<wrapped_message<Msg>*>(msg.get());
                if (wrapper)
                {
                    long re = LocalFunctionRun<Msg>(wrapper);
                    if (OK == re)
                    {
                        func(wrapper->contents);
                    }
                    else if(FSM_NOT_EXECUTE != re)
                    {
                        throw step_run_error();
                    }
                    return (re == OK  ? true : false);
                }
                else
                {
                    return prev->DispatchMessage(msg);  
                }
            }
        }
    public:
        CTemplateDispatcher(CTemplateDispatcher&& other) :
            m_Queue(other.m_Queue), prev(other.prev), m_chDescribe(other.m_chDescribe), m_chClass(other.m_chClass), m_chState(other.m_chState),
            func(std::move(other.func)),m_bChained(other.m_bChained)
        {
            other.m_bChained = true;
        }
        CTemplateDispatcher(CMyQueue* q_, PreviousDispatcher* prev_,string describe_, string clas_,string state_,Func&& f_) :
            m_Queue(q_), prev(prev_), m_chDescribe(describe_), m_chClass(clas_),m_chState(state_), func(std::forward<Func>(f_)), m_bChained(false)
        {
            prev_->m_bChained = true;
        }

        template<typename OtherMsg, typename OtherFunc>
        CTemplateDispatcher<CTemplateDispatcher, OtherMsg, OtherFunc>
            HandleMessage(string sStepDescribe, string sClas,string sState,OtherFunc&& of)  
        {
            return CTemplateDispatcher<CTemplateDispatcher, OtherMsg,OtherFunc>(
                    m_Queue, this, sStepDescribe, sClas,sState, std::forward<OtherFunc>(of));
        }
        ~CTemplateDispatcher() noexcept(false) 
        {
            if (!m_bChained)
            {
                WaitAndDispatch();
            }
        }
    };
}