#include "gamepad.h"




/***************************************************************************/
/*                                                                         */
/* Details: Determines if the keypad buttons have been pressed             */
/*                                                                         */
/* Auth: x-factor development (http://www.xfactordev.net)                  */
/*                                                                         */
/* Main functions:                                                         */
/* InitGamePad(); - Called at the beginning of the game, to inilize the    */
/*                  gamepads.                                              */
/*                                                                         */
/* GetInput(); - Called each time through the main                         */
/* game loop, it checks for any button presses etc, and fills in the       */
/* m_Gamepad structure                                                     */
/*                                                                         */
/*                                                                         */
/***************************************************************************/

// This header field will be responsible for getting feedback from the
// xbox gamepads



/***************************************************************************/
/*                                                                         */
/* XBInput_CreateGamepads()                                                */
/* Creates the gameapad devices                                            */
/*                                                                         */
/***************************************************************************/

HRESULT CGamePad::CreateGamepads()
{

    // Get a mask of all currently available devices
    DWORD dwDeviceMask = XGetDevices( XDEVICE_TYPE_GAMEPAD );

    // Open the devices
    for( DWORD i=0; i < XGetPortCount(); i++ )
    {
        ZeroMemory( &m_InputStates[i], sizeof(XINPUT_STATE) );
        ZeroMemory( &m_Gamepads[i], sizeof(XBGAMEPAD) );
        if( dwDeviceMask & (1<<i) ) 
        {
            // Get a handle to the device
            m_Gamepads[i].hDevice = XInputOpen( XDEVICE_TYPE_GAMEPAD, i, 
                                                XDEVICE_NO_SLOT, NULL );

            // Store capabilities of the device
            XInputGetCapabilities( m_Gamepads[i].hDevice, &m_Gamepads[i].caps );
        }
    }

    return S_OK;
}




/***************************************************************************/
/*                                                                         */
/* Name: XBInput_GetInput()                                                */
/* Desc: Processes input from the gamepads                                 */
/*                                                                         */
/***************************************************************************/

VOID CGamePad::GetInput( )
{


    XBGAMEPAD* pGamepads = m_Gamepads;

    // TCR 3-21 Controller Discovery
    // Get status about gamepad insertions and removals. Note that, in order to
    // not miss devices, we will check for removed device BEFORE checking for
    // insertions
    DWORD dwInsertions, dwRemovals;
    XGetDeviceChanges( XDEVICE_TYPE_GAMEPAD, &dwInsertions, &dwRemovals );

    // Loop through all gamepads
    for( DWORD i=0; i < XGetPortCount(); i++ )
    {
        // Handle removed devices.
        pGamepads[i].bRemoved = ( dwRemovals & (1<<i) ) ? TRUE : FALSE;
        if( pGamepads[i].bRemoved )
        {
            // if the controller was removed after XGetDeviceChanges but before
            // XInputOpen, the device handle will be NULL
            if( pGamepads[i].hDevice )
                XInputClose( pGamepads[i].hDevice );
            pGamepads[i].hDevice = NULL;
            pGamepads[i].Feedback.Rumble.wLeftMotorSpeed  = 0;
            pGamepads[i].Feedback.Rumble.wRightMotorSpeed = 0;
        }

        // Handle inserted devices
        pGamepads[i].bInserted = ( dwInsertions & (1<<i) ) ? TRUE : FALSE;
        if( pGamepads[i].bInserted ) 
        {
            // TCR 1-14 Device Types
            pGamepads[i].hDevice = XInputOpen( XDEVICE_TYPE_GAMEPAD, i, 
                                               XDEVICE_NO_SLOT, NULL );

            // if the controller is removed after XGetDeviceChanges but before
            // XInputOpen, the device handle will be NULL
            if( pGamepads[i].hDevice )
                XInputGetCapabilities( pGamepads[i].hDevice, &pGamepads[i].caps );
        }

        // If we have a valid device, poll it's state and track button changes
        if( pGamepads[i].hDevice )
        {
            // Read the input state
            XInputGetState( pGamepads[i].hDevice, &m_InputStates[i] );

            // Copy gamepad to local structure
            memcpy( &pGamepads[i], &m_InputStates[i].Gamepad, sizeof(XINPUT_GAMEPAD) );

            // Put Xbox device input for the gamepad into our custom format
            FLOAT fX1 = (pGamepads[i].sThumbLX+0.5f)/32767.5f;
            pGamepads[i].fX1 = ( fX1 >= 0.0f ? 1.0f : -1.0f ) *
                               max( 0.0f, (fabsf(fX1)-XBINPUT_DEADZONE)/(1.0f-XBINPUT_DEADZONE) );

            FLOAT fY1 = (pGamepads[i].sThumbLY+0.5f)/32767.5f;
            pGamepads[i].fY1 = ( fY1 >= 0.0f ? 1.0f : -1.0f ) *
                               max( 0.0f, (fabsf(fY1)-XBINPUT_DEADZONE)/(1.0f-XBINPUT_DEADZONE) );

            FLOAT fX2 = (pGamepads[i].sThumbRX+0.5f)/32767.5f;
            pGamepads[i].fX2 = ( fX2 >= 0.0f ? 1.0f : -1.0f ) *
                               max( 0.0f, (fabsf(fX2)-XBINPUT_DEADZONE)/(1.0f-XBINPUT_DEADZONE) );

            FLOAT fY2 = (pGamepads[i].sThumbRY+0.5f)/32767.5f;
            pGamepads[i].fY2 = ( fY2 >= 0.0f ? 1.0f : -1.0f ) *
                               max( 0.0f, (fabsf(fY2)-XBINPUT_DEADZONE)/(1.0f-XBINPUT_DEADZONE) );

            // Get the boolean buttons that have been pressed since the last
            // call. Each button is represented by one bit.
            pGamepads[i].wPressedButtons = ( pGamepads[i].wLastButtons ^ pGamepads[i].wButtons ) & pGamepads[i].wButtons;
            pGamepads[i].wLastButtons    = pGamepads[i].wButtons;

            // Get the analog buttons that have been pressed or released since
            // the last call.
            for( DWORD b=0; b<8; b++ )
            {
                // Turn the 8-bit polled value into a boolean value
                BOOL bPressed = ( pGamepads[i].bAnalogButtons[b] > XINPUT_GAMEPAD_MAX_CROSSTALK );

                if( bPressed )
                    pGamepads[i].bPressedAnalogButtons[b] = !pGamepads[i].bLastAnalogButtons[b];
                else
                    pGamepads[i].bPressedAnalogButtons[b] = FALSE;
                
                // Store the current state for the next time
                pGamepads[i].bLastAnalogButtons[b] = bPressed;
            }
        }
    }

	CheckResetCall();    
}




