#include "globals.h"

#if H323_USE_PRIVATE_IO_THREAD
#define FINITE_WAIT_TIME    3000

static  HANDLE      H323IoCompletionPort = NULL;
static  HANDLE      H323IoThread = NULL;
static  DWORD       H323IoThreadID = 0;

static DWORD WINAPI H323IoThreadProc (
    IN  PVOID   ThreadParameter)
{
    LPOVERLAPPED    Overlapped;
    ULONG_PTR       CompletionKey;
    DWORD           Status;
    DWORD           BytesTransferred;

    for (;;)
    {
        if( GetQueuedCompletionStatus( H323IoCompletionPort, 
            &BytesTransferred, 
            &CompletionKey, 
            &Overlapped, 
            INFINITE) == TRUE ) 
        {
            Status = ERROR_SUCCESS;
        }
        else 
        {
            if( Overlapped )
            {
                Status = GetLastError();
            }
            else 
            {
                H323DBG((DEBUG_LEVEL_ERROR, "failed to dequeue i/o completion "
                         "packet: %d, quitting...", GetLastError() ));

                ExitThread (GetLastError());
            }
        }

        _ASSERTE( CompletionKey);

        ((LPOVERLAPPED_COMPLETION_ROUTINE) CompletionKey)(  Status, 
                                                            BytesTransferred,
                                                            Overlapped );
    }

    // never reached
    return EXIT_SUCCESS;
}

static void CALLBACK H323IoThreadExitCallback (
    IN  DWORD   Status,
    IN  DWORD   BytesTransferred,
    IN  LPOVERLAPPED    Overlapped)
{
    H323DBG ((DEBUG_LEVEL_TRACE, "i/o completion thread is stopping"));
    ExitThread (EXIT_SUCCESS);
}

HRESULT H323IoThreadStart (void)
{
    if( H323IoCompletionPort == NULL )
    {
        H323IoCompletionPort = 
            CreateIoCompletionPort(  INVALID_HANDLE_VALUE, 
                                     NULL, 
                                     0, 
                                     0 );
        if( H323IoCompletionPort == NULL )
        {
            H323DBG(( DEBUG_LEVEL_ERROR, 
                "failed to create i/o completion port: %d", GetLastError() ));

            return GetLastResult();
        }
    }


    H323IoThread = CreateThread(NULL, 
                                0, 
                                H323IoThreadProc, 
                                NULL, 
                                0, 
                                &H323IoThreadID );

    if( H323IoThread == NULL )
    {
        H323DBG((   DEBUG_LEVEL_ERROR, 
                    "failed to create i/o completion worker thread: %d",
                    GetLastError() ));

        CloseHandle (H323IoCompletionPort);
        H323IoCompletionPort = NULL;

        return GetLastResult();
    }

    return S_OK;
}

void H323IoThreadStop (void)
{
    DWORD dwWaitTime = INFINITE;
    H323DBG ((DEBUG_LEVEL_WARNING, "H323IoThreadStop entered."));

    if( H323IoThread != NULL )
    {
        _ASSERTE( H323IoCompletionPort != NULL );

        if( !PostQueuedCompletionStatus( H323IoCompletionPort, 0,
            (ULONG_PTR) H323IoThreadExitCallback, (LPOVERLAPPED) -1) )
        {
            H323DBG(( DEBUG_LEVEL_WARNING, "PostQueuedCompletionStatus failed" ));
            dwWaitTime = FINITE_WAIT_TIME;
        }

        H323DBG(( DEBUG_LEVEL_WARNING, 
            "waiting for i/o completion port thread to finish..." ));

        WaitForSingleObject( H323IoThread, dwWaitTime );

        H323DBG(( DEBUG_LEVEL_WARNING, 
            "i/o completion port thread is finished." ));

        CloseHandle (H323IoThread);
        H323IoThread = NULL;
    }

    if( H323IoCompletionPort != NULL )
    {
        CloseHandle( H323IoCompletionPort );
        
        H323IoCompletionPort = NULL;
    }

    H323DBG ((DEBUG_LEVEL_WARNING, "H323IoThreadStop exited"));
}

BOOL H323BindIoCompletionCallback (
    IN  HANDLE  ObjectHandle,
    IN  LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine,
    IN  ULONG   Flags)
{
    if( H323IoCompletionPort != NULL )
    {
        if (!CompletionRoutine) 
        {
            SetLastError (ERROR_INVALID_PARAMETER);
            return FALSE;
        }

        return CreateIoCompletionPort(  ObjectHandle, 
                                        H323IoCompletionPort,
                                        (ULONG_PTR) CompletionRoutine, 
                                        0 ) != NULL;
    }
    else
    {
        H323DBG(( DEBUG_LEVEL_ERROR, "i/o completion port is not yet created" ));

        SetLastError( ERROR_GEN_FAILURE );
        return FALSE;
    }
}

#endif