/*****************************************************************************
Open Source MIT License

Copyright (c) 2017 Matthew Ahmed

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*****************************************************************************/

// Win.h: interface for the ZWin class.
//
//////////////////////////////////////////////////////////////////////

#pragma once
#include "Headers.h"

#define WMU_INIT  WM_USER + 9999
#define WMU0      WM_USER + 10000 // for individual classes

// WM_COMMAND handlers
#define WTAKECMD(wParam, fn) case wParam : (fn)(); return 0L
#define WTAKECMDPARM(wParam, fn) case wParam : (fn)(lP); return 0L
// Other Window message handlers
#define WTAKEMSG(msg, fn) case msg : (fn)(); return 0L
#define WTAKEMSGPARM(msg, fn) case msg : (fn)(wP, lP); return 0L

// Subs for "return fnErr(... " in void functions
#define RET_V(s1) {fnErr(s1); return;}
#define RET_V2(s1, s2) {fnErr(s1, s2); return;}
#define RET_SYSV(s1) {fnSysErr(s1); return;}
#define RET_SYSV2(s1, s2) {fnSysErr(s1, s2); return;}

// For fnWaitForMsg & fnYield
#define WFM_ERROR     -1
#define WFM_TIMEOUT   0
#define WFM_GOTMSG    1

#define SERROR_MAX    8191

typedef struct ZWinAppData
{
	TCHAR sProgDirSlash[2048]; // Larger for possible error message getting paths
  TCHAR sExeNameNoDotExt[_MAX_PATH];
  TCHAR sAppDocsDirSlash[_MAX_PATH];
  TCHAR sAppDataDirSlash[_MAX_PATH];
} ZWinAppData;

class ZWin
{
public:
	ZWin(HINSTANCE hInst = NULL, LPCTSTR sCapt1 = NULL, // Allow 1st two null for ZWinUtil
			 LPCTSTR sCapt2 = NULL, ZWin * pOwner = NULL, ZWinAppData * pzwd = NULL);
	virtual ~ZWin();
	HWND GetWnd();

  BOOL ToLog(LPCTSTR sMsg1, LPCTSTR sMsg2 = NULL, LPCTSTR sMsg3 = NULL,
             BOOL bTimeStamp = TRUE);
  BOOL ToLogNoStamp(LPCTSTR sMsg1, LPCTSTR sMsg2 = NULL, LPCTSTR sMsg3 = NULL);

#if defined(_WIN32_DCOM) // Assumes if defined, various related includes
  static BOOL CoInitDcom(); // Public for Minimal.cpp
#endif

protected:
	ZWin * m_pOwner;
	HWND m_hOwner;
	TCHAR m_sCapt[128];
	TCHAR m_sCaptLong[128];
	HINSTANCE m_hInst;
	HWND m_hWnd;

//  TCHAR m_sProgDirSlash[_MAX_PATH];
//  TCHAR m_sAppDocsDirSlash[_MAX_PATH];
//  TCHAR m_sAppDataDirSlash[_MAX_PATH];
//  TCHAR m_sExeNameNoDotExt[_MAX_PATH];
  ZWinAppData * m_pzwd;

  TCHAR sBS[4096];
  TCHAR sBS2[4096];
  INT nBS;
  INT nBS2;

  // Frequently used constants
  static const TCHAR cNull = _T('\0');
//  TCHAR sRN[3];
  LPCTSTR sRN;
  LPCTSTR sCapLetters;
  LPCTSTR sDigits;

  BOOL m_bFlushLog;

  TCHAR m_sError[SERROR_MAX + 1];
  BOOL SetError(LPCTSTR sMsg1, LPCTSTR sMsg2 = NULL, LPCTSTR sMsg3 = NULL,
					   LPCTSTR sMsg4 = NULL, LPCTSTR sMsg5 = NULL, LPCTSTR sMsg6 = NULL);
  BOOL AppendError(LPCTSTR sMsg1, LPCTSTR sMsg2 = NULL, LPCTSTR sMsg3 = NULL,
					   LPCTSTR sMsg4 = NULL, LPCTSTR sMsg5 = NULL, LPCTSTR sMsg6 = NULL);
  void ClearError();

  HANDLE m_hfLog;
  BOOL StartLog(LPCTSTR sFileName = NULL, LPCTSTR sMsg = NULL, BOOL bFlush = FALSE); 
  // BOOL ToLog(LPCTSTR sMsg1, LPCTSTR sMsg2 = NULL, LPCTSTR sMsg3 = NULL);
  BOOL CloseLog(LPCTSTR sMsg = NULL);
  BOOL WriteLineToLog(LPCTSTR sLine, BOOL bTimeStamp = TRUE,
                      BOOL bAddRN = TRUE);

	void CenterWnd(HWND hCenterIn = NULL);

  BOOL GetVersionNumStr(LPTSTR sVersion);

  BOOL GetCopyrightStr(LPTSTR sCopyright);

