
/*******************************************************\
{                                                       }
{       Microsoft Visual C++ Version 4.X                }
{       Alarm Clock 1.5                                 }
{                                                       }
{       Copyright (C) 1996, CAT Computing Center (R).   }
{                                                       }
\*******************************************************/

#define STRICT
#include <Windows.h>
#include <Windowsx.h>
#include <commctrl.h>
#include <tchar.h>
#include <stdio.h>
#include "Resource.h"
#include "Alarm.h"

void DelHotKey(LPSCHDATA lpSetData);
void SetHotKey(LPSCHDATA lpSetData);
BOOL StartMonitor();
BOOL ChangeMonitor(long nIndex, LPSCHDATA lpSetData);
void StopMonitor();
BOOL IsShowSettingsDlg();

BYTE szIdent[] = _T("LM\0\0\0CAT\0\0");
#define IDENTLEN	10

typedef struct tagDBHEAD
{
	BYTE bIdent[IDENTLEN];
	long nRecCount;
} DBHEAD, *LPDBHEAD;

TCHAR szMainKey[] = _T("SOFTWARE\\CAT\\Alarm Clock");
static HANDLE s_hFile = INVALID_HANDLE_VALUE;
LPDBHEAD s_lpHead = NULL;

DWORD GetRegDWORD(LPCTSTR lpszFolder, LPCTSTR lpszKey, DWORD dwDefault /*= 0*/)
{
	TCHAR szFolder[MAX_PATH];
	_tcscpy(szFolder, szMainKey);
	if(lpszFolder)
	{
		_tcscat(szFolder, _T("\\"));
		_tcscat(szFolder, lpszFolder);
	}
	
	HKEY hKey;
	if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, szFolder, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
	{
		DWORD dwTemp2, dwTemp = sizeof(DWORD);
		DWORD dwRealType;
		if(RegQueryValueEx(hKey, lpszKey, 0, &dwRealType, (LPBYTE)&dwTemp2, &dwTemp) == ERROR_SUCCESS)
		{
			if(REG_DWORD == dwRealType)
			{
				dwDefault = dwTemp2;
			}
		}
		RegCloseKey(hKey);
	}
	return dwDefault;
}

BOOL GetRegString(LPCTSTR lpszFolder, LPCTSTR lpszKey, LPCTSTR lpszDefault, LPTSTR lpszReturnedString, DWORD dwSize)
{
	TCHAR szFolder[MAX_PATH];
	_tcscpy(szFolder, szMainKey);
	if(lpszFolder)
	{
		_tcscat(szFolder, _T("\\"));
		_tcscat(szFolder, lpszFolder);
	}
	
	HKEY hKey;
	if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, szFolder, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
	{
		DWORD dwRealType;
		if(RegQueryValueEx(hKey, lpszKey, 0, &dwRealType, (LPBYTE)lpszReturnedString, &dwSize) != ERROR_SUCCESS)
		{
			_tcscpy(lpszReturnedString, lpszDefault);
			return FALSE;
		}
		RegCloseKey(hKey);
		if(REG_SZ == dwRealType)
			return TRUE;
	}
	return FALSE;
}

BOOL SetRegDWORD(LPCTSTR lpszFolder, LPCTSTR lpszKey, DWORD dwData)
{
	BOOL bRet = FALSE;
	TCHAR szFolder[MAX_PATH];
	_tcscpy(szFolder, szMainKey);
	if(lpszFolder)
	{
		_tcscat(szFolder, _T("\\"));
		_tcscat(szFolder, lpszFolder);
	}
	
	HKEY hKey;
	DWORD dwDisp;
	if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, szFolder, 0, NULL, 
		REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisp) == ERROR_SUCCESS)
	{
		if(RegSetValueEx(hKey, lpszKey, 0, REG_DWORD, (CONST BYTE*)&dwData, sizeof(DWORD)) == ERROR_SUCCESS)
		{
			bRet = TRUE;
		}
		RegCloseKey(hKey);
	}
	return bRet;
}

