//
//  Copyright © 2004, RESON Inc. All Rights Reserved.
//
//  No part of this file may be reproduced or transmitted in any form or by
//  any means, electronic or mechanical, including photocopy, recording, or
//  information storage or retrieval system, without permission in writing
//  from RESON Inc.
//
//  Filename:   
//
//  Project:    6046
//
//  Author(s):  W. Arcus
//
//  Purpose:    
//
//  Notes:      
//

#include "StdAfx.h"
#include "GenericSocket.h"

#include "..\..\..\Utils\NetUtils\SystemTime.h"
#include "..\..\..\Utils\NetUtils\ThreadedSocket.h"

#pragma comment( lib, "ws2_32.lib" )

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

namespace                                                       // Begin anonymous namespace.
{
    template <typename tType> inline void Destroy( tType *&rpPointer )
    {
        if ( rpPointer != NULL )
        {
            __TRY
            {
                delete rpPointer;
            }
            __FINALLY
            {
                rpPointer = NULL;
            }
            __ENDFINALLY
        }
    }

}                                                               // End anonymous namespace.

//////////////////////////////////////////////////////////////////////
// CGenericSocket class implementation.

CGenericSocket::CGenericSocket( void )
{
    m_eSocketType            = socketTypeUnspecified;
    m_pfnDataHandlerCallback = NULL;
    m_pvDataHandlerParam     = NULL;

    m_pUDPSocket  = NULL;
    m_pTCPSocket  = NULL;
}

CGenericSocket::~CGenericSocket( void )
{
    __TRY
    {
        Destroy( m_pUDPSocket );
        Destroy( m_pTCPSocket );
    }
    __FINALLY
    {
        m_pUDPSocket             = NULL;
        m_pTCPSocket             = NULL;
        m_pvDataHandlerParam     = NULL;
        m_pfnDataHandlerCallback = NULL;
        m_eSocketType            = socketTypeUnspecified;
    }
    __ENDFINALLY
}

bool CGenericSocket::Configure(    const ESOCKETTYPE                      &reSocketType,
                                    const unsigned short                   &runPort,
                                    const bool                             &rbBroadcast,
                                    PFN_DATACALLBACK                        pfnCallback,
                                    void *                                  pvCallbackParam,
                                    const unsigned long                    &rulSendAddress )
{
    bool bSuccess = false;

    Destroy( m_pUDPSocket );
    Destroy( m_pTCPSocket );

    ASSERT( reSocketType    != socketTypeUnspecified );
    ASSERT( pfnCallback     != NULL );
    ASSERT( pvCallbackParam != NULL );

    m_eSocketType            = socketTypeUnspecified;
    m_pfnDataHandlerCallback = pfnCallback;
    m_pvDataHandlerParam     = pvCallbackParam;

    switch ( m_eSocketType )
    {
        case socketTypeDatagram:

            m_pUDPSocket = new CUDPSocket( CUDPSocket::modeServer, runPort, rbBroadcast, rulSendAddress, m_pfnDataHandlerCallback, m_pvDataHandlerParam );

            if ( ( m_pUDPSocket == NULL ) && ( m_pUDPSocket->IsInitialized() ) )

            if ( ( m_pUDPSocket != NULL ) && ( m_pUDPSocket->IsInitialized() ) )
            {
                m_eSocketType = reSocketType;
                bSuccess = true;
            }

            break;

        case socketTypeStream:

            m_pTCPSocket = new CTCPSocket( runPort, rulSendAddress, m_pfnDataHandlerCallback, m_pvDataHandlerParam ); //StreamSocketCallback, this );
            ASSERT( m_pTCPSocket != NULL );

            if ( ( m_pTCPSocket != NULL ) && ( m_pTCPSocket->IsInitialized() ) )
            {
                m_eSocketType = reSocketType;
                bSuccess = true;
            }

            break;

        default:

            bSuccess = false;
            TRACE( _T( "CGenericSocket::Configure(), Unrecognised socket type.\n" ) );
            break;
    }

    return bSuccess;
}

bool CGenericSocket::Send( BYTE * const            pbyStream,
                            const unsigned long    &rulNumBytes,
                            const int              &riSocketIndex )
{
    bool bSuccess = false;

    switch ( m_eSocketType )
    {
        case socketTypeDatagram:

            bSuccess = ( ( m_pUDPSocket != NULL ) && ( m_pUDPSocket->Send( pbyStream, rulNumBytes ) ) );
            break;

        case socketTypeStream:
            
            ASSERT( riSocketIndex >= 0 );
            bSuccess = ( ( m_pTCPSocket != NULL ) && ( m_pTCPSocket->Send( pbyStream, rulNumBytes, riSocketIndex ) ) );
            break;

        default:

            ASSERT( false );
            break;
    }

    return bSuccess;
}

CGenericSocket::ESOCKETTYPE CGenericSocket::Type( void ) const
{
    return m_eSocketType;
}

bool CGenericSocket::IsHealthy( void )
{
    bool bHealthy = false;

    switch ( m_eSocketType )
    {
        case socketTypeDatagram:

            bHealthy = ( ( m_pUDPSocket != NULL ) && IsResponsive() );
            break;

        case socketTypeStream:
            
            bHealthy = ( ( m_pTCPSocket != NULL ) && IsResponsive() );
            break;

        default:

            bHealthy = false;
            break;
    }

    return bHealthy;
}

bool CGenericSocket::IsResponsive( void )
{
#pragma CompileMessage_m( "TODO: ADD LOGIC HERE TO MONITOR DURATION BETWEEN RECEIVED DATA FOR TIMEOUT ... MAY NEED TO IMPLEMENTE AN ACK/NAK SCHEME W/ CLIENT" )

    return true;
}


