#ifndef __FILEVIEWWATCHWER_H__
#define __FILEVIEWWATCHWER_H__

// file modification watcher thread
class KoWatcher
{
// Attributes
private:
	CEvent m_eventStartWatching;
	// signals that watcher thread shall start watching

	CEvent m_eventTerminate;
	// signals that watcher thread should terminate

	CCriticalSection m_section;
	// to synchronize access to data fileds

	TCHAR m_path[_MAX_PATH];
	// path to watch for changes

	bool m_isRecursive;
	// flag to tell if watching for recursive changes

	HWND m_hWnd;
	// window to post notification to

	HANDLE m_handles[3];
	// objects being watched

	DWORD m_count;
	// count of handles

public:
	// messages posted out
	enum 
	{ 
		WM_FILECHANGE = WM_APP + 51,
		// private message for delivering file change notification
	};


// Construction
public:
	KoWatcher(HWND hWnd)
	: m_isRecursive(false)
	, m_hWnd(hWnd)
	{ 
		m_handles[0] = m_eventStartWatching;
		m_handles[1] = m_eventTerminate;
		m_count = 2;
		*m_path = 0;

		// start the thread immediately
		AfxBeginThread(DelegateRun, this);
	}

private:
	// must call SignalTerminate() to destroy this object
	~KoWatcher()
	{}

// Operations
public:
	// signal to start watching for file changes in particular destination
	void SignalStartWatch(LPCTSTR path, bool isRecursive)
	{
		// store parameters
		m_section.Lock();
		_tcscpy(m_path, path);
		m_isRecursive = isRecursive;
		m_section.Unlock();
		m_eventStartWatching.SetEvent();
	}

	// signals to terminate
	void SignalTerminate()
	{
		m_eventTerminate.SetEvent();
	}

// Implementations
private:
	// delegates control to non-static member
	static UINT DelegateRun(LPVOID p)
	{
		KoWatcher* watcher = (KoWatcher*)p;
		return watcher->Run();
	}

	// responds to events until requested to terminate
	UINT Run()
	{
		
		for(;;)
		{
			DWORD dw = WaitForMultipleObjects(m_count, m_handles, FALSE, INFINITE);
			switch (dw)
			{
				case WAIT_OBJECT_0 :
				{
					// process signal to start watching
					StopWatch();
					StartWatch();
					m_eventStartWatching.Unlock();
					break;
				}
				case WAIT_OBJECT_0 + 1 :
				{
					// process signal to terminate
					StopWatch();
					delete this;
					return 0;
				}
				case WAIT_OBJECT_0 + 2 :
				{
					// process file change signal
					StopWatch();
					PostMessage(m_hWnd, WM_FILECHANGE, 0, 0);
					break;
				}

			}
		}
		return 0;
	}

	// starts monitoring 
	bool StartWatch()
	{
		// retrieve parameters first
		TCHAR path[_MAX_PATH];
		bool isRecursive;
		m_section.Lock();
		lstrcpyn(path, m_path, _MAX_PATH);
		isRecursive = m_isRecursive;
		m_section.Unlock();

		// start watching
		HANDLE h =	FindFirstChangeNotification( 
						path, 
						isRecursive,
						FILE_NOTIFY_CHANGE_FILE_NAME |
						FILE_NOTIFY_CHANGE_DIR_NAME |
						//FILE_NOTIFY_CHANGE_SIZE |
						FILE_NOTIFY_CHANGE_LAST_WRITE |
						//FILE_NOTIFY_CHANGE_LAST_ACCESS |
#if _MSC_VER >= 1200
						//FILE_NOTIFY_CHANGE_CREATION | (makes Win98 fails)
#endif
						//FILE_NOTIFY_CHANGE_SECURITY |
						FILE_NOTIFY_CHANGE_ATTRIBUTES
					);
		if (h != INVALID_HANDLE_VALUE)
		{
			m_handles[2] = h;
			m_count = 3;
		}
		return m_count == 3;
	}

	// stops monitoring
	void StopWatch()
	{
		if (m_count == 3 && m_handles[2] != INVALID_HANDLE_VALUE)
		{
			// reset and close the handle
			FindNextChangeNotification(m_handles[2]); 
			FindCloseChangeNotification(m_handles[2]);
			m_handles[2] = INVALID_HANDLE_VALUE;
			m_count = 2;
		}
	}
};



#endif
// __FILEVIEWWATCHWER_H__