/***************************************************************************/
/*                                                                         */
/* "FIRST" function to be called, this function initilises all the         */
/* gamepads, should be called only once at the beginning                   */
/*                                                                         */
/***************************************************************************/

void CGamePad::InitGamePad()
{
	XInitDevices( 0, 0);

	//Create the gamepad devices	
	CreateGamepads();
}


void CGamePad::Rumble(int iWhichGamePad, float m_fLeftMotorSpeed, float m_fRightMotorSpeed)
{
	m_Gamepads[iWhichGamePad].Feedback.Rumble.wLeftMotorSpeed  = WORD( (m_fLeftMotorSpeed/255)  * 65535.0f );
    m_Gamepads[iWhichGamePad].Feedback.Rumble.wRightMotorSpeed = WORD( (m_fRightMotorSpeed/255) * 65535.0f );

	XInputSetState( m_Gamepads[iWhichGamePad].hDevice, &m_Gamepads[iWhichGamePad].Feedback );
}


/***************************************************************************/
/*                                                                         */
/* This function checks for the reset call on controller 1 (ONLY!)         */
/* Call: Left Trigger, Right Trigger, Start button, and Back Button        */
/*                                                                         */
/***************************************************************************/
void CGamePad::CheckResetCall()
{
	// Handle Reset to Dash (L Trig, R Trig + Start + Back)
	if( m_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER] > 0 )
	{
		if( m_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER] > 0 )
		{
			if( m_Gamepads[0].wButtons &  XINPUT_GAMEPAD_START )
			{
				if( m_Gamepads[0].wButtons &  XINPUT_GAMEPAD_BACK )
				{
					LD_LAUNCH_DASHBOARD LaunchData = { XLD_LAUNCH_DASHBOARD_MAIN_MENU };
					XLaunchNewImage( NULL, (LAUNCH_DATA*)&LaunchData );
				}
			}
		}
	}
}
/***************************************************************************/
float CGamePad::fLeftTrigger(int iWhichGamePad)
{
	if(m_Gamepads[iWhichGamePad].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER] > 10)
	return m_Gamepads[iWhichGamePad].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER];
	else return m_Gamepads[iWhichGamePad].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]=0;
}
float CGamePad::fRightTrigger(int iWhichGamePad)
{
	if(m_Gamepads[iWhichGamePad].bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER] > 10)
	return m_Gamepads[iWhichGamePad].bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER];
	else return m_Gamepads[iWhichGamePad].bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER]=0;
}

