//
// Asura_Controller.h
//
// Created by KOR - 05 October 2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __ASURA_CONTROLLER_H__
#define __ASURA_CONTROLLER_H__

#include "Debugging/Asura_Assert.h"
#include "Input/Asura_Input.h"

const float fASURA_CONTROLLER_INPUT_MAX = 1.f;

class Asura_Controller
{
public:
	// constructor registers itself with Asura_Input and allocates arrays of the correct size.
	Asura_Controller(u_int uControllerIndex, u_int uNumKeys);
	virtual ~Asura_Controller();

	void Update();

	// Accessors for current values
	// Returns a value in the range [0.f, 1.f] depending on how much the key is pressed
	inline float GetKeyValue(u_int uIndex) const
	{
		Asura_Assert(uIndex < m_uNumKeys, "Key index out of range");
		return (uIndex < m_uNumKeys) ? m_pfCurrentKeys[uIndex] : 0.f;
	}
	// Returns true if the key is pressed at all.
	inline bool IsKeyPressed(u_int uIndex) const
	{
		return GetKeyValue(uIndex) > 0.f;
	}

	// Accessors for previous values. I don't expect these will be much use to the end user,
	// but they make the debounced functions nice and tidy.
	// Returns a value in the range [0.f, 1.f] depending on how much the key was pressed last frame
	inline float GetPrevKeyValue(u_int uIndex) const
	{
		Asura_Assert(uIndex < m_uNumKeys, "Key index out of range");
		return (uIndex < m_uNumKeys) ? m_pfPreviousKeys[uIndex] : 0.f;
	}
	// Returns true if the key as pressed at all last frame
	inline bool WasKeyPressed(u_int uIndex) const
	{
		return GetPrevKeyValue(uIndex) > 0.f;
	}

	// Debounced accessors
	// Returns true if the key is pressed but was not pressed last frame
	inline bool IsDebouncedKeyPressed(u_int uIndex) const
	{
		return IsKeyPressed(uIndex) && !WasKeyPressed(uIndex);
	}
	// Returns true if the key was pressed last frame but is not pressed now
	inline bool IsDebouncedKeyNotPressed(u_int uIndex) const
	{
		return !IsKeyPressed(uIndex) && WasKeyPressed(uIndex);
	}

	// Now that we have split axes into two floating point buttons,
	// this function can be used to retrieve the actual axis value
	// from the buttons easily. The advantage of this is that it allows
	// the user to treat a pair digital buttons as an axis as well,
	// simply by changing which enum values we pass into this function.
	inline float GetAxisValue(u_int uPositiveIndex, u_int uNegativeIndex) const
	{
		return GetKeyValue(uPositiveIndex) - GetKeyValue(uNegativeIndex);
	}

	// Any key accessors
	// RWM - 2007-08-31 - Made virtual as Wii needs to override (to prevent gestures counting as keypresses).
	virtual bool HasAnyKeyBeenPressed( void ) const;
	virtual bool DebouncedHasAnyKeyBeenPressed( void ) const;
protected:
	virtual void Platform_Update() {} // doesn't necessarily do anything, but can be over-ridden for platforms that need it.

	inline void SetKeyValue(u_int uKeyIndex, float fValue)
	{
		Asura_Assert(uKeyIndex < m_uNumKeys, "Key index out of range");
		Asura_Assert(0.f <= fValue && fValue <= fASURA_CONTROLLER_INPUT_MAX, "Key value out of range");
		m_pfCurrentKeys[uKeyIndex] = fValue;
	}
	inline void SetAxisValues(u_int uPositiveIndex, u_int uNegativeIndex, float fAxisValue)
	{
		if(fAxisValue >= 0.f)
		{
			SetKeyValue(uPositiveIndex, fAxisValue);
			SetKeyValue(uNegativeIndex, 0.f);
		}
		else
		{
			SetKeyValue(uPositiveIndex, 0.f);
			SetKeyValue(uNegativeIndex, -fAxisValue);
		}
	}

	u_int m_uControllerIndex;
	u_int m_uNumKeys;
	// Arrays of current and previous input, in the range [0.f, 1.f].
	// Current input is filled out by platform implementation
	float* m_pfCurrentKeys;
	// Previous input is copied across each frame before platform update is performed.
	float* m_pfPreviousKeys;
};

#endif//__ASURA_CONTROLLER_H__
