class CMTPadMsgLoop : public CMessageLoop
{
public:
	CMainFrame m_wndFrame;

	int Run(LPTSTR lpstrCmdLine, int nCmdShow)
	{
		if(m_wndFrame.CreateEx() == NULL)
		{
			ATLTRACE(_T("CMainFrame creation failed!\n"));
			return 0;
		}

		if(lpstrCmdLine[0] == 0)
		{
			m_wndFrame.DoFileNew();
		}
		else	// file name specified at the command line
		{
			// strip quotes (if any)
			LPTSTR lpstrCmd = lpstrCmdLine;
			if(lpstrCmd[0] == '"')
			{
				lpstrCmd++;
				for(int i = 0; i < lstrlen(lpstrCmd); i++)
				{
					if(lpstrCmd[i] == '"')
					{
						lpstrCmd[i] = 0;
						break;
					}
				}
			}
			// get full path and file name
			TCHAR szPathName[MAX_PATH];
			LPTSTR lpstrFileName = NULL;
			::GetFullPathName(lpstrCmd, MAX_PATH, szPathName, &lpstrFileName);
			// open file
			if(m_wndFrame.DoFileOpen(szPathName, lpstrFileName))
			{
				m_wndFrame.m_mru.AddToList(szPathName);
			}
		}

		m_wndFrame.ShowWindow(nCmdShow);

		return CMessageLoop::Run();
	}

	virtual BOOL PreTranslateMessage(MSG* pMsg)
	{
		return m_wndFrame.PreTranslateMessage(pMsg);
	}

	virtual BOOL OnIdle(int)
	{
		m_wndFrame.UpdateUIAll();
		return FALSE;
	}
};

class CThreadManager
{
public:
	// thread init param
	struct _RunData
	{
		LPTSTR lpstrCmdLine;
		int nCmdShow;
	};

	// thread proc
	static DWORD WINAPI RunThread(LPVOID lpData)
	{
		CMTPadMsgLoop theLoop;
		_Module.AddMessageLoop(&theLoop);

		_RunData* pData = (_RunData*)lpData;
		int nRet = theLoop.Run(pData->lpstrCmdLine, pData->nCmdShow);
		delete pData;

		_Module.RemoveMessageLoop();
		return nRet;
	}

	DWORD m_dwCount;
	HANDLE m_arrThreadHandles[MAXIMUM_WAIT_OBJECTS - 1];

	CThreadManager() : m_dwCount(0)
	{ }

// Operations
	DWORD AddThread(LPTSTR lpstrCmdLine, int nCmdShow)
	{
		if(m_dwCount == (MAXIMUM_WAIT_OBJECTS - 1))
		{
			::MessageBox(NULL, _T("ERROR: Cannot create ANY MORE threads!!!"), _T("MTPad"), MB_OK);
			return 0;
		}

		_RunData* pData = new _RunData;
		pData->lpstrCmdLine = lpstrCmdLine;
		pData->nCmdShow = nCmdShow;
		DWORD dwThreadID;
		HANDLE hThread = ::CreateThread(NULL, 0, RunThread, pData, 0, &dwThreadID);
		if(hThread == NULL)
		{
			::MessageBox(NULL, _T("Cannot create thread!!!"), _T("MTPad"), MB_OK);
			return 0;
		}

		m_arrThreadHandles[m_dwCount] = hThread;
		m_dwCount++;
		return dwThreadID;
	}

	void RemoveThread(DWORD dwIndex)
	{
		::CloseHandle(m_arrThreadHandles[dwIndex]);
		if(dwIndex != (m_dwCount - 1))
			m_arrThreadHandles[dwIndex] = m_arrThreadHandles[m_dwCount - 1];
		m_dwCount--;
	}

	int Run(LPTSTR lpstrCmdLine, int nCmdShow)
	{
		MSG msg;
		// force message queue to be created
		::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

		AddThread(lpstrCmdLine, nCmdShow);

		int nRet = m_dwCount;
		DWORD dwRet;
		while(m_dwCount > 0)
		{
			dwRet = ::MsgWaitForMultipleObjects(m_dwCount, m_arrThreadHandles, FALSE, INFINITE, QS_ALLINPUT);

			if(dwRet == 0xFFFFFFFF)
				::MessageBox(NULL, _T("Wait for multiple objects failed!!!"), _T("MTPad"), MB_OK);
			else if(dwRet >= WAIT_OBJECT_0 && dwRet <= (WAIT_OBJECT_0 + m_dwCount - 1))
				RemoveThread(dwRet - WAIT_OBJECT_0);
			else if(dwRet == (WAIT_OBJECT_0 + m_dwCount))
			{
				::GetMessage(&msg, NULL, 0, 0);
				if(msg.message == WM_USER)
					AddThread(_T(""), SW_SHOWNORMAL);
				else
					::MessageBeep((UINT)-1);
			}
			else
				::MessageBeep((UINT)-1);
		}

		return nRet;
	}
};
