' Classes/System/Threading/WaitHandle.ab

#ifndef __SYSTEM_THREADING_WAITHANDLE_AB__
#define __SYSTEM_THREADING_WAITHANDLE_AB__

#require <Classes/System/misc.ab>

Namespace System
Namespace Threading

Namespace Detail
	TypeDef PFNSignalObjectAndWait = *Function(hObjectToSignal As HANDLE, hObjectToWaitOn As HANDLE, dwMilliseconds As DWord, bAlertable As DWord) As DWord
End Namespace

Class WaitHandle
	Inherits System.IDisposable
Public
	' Properties
'	Const Function SafeWaitHandle() As SafeWaitHandle
'	Sub SafeWaitHandle(h As SafeWaitHandle)

	Const Virtual Function Handle() As HANDLE
		Return h
	End Function

	Virtual Sub Handle(newHandle As HANDLE)
		h = newHandle
	End Sub

	' Methods

	Virtual Sub ~WaitHandle()
		Dispose()
	End Sub

	Virtual Sub Close()
		Dispose()
	End Sub

	Override Sub Dispose()
		Dim hDisposing = InterlockedExchangePointer(h, 0)
		If hDisposing <> 0 Then
			CloseHandle(hDisposing)
		End If
	End Sub

	Function WaitOne() As Boolean
		Return WaitOne(INFINITE, FALSE)
	End Function

	Function WaitOne(millisecondsTimeout As Long, exitContext As BOOL) As Boolean
		Return WaitHandle.AfterWait(WaitForSingleObject(h, millisecondsTimeout As DWord), 1)
	End Function

'	Function WaitOne(timeout As TimeSpan, exitContext As BOOL) As BOOL
/*
	Static Function WaitAll(count As DWord, handles As *HANDLE) As BOOL
		Return WaitAll(count, handles, INFINITE, FALSE)
	End Function

	Static Function WaitAll(count As DWord, handles As *HANDLE, millisecondsTimeout As Long, exitContext As BOOL) As BOOL
		Return WaitHandle.AfterWait(WaitForMultipleObjects(count, handles, TRUE, millisecondsTimeout), count)
	End Function

'	Static Function WaitAll(timeout As TimeSpan, handles As *HANDLE, millisecondsTimeout As Long, exitContext As BOOL) As BOOL

	Static Function WaitAny(count As DWord, handles As *HANDLE) As BOOL
		Return WaitAny(count, handles, INFINITE, FALSE)
	End Function

	Static Function WaitAny(count As DWord, handles As *HANDLE, millisecondsTimeout As Long, exitContext As BOOL) As BOOL
		Return WaitHandle.AfterWait(WaitForMultipleObjects(count, handles, FALSE, millisecondsTimeout), count)
	End Function

'	Static Function WaitAny(timeout As TimeSpan, handles As *HANDLE, millisecondsTimeout As Long, exitContext As BOOL) As BOOL
*/
	Static Function SignalAndWait(toSignal As WaitHandle, toWaitOn As WaitHandle) As Boolean
		Return SignalAndWait(toSignal, toWaitOn, INFINITE, FALSE)
	End Function

Public
	Static Function SignalAndWait(toSignal As WaitHandle, toWaitOn As WaitHandle, millisecondsTimeout As Long, exitContext As BOOL) As Boolean
		Dim pSignalObjectAndWait = GetProcAddress(GetModuleHandle("Kernel32.dll"), "SignalObjectAndWait") As Detail.PFNSignalObjectAndWait
		If pSignalObjectAndWait = 0 Then
			' PlatformNotSupportedException
			Debug
			ExitThread(-1)
		End If
		Return WaitHandle.AfterWait(pSignalObjectAndWait(toSignal.Handle, toWaitOn.Handle, millisecondsTimeout As DWord, FALSE), 1)
	End Function

'	Static Function SignalAndWait(ByRef toSignal As WaitHandle, ByRef toWaitOn As WaitHandle, timeout As TimeSpan, exitContext As BOOL) As BOOL

' Protected
	Sub WaitHandle()
	End Sub

Protected
	Static Const InvalidHandle = INVALID_HANDLE_VALUE As HANDLE

Private
	h As HANDLE

	Static Function AfterWait(ret As DWord, n As DWord) As Boolean
		Select Case ret
			Case WAIT_TIMEOUT
				Return False
			Case WAIT_ABANDONED
				' Throw AbandonedMutexException
				Debug
				ExitThread(0)
			'Case WAIT_FAILED
			Case Else
				If WAIT_OBJECT_0 <= ret And ret < WAIT_OBJECT_0 + n Then
					Return True
				End If
				' ObjectDisposedException?
				Debug
				ExitThread(0)
		End Select
	End Function
End Class

End Namespace 'Threading
End Namespace 'System

#endif '__SYSTEM_THREADING_WAITHANDLE_AB__
