#pragma once
#include <functional>
#include "sender.hpp"
#include "TemplateDispatcher.hpp"

namespace ns_mess
{
    typedef std::function<string()> StateFunc;

    class __declspec(dllexport) close_queue {}; // ���ڹرն��е���Ϣ
    class __declspec(dllexport) ChangeState  // ����״̬�л�����Ϣ
    {
        public:
            StateFunc m_chState;
            explicit ChangeState(StateFunc s) : m_chState(s) {};
    };

    class __declspec(dllexport) CDispatcher
    {
        CMyQueue* m_Queue;
        bool m_bChained;

        CDispatcher(CDispatcher const&) = delete;  // dispatcherʵ�����ܱ�����
        CDispatcher& operator=(CDispatcher const&) = delete;

        template<typename Dispatcher,typename Msg,typename Func>  // ����TemplateDispatcherʵ�������ڲ���Ա
        friend class CTemplateDispatcher;

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

        bool DispatchMessage(
            std::shared_ptr<MESSAGE_BASE> const& msg)
        {
            if (dynamic_cast<wrapped_message<close_queue>*>(msg.get()))
            {
                throw close_queue();
            }
            else if (dynamic_cast<wrapped_message<ChangeState>*>(msg.get()))
            {
                wrapped_message<ChangeState>* wrapper = dynamic_cast<wrapped_message<ChangeState>*>(msg.get());
                throw wrapper->contents;
            }
            return true;
        }
    public:
        CDispatcher(CDispatcher&& other) :  // dispatcherʵ�������ƶ�
            m_Queue(other.m_Queue), m_bChained(other.m_bChained)
        {
            other.m_bChained = true;  // Դ���ܵȴ���Ϣ
        }
        explicit CDispatcher(CMyQueue* q_) :
            m_Queue(q_), m_bChained(false)
        {
        }

        template<typename Message,typename Func>
        CTemplateDispatcher<CDispatcher, Message,Func>
            HandleMessage(string describe_, string clas_,string state_, Func&& func) 
        {
             return CTemplateDispatcher<CDispatcher, Message, Func>(m_Queue, this, describe_, clas_,state_, std::forward<Func>(func));
        }

        ~CDispatcher() noexcept(false)
        {
            if (!m_bChained)
            {
                WaitAndDispatch();
            }
        }
    };
}