BOOL SetRegString(LPCTSTR lpszFolder, LPCTSTR lpszKey, LPCTSTR lpszString)
{
	BOOL bRet = FALSE;
	TCHAR szFolder[MAX_PATH];
	_tcscpy(szFolder, szMainKey);
	if(lpszFolder)
	{
		_tcscat(szFolder, _T("\\"));
		_tcscat(szFolder, lpszFolder);
	}
	
	HKEY hKey;
	DWORD dwDisp;
	if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, szFolder, 0, NULL, 
		REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisp) == ERROR_SUCCESS)
	{
		if(RegSetValueEx(hKey, lpszKey, 0, REG_SZ, (CONST BYTE*)lpszString, _tcslen(lpszString)) != ERROR_SUCCESS)
		{
			bRet = TRUE;
		}
		RegCloseKey(hKey);
	}
	return bRet;
}

int ShowOSError(UINT uMesID, DWORD dwError, int nMode /*= MB_OK|MB_ICONERROR*/)
{
	TCHAR szBuf[256];
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szBuf, 256, 0);
	TCHAR szText[256];
	LoadString(g_AppData.hInstance, uMesID, szText, 255);
	TCHAR szEndMes[512];
	_tcscpy(szEndMes, szText);
	_tcscat(szEndMes, szBuf);
	return ReportBox(szEndMes, nMode);
}

BOOL ReadHeader()
{
	DBHEAD Header;
	DWORD dwSize;
	if(sizeof(DBHEAD) <= GetFileSize(s_hFile, NULL))
	{
		if(ReadFile(s_hFile, &Header, sizeof(DBHEAD), &dwSize, NULL) || (dwSize != sizeof(DBHEAD)))
		{
			if(memcmp(Header.bIdent, szIdent, IDENTLEN) == 0)
				return TRUE;
		}
		SetFilePointer(s_hFile, 0, NULL, FILE_BEGIN);
	}
	memcpy(Header.bIdent, szIdent, IDENTLEN);
	Header.nRecCount = 0;
	if(!WriteFile(s_hFile, &Header, sizeof(DBHEAD), &dwSize, NULL) || (dwSize != sizeof(DBHEAD)))
	{
		ShowOSError(IDS_DBS_SYS_ERROR, GetLastError());
		return FALSE;
	}
	if(!SetEndOfFile(s_hFile))
	{
		ShowOSError(IDS_DBS_SYS_ERROR, GetLastError());
		return FALSE;
	}
	return TRUE;
}

BOOL CreateMap()
{
	HANDLE hMapFile = CreateFileMapping(s_hFile, NULL, PAGE_READWRITE, 0, sizeof(DBHEAD), NULL);
	if(hMapFile)
	{
		s_lpHead = (LPDBHEAD)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(DBHEAD));
		CloseHandle(hMapFile);
	}
	else
	{
		ShowOSError(IDS_DBS_SYS_ERROR, GetLastError());
		return FALSE;
	}
	return TRUE;
}

