using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public enum ControllerInput
{
    DPadUp,
    DPadDown,
    DPadLeft,
    DPadRight,

    RightStickUp,
    RightStickDown,
    RightStickLeft,
    RightStickRight,

    LeftStickUp,
    LeftStickDown,
    LeftStickLeft,
    LeftStickRight,

    ButtonUp,
    ButtonUpRelease,
    ButtonDown,
    ButtonDownRelease,
    ButtonLeft,
    ButtonLeftRelease,
    ButtonRight,
    ButtonRightRelease,

    TriggerRight,
    TriggerRightUp,
    TriggerLeft,
    TriggerLeftUp,

    BumperRight,
    BumperLeft,

    ButtonLeftStick,
    ButtonRightStick,

    CntSelect,
    CntStart,
}

//http://pastebin.com/4h3CqpYy
//C# RawInput wrapper
//May help with connection/disconnection
//https://www.gamedev.net/blog/1750/entry-2259016-raw-input-api/
//RawInput for gamepad


public class InputManager : MonoBehaviour {

    [SerializeField]
	Controller Controller1;
    [SerializeField]
	Controller Controller2;
    [SerializeField]
	Controller Controller3;
    [SerializeField]
	Controller Controller4;

    //string controllerNames;

	//This should just be a selection of active players
	//Inputable Player1; ect
	/*
public List<Inputable> Player1Objects;
public List<Inputable> Player2Objects;
public List<Inputable> Player3Objects;
public List<Inputable> Player4Objects;
//*/
	[SerializeField]
	Inputable Player1;
	[SerializeField]
	Inputable Player2;
	[SerializeField]
	Inputable Player3;
	[SerializeField]
	Inputable Player4;

	private static InputManager instance = null;
	private GameObject controllerPrefab;
	private GameObject playerPrefab;

	// Use this for initialization
	void Start ()
	{
		/*
		//Debug logs the name of all connected joysticks
			//GetJoystickNames appears to be the only way to test how many joysticks are connected
        for (int i = 0; i < Input.GetJoystickNames().Length; i++)
        {
            Debug.Log(Input.GetJoystickNames()[i]);
        }
		//*/

		//Foreach joystick connected
		for (int i = 0; i < Input.GetJoystickNames().Length; i++)
		{
			Debug.Log("Controller " + i + " = " + Input.GetJoystickNames()[i]);

			Controller controller = GameObject.Instantiate(controllerPrefab).GetComponent<Controller>();
			controller.SetAxisMappings(i);
			AttachController_Priv(controller, i);
			Player player = GameObject.Instantiate(playerPrefab).GetComponent<Player>();
			AttachPlayer_Priv(player, i);
            player.Initialize(i);
        }

	}
	private static InputManager Instance()
	{
		if (instance == null)
		{
			Debug.Log("New InputManager created");
			GameObject manager = new GameObject("[InputManager]");
			instance = manager.AddComponent<InputManager>();
			//DontDestroyOnLoad(manager);
		}

		return instance;
	}

	void Awake()
    {
		Debug.Log("InputManager awake");

		//If instance already exists on another object, destroy this
		//Ensures singleton unicity
		if (instance && instance != this)
		{
			Debug.Log("InputManager Destroyed to ensure unicity");
			Destroy(gameObject);
		}
	}
	
	// Update is called once per frame
	void Update ()
	{

	}

	#region Public Static

	public static void KeyPress(ControllerInput pressedKey, Controller sender)
	{
		Instance().KeyPress_Priv(pressedKey, sender);
	}

	public static void ThumbstickLeft(float vert, float horiz, Controller sender)
	{
		Instance().ThumbstickLeft_Priv(vert, horiz, sender);
	}

	public static void ThumbstickRight(float vert, float horiz, Controller sender)
	{
		Instance().ThumbstickRight_Priv(vert, horiz, sender);
	}

	public static void WakeUp(GameObject _controllerPrefab, GameObject _playerPrefab)
	{
		Instance().WakeUp_Priv(_controllerPrefab, _playerPrefab);
		Debug.Log("ControllerPrefab passed = " + _controllerPrefab);
		
	}

	public static void AttachPlayer(Inputable player, int i)
	{
		Instance().AttachPlayer_Priv(player, i);
	}

	#endregion

	private void KeyPress_Priv(ControllerInput pressedKey, Controller sender)
	{
		//On KeyPress call, call the method equaling the button
		//Inovke allows abstracted method call; can call anything based on the Input enum .toString()
		//as long as the .ToString() matches a method
		if (sender == Controller1)
		{
            Debug.Log("Controller1 sent");
			Player1.Invoke(pressedKey.ToString(), 0);
		}
		if (sender == Controller2)
		{
            Debug.Log("Controller2 sent");
            Player2.Invoke(pressedKey.ToString(), 0);
		}
		if (sender == Controller3)
		{
            Debug.Log("Controller3 sent");
            Player3.Invoke(pressedKey.ToString(), 0);
		}
		if (sender == Controller4)
		{
            Debug.Log("Controller4 sent");
            Player4.Invoke(pressedKey.ToString(), 0);
		}
	}

	private void ThumbstickLeft_Priv(float vert, float horiz, Controller sender)
	{
		if (sender == Controller1)
		{
			Player1.ThumbstickLeft(vert, horiz);
		}
		if (sender == Controller2)
		{
			Player2.ThumbstickLeft(vert, horiz);
		}
		if (sender == Controller3)
		{
			Player3.ThumbstickLeft(vert, horiz);
		}
		if (sender == Controller4)
		{
			Player4.ThumbstickLeft(vert, horiz);
		}
	}

	private void ThumbstickRight_Priv(float vert, float horiz, Controller sender)
	{
		if (sender == Controller1)
		{
			Player1.ThumbstickRight(vert, horiz);
		}
		if (sender == Controller2)
		{
			Player2.ThumbstickRight(vert, horiz);
		}
		if (sender == Controller3)
		{
			Player3.ThumbstickRight(vert, horiz);
		}
		if (sender == Controller4)
		{
			Player4.ThumbstickRight(vert, horiz);
		}
	}

	private void WakeUp_Priv(GameObject _controllerPrefab, GameObject _playerPrefab)
	{
		controllerPrefab = _controllerPrefab;
		playerPrefab = _playerPrefab;
	}

	private void AttachController_Priv(Controller controller, int i)
	{
		//THIS IS THE WORST
		//TODO: Change to List<Controller> and throw callback by instance?
			//Might be more work in button/thumbstick callbacks
			//Could have controller track "player number" and return that on button press instead of "this"
		if (i == 0)
		{
			Controller1 = controller;
		}
		else if (i == 1)
		{
			Controller2 = controller;
		}
		else if (i == 2)
		{
			Controller3 = controller;
		}
		else if (i == 3)
		{
			Controller4 = controller;
		}
	}

	private void AttachPlayer_Priv(Inputable player, int i)
	{
		//THIS IS THE WORST
		//TODO: Change to List<Controller> and throw callback by instance?
		//Might be more work in button/thumbstick callbacks
		//Could have controller track "player number" and return that on button press instead of "this"
		if (i == 0)
		{
			Player1 = player;
		}
		else if (i == 1)
		{
			Player2 = player;
		}
		else if (i == 2)
		{
			Player3 = player;
		}
		else if (i == 3)
		{
			Player4 = player;
		}
	}
}
