#pragma once
//#include "FiberCamera_Exports.h"
#include <afxwin.h>

#ifndef WM_QUIT_THREAD
    #define WM_QUIT_THREAD  (WM_USER +0)
#endif

/// \brief 工作线程类。
/// 多线程有多种实现方式，本类适合：
/// 1. 指定一个函数作为线程的主循环。
/// 2. 需要用到windows的消息系统。
/// 
/// 简单用法：
/// 1. 工作类相关的某个类里定义一个成员：
/// CMFCThread * m_Thread;
/// 
/// 2. 构造实例，但未启动线程：
/// m_Thread = new CMFCThread(<静态函数指针>);
/// 或：
/// m_Thread = new CMFCThread(std::bind(<类成员函数指针>, this));
/// 
/// 
/// 3. 启动线程：
/// if(m_Thread){
///     m_Thread->Start();
/// }
/// 
/// 4. 终止线程：
/// if(m_Thread){
///     m_Thread->Quit();
/// }

class CMFCThread :
    public CWinThread // 继承CWinThread的目的是需要用到windows的消息系统
{
public:
	//   DECLARE_DYNAMIC(CMFCThread) // 需要MFC的动态类型信息时打开。本类只创建实例指针，不需要动态类型信息。

    using run_func_t = int(void);

    /// @brief  用静态函数指针构造工作线程实例
    /// @param func 
    CMFCThread(run_func_t* func)
        : _Run(func)
    {

    }

    /// @brief  用bind()封装类成员函数、lambda函数等
    /// @param func 
    CMFCThread(std::function<int()> func)
        : _Run(func)
    {

    }

protected:
    /// 主循环函数，可以指定静态函数或、类成员函数、lambda函数
    std::function<int()> _Run;

    /// 直接返回TRUE，缺省不会进run()而是进入CWinThread的消息循环
    virtual BOOL InitInstance()
    {
        return TRUE; 
        //return CWinThread::InitInstance();
    }

public:
    /// @brief 线程主函数，内部改成了函数调用，方便简单应用场景不需要再重载。
    virtual int Run() override
    {
        ASSERT(_Run != nullptr); // 使用前必须设置函数指针
        return _Run();
    }

    /// @brief 设置函数指针和优先级
    /// @param prio 线程优先级，默认THREAD_PRIORITY_NORMAL。
    bool Start(int prio = THREAD_PRIORITY_NORMAL) {
        if (CreateThread()) {
            if (prio != THREAD_PRIORITY_NORMAL) {
                SetThreadPriority(prio);
            }
            return true;
        }
        else {
            return false;
        }
    }

    /// @brief  外部调用结束线程
    void Quit(int ret=0) {
        if(m_nThreadID) ::PostThreadMessage(m_nThreadID, WM_QUIT_THREAD, WPARAM(ret), 0);
    }

	/// @brief  等待线程结束。与Quit()分开方便先所有子线程调用一遍Quit()，再一个个等。
	/// @param ms 等待时间，单位毫秒
    bool Wait(int ms) {
        DWORD uResult = WaitForSingleObject(this->m_hThread, ms);
		if(WAIT_OBJECT_0 == uResult) {
			//alog->info(u8"线程正常退出");
            return true;
		}
		else {
			alog->warn(u8"线程退出超时 {}", uResult);
            return false;
		}
	}

};