BOOL OpenDBSettings()
{
	if(INVALID_HANDLE_VALUE == s_hFile)
	{
		TCHAR szPath[MAX_PATH];
		if(!GetModuleFileName(g_AppData.hInstance, szPath, MAX_PATH))
			return FALSE;
		LPTSTR lpszTemp = _tcsrchr(szPath, _T('.'));
		if(lpszTemp)
			lpszTemp[0] = 0;
		_tcscat(szPath, _T(".dbs"));
		s_hFile = CreateFile(szPath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
		if(INVALID_HANDLE_VALUE == s_hFile)
		{
			ShowOSError(IDS_OPEN_DBS_FAILED, GetLastError());
			return FALSE;
		}
		if(!ReadHeader())
		{
			s_hFile = INVALID_HANDLE_VALUE;
			return FALSE;
		}
		if(!CreateMap())
		{
			s_hFile = INVALID_HANDLE_VALUE;
			return FALSE;
		}
	}
	return StartMonitor();
}

BOOL CloseDBSettings()
{
	CloseHandle(s_hFile);
	UnmapViewOfFile(s_lpHead);
	s_lpHead = NULL;
	s_hFile = INVALID_HANDLE_VALUE;
	StopMonitor();
	return TRUE;
}

BOOL ReadDBSettings(long nIndex, LPSCHDATA lpSetData)
{
	DWORD dwSize;
	if(nIndex >= s_lpHead->nRecCount)
		return FALSE;
	if((SetFilePointer(s_hFile, sizeof(DBHEAD) + sizeof(SCHDATA) * nIndex, NULL, FILE_BEGIN) == -1) && (GetLastError() != NO_ERROR))
	{
		ShowOSError(IDS_DBS_SYS_ERROR, GetLastError());
		return FALSE;
	}
	if(!ReadFile(s_hFile, lpSetData, sizeof(SCHDATA), &dwSize, NULL) || (dwSize != sizeof(SCHDATA)))
	{
		ShowOSError(IDS_DBS_SYS_ERROR, GetLastError());
		return FALSE;
	}
	return TRUE;
}

BOOL WriteDBSettings(long nIndex, LPSCHDATA lpSetData)
{
	DWORD dwSize;
	if(nIndex > s_lpHead->nRecCount)
		return FALSE;
	if(SetFilePointer(s_hFile, sizeof(DBHEAD) + sizeof(SCHDATA) * nIndex, NULL, FILE_BEGIN) == (DWORD)-1)
	{
		ShowOSError(IDS_DBS_SYS_ERROR, GetLastError());
		return FALSE;
	}
	if(!WriteFile(s_hFile, lpSetData, sizeof(SCHDATA), &dwSize, NULL) || (dwSize != sizeof(SCHDATA)))
	{
		ShowOSError(IDS_DBS_SYS_ERROR, GetLastError());
		return FALSE;
	}
	if(nIndex == s_lpHead->nRecCount)
		s_lpHead->nRecCount++;
	return ChangeMonitor(nIndex, lpSetData);
}

BOOL ClearDBSettings()
{
	if(SetFilePointer(s_hFile, sizeof(DBHEAD), NULL, FILE_BEGIN) == (DWORD)-1)
	{
		ShowOSError(IDS_DBS_SYS_ERROR, GetLastError());
		return FALSE;
	}
	UnmapViewOfFile(s_lpHead);
	if(!SetEndOfFile(s_hFile))
	{
		ShowOSError(IDS_DBS_SYS_ERROR, GetLastError());
		return FALSE;
	}
	if(!CreateMap())
	{
		return FALSE;
	}
	s_lpHead->nRecCount = 0;
	StartMonitor();
	return TRUE;
}

long& GetDBRecCount()
{
	return s_lpHead->nRecCount;
}

static LPSCHDATA s_lpSetData = NULL;
static long s_nCount = -1;
static UINT s_uTID = 0;

long DecrementTime(LPSYSTEMTIME lpSysTime)
{
	if(lpSysTime->wMinute)
	{
		lpSysTime->wMinute--;
	}
	if(lpSysTime->wMinute == 0)
	{
		if(lpSysTime->wHour)
			lpSysTime->wHour--;
	}
	return (lpSysTime->wHour || lpSysTime->wMinute);
}

void ExecuteMonitor(LPSCHDATA lpSetData)
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	memset(&si, 0, sizeof(STARTUPINFO));
	si.cb = sizeof(STARTUPINFO);
	if(!CreateProcess(NULL, lpSetData->szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
	{
		TCHAR szErrorText[512];
		TCHAR szTemp[256];
		LoadString(g_AppData.hInstance, IDS_ERROR_EXEC, szTemp, 255);
		sprintf(szErrorText, szTemp, lpSetData->szPath);
		ReportBox(szErrorText, MB_OK|MB_ICONSTOP);
		return;
	}
	CloseHandle(pi.hProcess);
}

VOID CALLBACK MonitorProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
	if(IsShowSettingsDlg() == TRUE)
		return;

	SYSTEMTIME st;
	GetLocalTime(&st);
	for(long i = 0; i < s_nCount; i++)
	{
		if(!s_lpSetData[i].bEnable)
			continue;

		switch(s_lpSetData[i].nFrecq)
		{
			case 0:
			{
				if(((s_lpSetData[i].st00.wYear % 100) == (st.wYear % 100)) && (s_lpSetData[i].st00.wMonth == st.wMonth) && (s_lpSetData[i].st00.wDay == st.wDay)
					&& (s_lpSetData[i].st01.wHour == st.wHour) && (s_lpSetData[i].st01.wMinute == st.wMinute))
				{
					ExecuteMonitor(&s_lpSetData[i]);
					s_lpSetData[i].bEnable = 0;
					WriteDBSettings(i, &s_lpSetData[i]);
				}
				break;
			}
			case 1:
			{
				if(s_lpSetData[i].nMinutes10 == st.wMinute)
					ExecuteMonitor(&s_lpSetData[i]);
				break;
			}
			case 2:
			{
				if((s_lpSetData[i].st20.wHour == st.wHour) && (s_lpSetData[i].st20.wMinute == st.wMinute))
					ExecuteMonitor(&s_lpSetData[i]);
				break;
			}
			case 3:
			{
				if((s_lpSetData[i].nDayOfWeek30 == st.wDayOfWeek) && (s_lpSetData[i].st31.wHour == st.wHour) && (s_lpSetData[i].st31.wMinute == st.wMinute))
					ExecuteMonitor(&s_lpSetData[i]);
				break;
			}
			case 4:
			{
				if((s_lpSetData[i].nDayOfMonth40 == st.wDay) && (s_lpSetData[i].st31.wHour == st.wHour) && (s_lpSetData[i].st31.wMinute == st.wMinute))
					ExecuteMonitor(&s_lpSetData[i]);
				break;
			}
			case 5:
			{
				if(!DecrementTime(&s_lpSetData[i].st51))
					ExecuteMonitor(&s_lpSetData[i]);
				memcpy(&s_lpSetData[i].st51, &s_lpSetData[i].st50, sizeof(SYSTEMTIME));
				break;
			}
		}
	}
}

BOOL StartMonitor()
{
	if(s_lpSetData)
		StopMonitor();

	if((s_nCount = s_lpHead->nRecCount) == 0)
		return TRUE;

	s_lpSetData = new SCHDATA[s_nCount];
	for(long i = 0; i < s_nCount; i++)
	{
		if(!ReadDBSettings(i, &s_lpSetData[i]))
		{
			StopMonitor();
			return FALSE;
		}
		SetHotKey(&s_lpSetData[i]);
	}
	s_uTID = SetTimer(g_AppData.hMainWnd, 1999, 60000, MonitorProc);
	return TRUE;
}

void StopMonitor()
{
	if(s_uTID)
		KillTimer(g_AppData.hMainWnd, s_uTID);
	if(s_lpSetData)
	{
		for(long i = 0; i < s_nCount; i++)
		{
			DelHotKey(&s_lpSetData[i]);
		}
		delete[] s_lpSetData;
	}
	s_lpSetData = NULL;
	s_nCount = -1;
}

BOOL ChangeMonitor(long nIndex, LPSCHDATA lpSetData)
{
/*	if(s_nCount == -1)
		return FALSE;

	if(nIndex < s_nCount)
		memmove(&s_lpSetData[nIndex], lpSetData, sizeof(SCHDATA));
	else
		return StartMonitor();*/
	return TRUE;
}

BOOL HotKeyMonitor(WPARAM wParam, LPARAM lParam)
{
	if(IsShowSettingsDlg() == FALSE)
	{
		for(long i = 0; i < s_nCount; i++)
		{
			if(s_lpSetData[i].dwHotKey == wParam)
			{
				ExecuteMonitor(&s_lpSetData[i]);
			}
		}
		return TRUE;
	}
	return FALSE;
}
