//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:  

Abstract:

Platform independent CPCCard Client Managment functions

Notes: 
--*/
#include <windows.h>
#include <types.h>
#include "cardsv2.h"
#include "socksv2.h"
#include <ceddk.h>
#include "debug.h"
#include "PCClient.h"

CARD_REGISTER_PARMS CCardClient::defaultCardRegisterParms =
{
    0, 0, 0
};
CCardClient:: CCardClient( CLIENT_CALLBACK CallBackFn,
                           PCARD_REGISTER_PARMS pParms ) : m_CallBackFn( CallBackFn )
{
    DEBUGCHK( pParms );
    m_Parms = ( ( pParms ) != NULL ? *pParms : defaultCardRegisterParms );
};

CCardClient::~CCardClient()
{
    Lock();
    Unlock();
}
STATUS CCardClient::EventNotification( UINT32 uEvent,
                                       CARD_SOCKET_HANDLE hSock,
                                       UINT32 Parm1,
                                       UINT32 Parm2 )
{
    STATUS status = CERR_SUCCESS;
    // Notify Every one.
    Lock();
    CARD_EVENT_PARMS mEventParam;
    mEventParam.Parm1 = Parm1;
    mEventParam.Parm2 = Parm2;
    mEventParam.uClientData = m_Parms.uClientData;
    BOOL bCallClient = FALSE;
    switch( uEvent )
    {
      case CE_CARD_READY:
        if( ( m_Parms.fEventMask & EVENT_MASK_CARD_READY ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;
      case CE_CARD_REMOVAL:
      case CE_CARD_INSERTION:
        if( ( m_Parms.fEventMask & EVENT_MASK_CARD_DETECT ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;
      case CE_STATUS_CHANGE_INTERRUPT:
        if( ( m_Parms.fEventMask & EVENT_MASK_STATUS_CHANGE ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;
      case CE_POWER_CYCLE_ON:
      case CE_POWER_CYCLE_OFF:
        if( ( m_Parms.fEventMask & EVENT_MASK_POWER_CYCLE ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;
      case CE_BATTERY_DEAD :
        if( ( m_Parms.fEventMask & EVENT_MASK_BATTERY_DEAD ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;
      case CE_BATTERY_LOW  :
        if( ( m_Parms.fEventMask & EVENT_MASK_BATTERY_DEAD ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;
      case CE_CARD_LOCK :
      case CE_CARD_UNLOCK :
        if( ( m_Parms.fEventMask & EVENT_MASK_CARD_LOCK ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;
      case CE_EJECTION_COMPLETE:
      case CE_EJECTION_REQUEST:
        if( ( m_Parms.fEventMask & EVENT_MASK_EJECT_REQ ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;
      case CE_INSERTION_COMPLETE:
      case  CE_INSERTION_REQUEST:
        if( ( m_Parms.fEventMask & EVENT_MASK_INSERT_REQ ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;
      case CE_PM_RESUME:
      case CE_PM_SUSPEND:
        if( ( m_Parms.fEventMask & EVENT_MASK_POWER_MGMT ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;
      case CE_RESET_PHYSICAL :
      case CE_RESET_REQUEST :
      case CE_CARD_RESET :
      case CE_RESET_COMPLETE:
        if( ( m_Parms.fEventMask & EVENT_MASK_RESET ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;

      case CE_WRITE_PROTECT :
        if( ( m_Parms.fEventMask & EVENT_MASK_WRITE_PROTECT ) != NULL )
        {
            bCallClient = TRUE;
        }
        break;                
      case CE_REGISTRATION_COMPLETE:
      case CE_EXCLUSIVE_COMPLETE :
      case CE_EXCLUSIVE_REQUEST:
      case CE_CARD_BUS_INFO:
      case CE_CARD_UNLOAD_DRIVER:
      case  CE_CARD_LOAD_DRIVER:
        // No event mask associated with those event.   
        bCallClient = TRUE;
        break;
      default:
        break;
    }
    if( m_CallBackFn != NULL && bCallClient )
    {
        __try
        {
            status = ( m_CallBackFn ) ( uEvent, hSock, & mEventParam );
        }
        __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_GENERAL_FAILURE;
        };
    }
    Unlock();
    return status;
}
CClientContainer* CClientContainer::g_pClientContainer = NULL;
extern "C" 
CARD_CLIENT_HANDLE CardRegisterClient( CLIENT_CALLBACK CallBackFn,
                                       PCARD_REGISTER_PARMS pParms )
{
    CCardClient* pCardClient = new CCardClient( CallBackFn, pParms );
    if( pCardClient )
    {
        if( CClientContainer::g_pClientContainer == NULL ||
            CClientContainer::g_pClientContainer->InsertObjectAtEmpty( NULL, pCardClient ) ==  NULL )
        {
            DEBUGMSG( ZONE_ERROR,( TEXT( "CardBus.DLL : Can not inserted new Client!!!\r\n" ) ) );
            delete pCardClient;
        }
        else
        {
            CARD_SOCKET_HANDLE hSocket =
            {
                -1, -1
            };
            pCardClient->EventNotification( CE_REGISTRATION_COMPLETE, hSocket, (UINT32) pCardClient , 0 );
        }
    }
    else
    {
        DEBUGMSG( ZONE_ERROR,( TEXT( "CardBus.DLL : Can not Create new Client!!!\r\n" ) ) );
    }
    return ( CARD_CLIENT_HANDLE ) pCardClient;
}
extern "C"
STATUS CardDeregisterClient( CARD_CLIENT_HANDLE hCardClient )
{
    STATUS status = CERR_SUCCESS;
    CCardClient* pClient = ( CCardClient* ) hCardClient; // Return value by CardRegisterClient
    if( pClient )
    {
        if( CClientContainer::g_pClientContainer ==
            NULL ||
            CClientContainer::g_pClientContainer->RemoveObjectBy( pClient ) ==
            NULL )
        {
            DEBUGCHK( FALSE );
            DEBUGMSG( ZONE_ERROR,
                      ( TEXT( "CardBus.DLL : Can not delete this client %x Client!!!\r\n" ),
                        hCardClient ) );
        }
    }
    return status;
};
STATUS CClientContainer::EventNotification( DWORD dwInterfaceType,
                                            UINT32 uEvent,
                                            CARD_SOCKET_HANDLE hSock,
                                            UINT32 Parm1,
                                            UINT32 Parm2 )
{
    if( g_pClientContainer )
    {
        for( DWORD dwIndex = NUM_CLIENTS - 1;
             dwIndex < NUM_CLIENTS;
             dwIndex-- )
        {
            // Yes. FILO search
            CCardClient* pClient = g_pClientContainer->ObjectIndex( dwIndex );
            if( pClient )
            {
                if( ( dwInterfaceType & CFG_IFACE_CARDBUS ) != 0 )
                {
                    if( ( ( pClient->GetRegisterParam() ).fAttributes & CLIENT_ATTR_CARDBUS_DRIVER ) !=
                        0 )
                        pClient->EventNotification( uEvent,
                                                    hSock,
                                                    Parm1,
                                                    Parm2 );
                }
                else if( ( dwInterfaceType & CFG_IFACE_MEMORY_IO ) !=
                         0 &&
                         ( ( pClient->GetRegisterParam() ).fAttributes & CLIENT_ATTR_IO_DRIVER ) !=
                         0 )
                {
                    pClient->EventNotification( uEvent, hSock, Parm1, Parm2 );
                }
                else if( ( dwInterfaceType & CFG_IFACE_MEMORY ) != 0 )
                {
                    pClient->EventNotification( uEvent, hSock, Parm1, Parm2 );
                }
                pClient->DeRef();
            }
        }
    }
    return CERR_SUCCESS;
}
