#include "core/config.h"
#include "usbapp/usb_application_switch.h"
#include "usb/usb_bridge.h"
#include "usb/usb_config.h"
#include "usbd_vendor.h"
#if CONFIG_NFMBASECLASS
#include "app/nfm/nfm_base.h"
#elif CONFIG_KEYSW
#include "drivers/keycontrol/keycontrol.h"
#endif

#define  PROTO_REQ_GET_KEY_STAT           0x04   // считать состояние ключей
#define  PROTO_REQ_SET_KEY_STAT           0x05   // записать состояние ключей
#define  PROTO_REQ_GET_KEY_STAT2          0xF0   // прочесть управляющий код выданный на ключи

#define  PROTO_REQ_AMP_KEY_STAT           0x05   // Записать состояние усилителей
#define  PROTO_REQ_FILT_KEY_STAT          0x0C   // Записать состояние фильтров
#define  PROTO_REQ_AMP_KEY_READ           0x0D   // Считать состояние усилителей
#define  PROTO_REQ_FILT_KEY_READ          0x0E   // Считать состояние фильтров

static int8_t fSwitchAppInit();
static int8_t fSwitchAppDeInit();
static void   fSwitchAppReset();
static bool   fSwitchAppSetup( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success );
static size_t fSwitchAppControlRx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining );
static size_t fSwitchAppControlTx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining );

const sUSBAppEntry_Control_t usbapplication_ACM_planarproto_switch = {

     .fUsbInit     = fSwitchAppInit,
     .fUsbDeInit   = fSwitchAppDeInit,
     .fUsbSetup    = fSwitchAppSetup,
     .fUsbCtlEpRx  = fSwitchAppControlRx,
     .fUsbCtlEpTx  = fSwitchAppControlTx,
     .fResetEvent  = fSwitchAppReset,
};
 
static int8_t fSwitchAppInit()
{
    return 0;
}

static int8_t fSwitchAppDeInit()
{
    return 0;
}

static void fSwitchAppReset()
{

}

static bool fSwitchAppSetup( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success )
{
    switch( pSetup->bRequest )
    {
        case PROTO_REQ_GET_KEY_STAT2:
        case PROTO_REQ_GET_KEY_STAT:
        {
             return true;
        }
        break;

        case PROTO_REQ_AMP_KEY_STAT:
        {
            eNFMAmpState_t state = (eNFMAmpState_t)pSetup->wValue;
            if( ! NFMClass->methods.checkAmpStateAvailable( state ))
            {
                return false; // Key State unavailable in this device
            }
            else if( ! NFMClass->methods.keyStatesMethods.setAmpStateCommon( state ))
            {
                return false; // Key Switch Error
            }
            return true;
        }break;
        case PROTO_REQ_FILT_KEY_STAT:
        {
            eNFMFiltState_t state = (eNFMFiltState_t)pSetup->wValue;
            if( ! NFMClass->methods.checkFiltStateAvailable( state ))
            {
                return false; // Key State unavailable in this device
            }
            else if( ! NFMClass->methods.keyStatesMethods.setFiltStateCommon( state ))
            {
                return false; // Key Switch Error
            }
            return true;
        }break;
        
        case PROTO_REQ_AMP_KEY_READ:
        {
            return true;
        }break;
        
        case PROTO_REQ_FILT_KEY_READ:
        {
            return true;
        }break;
//             #if CONFIG_NFMBASECLASS
//               uint32_t dwCode = (((uint32_t)pSetup->wIndex)<<16ul) | (uint32_t)pSetup->wValue;
//               return NFMClass->methods.keyStatesMethods.setKeyStateLegacy( dwCode );
//             #elif CONFIG_KEYSW
//               #error Программа отправляет код в виде wIndex wValue
//               tKeySwitchState_t state = KEYSWITCH_LEGACYSTATE_2_STATE( pSetup->wValue );
//               return KeySwitchHandle.SetKeyState( state );
//             #else
//               return false;
//             #endif
        }
    return false;
}

static size_t fSwitchAppControlRx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining )
{
    return 0;
}

static size_t fSwitchAppControlTx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining )
{
    switch( pSetup->bRequest )
    {
        #if CONFIG_NFMBASECLASS

        case PROTO_REQ_GET_KEY_STAT2: // read the raw lowlevel control code
        {
             if( 0 == idx && sizeof(uint32_t) == bytesRemaining )
             {
                 uint32_t code = NFMClass->methods.keyStatesMethods.getRawKeyControlCode();

                 usb_push_transfer( tx, &code, sizeof( code ) );
             }
        }
        break;

        case PROTO_REQ_GET_KEY_STAT:
        {
             if( 0 == idx && sizeof(uint16_t) == bytesRemaining )
             {
                 uint16_t lstate = 0;
                 uint32_t state = 0;

                 if( NFMClass->methods.keyStatesMethods.getKeyStateLegacy( &state ) )
                 {
                     lstate = (uint16_t)state; // in 2-port ACM only lower 16-bit are used

                     usb_push_transfer( tx, &lstate, sizeof( lstate ) );
                 }
             }
        }
        break;
        
        case PROTO_REQ_AMP_KEY_READ:
        {
            if( 0 == idx && sizeof(uint16_t) == bytesRemaining )
             {
                 uint16_t currentState =  (uint16_t)NFMClass->methods.keyStatesMethods.getAmpStateCommon();
                 usb_push_transfer( tx, &currentState, sizeof( currentState ) );
             }
        }
        break;
        
        case PROTO_REQ_FILT_KEY_READ:
        {
            if( 0 == idx && sizeof(uint16_t) == bytesRemaining )
             {
                 uint16_t currentState =  (uint16_t)NFMClass->methods.keyStatesMethods.getFiltStateCommon();
                 usb_push_transfer( tx, &currentState, sizeof( currentState ) );
             }
        }
        break;
        
        #elif CONFIG_KEYSW
        case PROTO_REQ_GET_KEY_STAT2:
        {
             if( 0 == idx && sizeof(tKeySwitchCode_t) == bytesRemaining )
             {
                 tKeySwitchCode_t code;

                 if( KeySwitchHandle.GetKeyCode( &code ) )
                 {
                     usb_push_transfer( tx, &code, sizeof( code ) );
                 }
             }
        }
        break;

        case PROTO_REQ_GET_KEY_STAT:
        {
             if( 0 == idx && sizeof(tKeySwitchStateLegacy_t) == bytesRemaining )
             {
                 tKeySwitchStateLegacy_t lstate;
                 tKeySwitchState_t state;

                 if( KeySwitchHandle.GetKeyState( &state ) )
                 {
                     lstate = KEYSWITCH_STATE_2_LEGACYSTATE( state );

                     usb_push_transfer( tx, &lstate, sizeof( lstate ) );
                 }
             }
        }
        break;
        #endif
    }

    return usb_count_transfer( tx );
}