bool CGamePad::bBlackButtonPressed(int iWhichGamePad)
{
	if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK] )
		return true;
	else
		return false;
}
bool CGamePad::bWhiteButtonPressed( int iWhichGamePad)
{
	if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_WHITE] )
		return true;
	else
		return false;
}

bool CGamePad::bYellowButtonPressed( int iWhichGamePad)
{
	if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_Y] ) // Y button
		return true;
	else
		return false;
}
bool CGamePad::bRedButtonPressed( int iWhichGamePad)
{
	if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_B] )  // B button
		return true;
	else
		return false;
}
bool CGamePad::bBlueButtonPressed( int iWhichGamePad)
{
	if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_X] ) // X Buton
		return true;
	else
		return false;
}
bool CGamePad::bGreenButtonPressed( int iWhichGamePad)
{
	if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_A] ) // A Button
		return true;
	else
		return false;
}

bool CGamePad::bStartButton( int iWhichGamePad)
{
	if(	 m_Gamepads[iWhichGamePad].wButtons &  XINPUT_GAMEPAD_START)
		return true;
	else
		return false;
}
bool CGamePad::bBackButton( int iWhichGamePad)
{
	if(	 m_Gamepads[iWhichGamePad].wButtons &  XINPUT_GAMEPAD_BACK)
		return true;
	else
		return false;
}

//---------------------------------------------------------------------------

float CGamePad::iAnalogStickUp( int iWhichGamePad)
{
	if(m_Gamepads[iWhichGamePad].fY1 > XBINPUT_DEADZONE)
		return m_Gamepads[iWhichGamePad].fY1;
	else
		return 0.0f;
}
float CGamePad::iAnalogStickDown(int iWhichGamePad)
{
	if(	 m_Gamepads[iWhichGamePad].fY1 < -XBINPUT_DEADZONE)
		return  m_Gamepads[iWhichGamePad].fY1;
	else
		return 0.0f;

}
float CGamePad::iAnalogStickLeft(int iWhichGamePad)
{
	if(	 m_Gamepads[iWhichGamePad].fX1 < -XBINPUT_DEADZONE)
		return  m_Gamepads[iWhichGamePad].fX1;
	else
		return 0.0f;
}
float CGamePad::iAnalogStickRight(int iWhichGamePad)
{
	if(	 m_Gamepads[iWhichGamePad].fX1 > XBINPUT_DEADZONE)
		return  m_Gamepads[iWhichGamePad].fX1;
	else
		return 0.0f;
}

//---------------------------------------------------------------------------

bool CGamePad::bButtonPadUp(int iWhichGamePad)
{
	if(  m_Gamepads[iWhichGamePad].wButtons &	XINPUT_GAMEPAD_DPAD_UP)
		return true;
	else
		return false;
}
bool CGamePad::bButtonPadDown( int iWhichGamePad)
{
	if(	 m_Gamepads[iWhichGamePad].wButtons &  XINPUT_GAMEPAD_DPAD_DOWN)
		return true;
	else
		return false;
}
bool CGamePad::bButtonPadRight( int iWhichGamePad)
{
	if(	 m_Gamepads[iWhichGamePad].wButtons &	XINPUT_GAMEPAD_DPAD_RIGHT) 
		return true;
	else
		return false;
}
bool CGamePad::bButtonPadLeft( int iWhichGamePad)
{
	if(	 m_Gamepads[iWhichGamePad].wButtons &	XINPUT_GAMEPAD_DPAD_LEFT)
		return true;
	else
		return false;
}

//[NOTE]
//Single button depresses, e.g. will not repeat. The button has
//to be pressed repeatedly.
//if( m_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_UP)
//if( m_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN)
//if( m_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_LEFT)
//if( m_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
//---------------------------------------------------------------------------



float CGamePad::iRightStickUp( int iWhichGamePad)
{
	if( m_Gamepads[iWhichGamePad].fY2 > XBINPUT_DEADZONE)
		return  m_Gamepads[iWhichGamePad].fY2;
	else
		return 0.0f;
}
float CGamePad::iRightStickDown( int iWhichGamePad)
{
	if( m_Gamepads[iWhichGamePad].fY2 < -XBINPUT_DEADZONE)
		return  m_Gamepads[iWhichGamePad].fY2;
	else
		return 0.0f;
}
float CGamePad::iRightStickLeft( int iWhichGamePad)
{
	if( m_Gamepads[iWhichGamePad].fX2 < -XBINPUT_DEADZONE)
		return  m_Gamepads[iWhichGamePad].fX2;
	else
		return 0.0f;
}
float CGamePad::iRightStickRight( int iWhichGamePad)
{
	if( m_Gamepads[iWhichGamePad].fX2 > XBINPUT_DEADZONE)
		return  m_Gamepads[iWhichGamePad].fX2;
	else
		return 0.0f;
}

