#ifndef __SCRIPT_EXECUTOR__
#define __SCRIPT_EXECUTOR__

#pragma once

#define BUFSIZE 4096
enum PY_RUN_TYPE
{
	EMBEDDED,			// 嵌入到本进程运行;
	SUBPROCESS			// 以子进程方式运行;
};

class CScriptExecutor
{
public:
	CScriptExecutor(void);
	~CScriptExecutor(void);

protected:
	HANDLE			m_hWorkThread;						// 事件句柄;
	HANDLE			m_hWorkEvent;						// 线程事件;
	HANDLE			m_hLogThread;						// 事件句柄;
	HANDLE			m_hLogEvent;						// 线程事件;
	BOOL			m_bStatus;							// 线程状态;
	TCHAR			m_szScriptPath[MAX_PATH];			// 脚本路径;
	TCHAR			m_szLogPath[MAX_PATH];				// 日志路径;	
	TCHAR			m_szExtraSentence[MAX_PATH];		// 脚本命令行参数或额外要执行的语句;
	int				m_nRunType;
	// 重定向标准输出和标准错误;
	HANDLE			m_hStdOutRead;
	HANDLE			m_hStdOutWrite;
	HANDLE			m_hStdErrorWrite;
	HANDLE			m_hOldStdOutWrite;					// 用于本进程标准输出备份;
	// 子进程信息;
	STARTUPINFO			m_si;
	PROCESS_INFORMATION	m_pi;
	// 进程结束标志;
	BOOL			m_bKillProcess;
	// 停止日志导出线程;
	BOOL			m_bStopLogExport;
	// 执行器执行时间;
	CTime			m_tStartTime;
	// 执行器结束时间;
	CTime			m_tEndTime;
	// 子进程ID;
	DWORD			m_dwSubprocessId;
	// 线程ID;
	DWORD			m_dwThreadId;
	// 脚本是否成功运行;
	BOOL			m_bRuned;
protected:
	// 工作者线程函数;
	static DWORD WINAPI _WorkerThread(LPVOID lpParam);
	// 日志导出线程;
	static DWORD WINAPI _LogExportThread(LPVOID lpParam);
	// 重定向本进程标准输出;
	int RedirectProcessStdout();
	// 重定子进程向标准输出;
	int RedirectSubprocessStdout(LPSTARTUPINFO si = NULL);	
	// 获取Python异常;
	void CatchPythonException();
	// 运行嵌入的脚本;
	int RunEmbeddedScript();
	// 运行脚本进程;
	int RunScripProcess();
	// 开启线程;
	bool StartWorkThread();
	bool StartLogThread();
	// 结束线程;
	void EndWorkThread();
	void EndLogThread();
	void EndThread(HANDLE hThread, HANDLE hEvent);
	// 结束子进程;
	BOOL EndSubprocess();
	// 从管道读取日志;
	void ReadFromPipe();
	// 结束重定向句柄,恢复默认;
	void EndProcessStdOut();
	void EndSubprocessStdOut();
public:
	// 初始脚本运行参数;
	void InitScript(
		std::string strScript, 
		std::string strLogPath, 
		std::string strScriptCmd, 
		int nRunType = EMBEDDED);
	// 运行脚本;
	bool StartScript();
	// 停止脚本;
	void StopScript();
	// 脚本是否结束;
	bool IsScriptOver();
	// 运行类型;
	int GetRunType() const { return m_nRunType;}
	// 获取脚本Id;
	DWORD GetScriptId() const {
		if ( m_nRunType == SUBPROCESS )
			return m_dwSubprocessId;
		else
			return m_dwThreadId;
	}
};

#endif // __SCRIPT_EXECUTOR__