	INT WaitForMsg(UINT uMsg, UINT uTimeOut, WPARAM * pWp = NULL,
													LPARAM * pLp = NULL, UINT uTimerID = 789);

	inline BOOL fnYield(UINT uDelay = 10, UINT uTimerID = 678)
	{
		//      Here, 0 (i.e. WFM_TIMEOUT) is the expected fnWaitForMsg return
		return (WaitForMsg(0, uDelay, NULL, NULL, uTimerID)) ? FALSE : TRUE;
	}

	inline BOOL fnYield(LPCTSTR sErrPlace, UINT uDelay = 10, UINT uTimerID = 678)
	{												// sErrPlace can be NULL
		return (WaitForMsg(0, uDelay, NULL, NULL, uTimerID)) ?
																		fnErr(_T("Timer Error"), sErrPlace) : TRUE;
	}

  void fnYieldOnce();

	// Basic overrides simply set hWnd and caption
	INT MB(LPCTSTR sMsg1, LPCTSTR sMsg2 = NULL, LPCTSTR sMsg3 = NULL,
									LPCTSTR sMsg4 = NULL, LPCTSTR sMsg5 = NULL,
										LPCTSTR sMsg6 = NULL, UINT uType = MB_OK)
	{										// Yes, caption first
		return MsgB(m_hWnd, m_sCapt, sMsg1, sMsg2,
									sMsg3, sMsg4, sMsg5, sMsg6, uType);
	}
				// So can set MB_... without writing NULL for all unused sMsg#
	INT MB(UINT uType, LPCTSTR sMsg1, LPCTSTR sMsg2 = NULL, LPCTSTR sMsg3 = NULL,
							LPCTSTR sMsg4 = NULL, LPCTSTR sMsg5 = NULL, LPCTSTR sMsg6 = NULL)
	{										// Yes, caption first
		return MsgB(m_hWnd, m_sCapt, sMsg1, sMsg2,
									sMsg3, sMsg4, sMsg5, sMsg6, uType);
	}

	BOOL fnErr(LPCTSTR sErr1, LPCTSTR sErr2 = NULL, LPCTSTR sErr3 = NULL,
							LPCTSTR sErr4 = NULL, LPCTSTR sErr5 = NULL, LPCTSTR sErr6 = NULL);
// Now in ZWin.cpp, to append " - ERROR" to window caption
	//{
	//	return fnError(m_hWnd, m_sCapt, sErr1, sErr2,
	//											sErr3, sErr4, sErr5, sErr6);
	//}

	//BOOL fnSysErr(LPCTSTR sErr1, LPCTSTR sErr2 = NULL,
	//								LPCTSTR sErr3 = NULL, LPCTSTR sErr4 = NULL)
	//{
 //   return fnSysError(m_hWnd, m_sCapt, sErr1, sErr2, sErr3, sErr4);
	//}

	BOOL fnSysErr(DWORD dwErr, LPCTSTR sErr1, LPCTSTR sErr2 = NULL,
									LPCTSTR sErr3 = NULL, LPCTSTR sErr4 = NULL)
	{
    return fnSysError(dwErr, m_hWnd, m_sCapt, sErr1, sErr2, sErr3, sErr4);
	}

	BOOL fnSysErr(LPCTSTR sErr1, LPCTSTR sErr2 = NULL,
									LPCTSTR sErr3 = NULL, LPCTSTR sErr4 = NULL)
	{
    return fnSysError(0, m_hWnd, m_sCapt, sErr1, sErr2, sErr3, sErr4);
	}

  BOOL SetSysErr(LPCTSTR sErr1, LPCTSTR sErr2 = NULL,
									LPCTSTR sErr3 = NULL, LPCTSTR sErr4 = NULL);

  BOOL SetSysErr(DWORD dwErr, LPCTSTR sErr1, LPCTSTR sErr2 = NULL,
									LPCTSTR sErr3 = NULL, LPCTSTR sErr4 = NULL);

  //void zPeekMessage(void);
  MSG zm_msg;
  inline void zPeekMessage()
  {
    while (PeekMessage(&zm_msg , NULL, NULL, NULL, PM_REMOVE))
    {
      TranslateMessage(&zm_msg);
      DispatchMessage(&zm_msg);
    }
  }

	BOOL ReadReg(HKEY hOpen, LPCTSTR sKey, LPCTSTR sValue, LPTSTR sTarget,
												BOOL bErrMsg = FALSE, DWORD dwSize = _MAX_PATH);

#if defined(_INC_COMMCTRL)
  virtual void ProcessProgress(MSG * pMsg, INT nProgress, INT nInfo = 0);
  INT GetListviewSingleSelected(HWND hList);
#endif

#if defined(_WIN32_DCOM) // Assumes if defined, various related includes

BOOL SelectFolder(HWND hOwner, LPTSTR sReturn, LPCTSTR sTitle = NULL,
                     LPCTSTR sDefault = NULL, INT nCsidlRoot = 0);

#endif // _WIN32_DCOM

private:
  TCHAR sTmp_ZWin_private[2048];

}; // class ZWin

