// Created by Paul Gonzalez Becerra

using System;
using System.Reflection;

using Saserdote.DataSystems;
using Saserdote.GamingServices;
using Saserdote.Mathematics;

using Tao.Sdl;

namespace Saserdote.Input
{
	public static class GameInput
	{
		#region --- Field Variables ---
		
		// Variables
		private static Game	game;
		private static bool	bFocused;
		internal static KeyboardHelper	khelper;
		internal static MouseHelper	mhelper;
		internal static Gamepad	gamepad;
		private static bool	pUseFocus;
		public static FList<GamepadInfo>	gamepadDetector;
		
		#endregion // Field Variables
		
		#region --- Static Properties ---
		
		// Gets and sets if the mouse should be locked to the center of the viewport
		public static bool bLockCursorToCenter
		{
			get	{	return mhelper.bLockToCenter;	}
			set	{	mhelper.bLockToCenter=	value;	}
		}
		
		// Gets and sets if the cursor should be shown
		public static bool bShowCursor
		{
			get	{	return mhelper.pShowCursor;	}
			set	{	mhelper.bShowCursor=	value;	}
		}
		
		// Gets and sets if the input will shut down if unfocused
		public static bool bUseFocus
		{
			get	{	return pUseFocus;	}
			set
			{
				pUseFocus=	value;
				if(!pUseFocus)
					bFocused=	true;
			}
		}
		
		#endregion // Static Properties
		
		#region --- Static Methods ---
		
		// Initiates the input
		internal static void init(Game pmGame)
		{
			game=	pmGame;
			Sdl.SDL_Init(Sdl.SDL_INIT_JOYSTICK);
			
			game.window.viewport.LostFocus+=	onLostFocus;
			game.window.viewport.GotFocus+=	onGotFocus;
			
			bFocused=	true;
			pUseFocus=	true;
			
			mhelper=	new MouseHelper(game.window.viewport);
			khelper=	new KeyboardHelper(game.window.viewport);
			gamepadDetector=	new FList<GamepadInfo>();
			gamepadDetector.add(new GamepadInfo(15, 0, 3, typeof(Xbox360Gamepad)));
			gamepadDetector.add(new GamepadInfo(12, 1, 2, typeof(PS2Gamepad)));
			
			if(Sdl.SDL_NumJoysticks()> 0)
			{
				gamepad=	getGamepadNoQuit(0);
			}
		}
		
		// Refreshes the gamepads, finding new ones or kicking out old ones
		public static void refreshGamepads()
		{
			gamepad=	getGamepad(0);
		}
		
		// Gets the gamepad with the given player index
		public static Gamepad getGamepad(int playerIndex)
		{
			Sdl.SDL_Quit();
			gamepad=	null;
			Sdl.SDL_Init(Sdl.SDL_INIT_EVERYTHING);
			
			return getGamepadNoQuit(playerIndex);
		}
		
		// Gets the gamepad with the given player index, without quiting the sdl stuffs
		public static Gamepad getGamepadNoQuit(int playerIndex)
		{
			// Variables
			IntPtr	js;
			int	btns;
			int	dps;
			int	sks;
			int	n;
			
			n=	Sdl.SDL_NumJoysticks();
			
			if(n<= 0 || playerIndex> n)
				return null;
			
			js=	Sdl.SDL_JoystickOpen(playerIndex);
			btns=	Sdl.SDL_JoystickNumButtons(js);
			dps=	Sdl.SDL_JoystickNumHats(js);
			sks=	Sdl.SDL_JoystickNumAxes(js)/2;
			
			for(int i= 0; i< gamepadDetector.size; i++)
			{
				if((gamepadDetector[i].numOfButtons== btns) && (gamepadDetector[i].numOfDpads== dps) && (gamepadDetector[i].numOfSticks== sks))
				{
					if(gamepadDetector[i].gamepadType!= null)
					{
						// Variables
						ConstructorInfo	constructor=	gamepadDetector[i].gamepadType.GetConstructor(new Type[]{typeof(IntPtr)});
						
						if(constructor!= null && gamepadDetector[i].gamepadType.IsSubclassOf(typeof(Gamepad)))
						{
							Console.WriteLine("Found Gamepad: "+gamepadDetector[i].gamepadType);
							
							return (Gamepad)(constructor.Invoke(new object[]{js}));
						}
					}
				}
			}
			
			return null;
		}
		
		// Called when the viewport is no longer focused
		private static void onLostFocus(object sender, EventArgs args)
		{
			if(bUseFocus)
				bFocused=	false;
		}
		
		// Called when the viewport has gotten focus
		private static void onGotFocus(object sender, EventArgs args)
		{
			if(bUseFocus)
				bFocused=	true;
		}
		
		// Gets the keyboard's input state
		public static KeyboardState getKeyboardState()
		{
			// Variables
			KeyboardState	keyboard=	new KeyboardState();
			
			keyboard.keysHeld=	khelper.keysHeld.toArray();
			
			return keyboard;
		}
		
		// Gets the mouse's input state
		public static MouseState getMouseState()
		{
			// Variables
			MouseState	mouse=	new MouseState();
			
			mouse.mouseWheel=	mhelper.mouseWheel;
			mouse.buttonsHeld=	mhelper.getHeldButtons();
			mhelper.updateMouseMovement();
			mouse.pMovement=	mhelper.movement;
			mouse.pPosition=	mhelper.currPosition;
			mouse.bLockToCenter=	mhelper.bLockToCenter;
			mouse.pShowCursor=	mhelper.pShowCursor;
			
			return mouse;
		}
		
		// Gets the gamepad's input state
		public static GamepadState getGamepadState()
		{
			// Variables
			GamepadState gpad=	new GamepadState();
			
			gpad.gamepad=	gamepad;
			gpad.update();
			
			
			return gpad;
		}
		
		// Gets the input args
		public static InputArgs getInputArgs()
		{
			if(!bFocused)
				return getEmptyInputArgs();
			
			// Variables
			InputArgs	args=	new InputArgs();
			
			args.keyboard=	getKeyboardState();
			args.mouse=	getMouseState();
			args.gamepad=	getGamepadState();
			
			return args;
		}
		
		// Gets an empty set of input args
		private static InputArgs getEmptyInputArgs()
		{
			// Variables
			InputArgs	args=	new InputArgs();
			
			args.keyboard=	KeyboardState.getEmpty();
			args.mouse=	MouseState.getEmpty();
			args.gamepad=	GamepadState.getEmpty();
			
			return args;
		}
		
		#endregion // Static Methods
	}
}

// End of File