/*
 * InputController.java
 *
 * This class buffers in input from the devices and converts it into its
 * semantic meaning. If your game had an option that allows the player to
 * remap the control keys, you would store this information in this class.
 * That way, the main GameEngine does not have to keep track of the current
 * key mapping.
 *
 * This class is a singleton for this application.
 *
 * Author: Walker M. White
 * Based on original Parallax Sample by Don Holden, 2007
 * LibGDX version, 2/28/2015
 */
package edu.cornell.gdiac.parallax;

import com.badlogic.gdx.*;
import com.badlogic.gdx.utils.Array;
import edu.cornell.gdiac.util.*;

/**
 * Class for reading player input. 
 *
 * This supports both a keyboard and X-Box controller. In previous solutions, we only 
 * detected the X-Box controller on start-up.  This class allows us to hot-swap in
 * a controller via the new XBox360Controller class.
 */
public class InputController {
	// Speed limitations for controller the car
	private static final float MAX_SPEED  = 15.0f;
	private static final float BASE_ACCEL =  0.5f;

	/** Reference to the controller singleton */
	private static InputController theController = null;
	
	/**
	 * Return a reference to the controller
	 * 
	 * This method will allocate the controller the first time it is
	 * called.  This allows us to delay initialization of the controller
	 * until the game engine is active.
	 * 
	 * @return a reference to the controller
	 */
	public static InputController getInstance() {
		if (theController == null) {
			theController = new InputController();
		}
		return theController;
	}
	
	/** The only thing we can do other than move is exit. */
	private boolean exit;

    // Fields to manage car movement
	/** How much did we move? */
    private float speed;		
    /** Should we accelerate? */
    private boolean accel;
    /** Should we decelerate? */
    private boolean decel;
	
	/** An X-Box controller (if it is connected) */
	private XBoxController xbox;
	
	/**
	 * Returns the amount of sideways movement. 
	 *
	 * -1 = left, 1 = right, 0 = still
	 *
	 * @return the amount of sideways movement. 
	 */
	public float getSpeed() {
		return speed;
	}
	
	
	/**
	 * Returns true if the exit button was pressed.
	 *
	 * @return true if the exit button was pressed.
	 */
	public boolean didExit() {
		return exit;
	}
	
	/**
	 * Creates a new input controller
	 * 
	 * The input controller attempts to connect to the X-Box controller at device 0,
	 * if it exists.  Otherwise, it falls back to the keyboard control.
	 */
	public InputController() { 
		// If we have a game-pad for id, then use it.
		Array<XBoxController> controllers = Controllers.get().getXBoxControllers();
		if (controllers.size > 0) {
			xbox = controllers.get( 0 );
		} else {
			xbox = null;
		}
	}

	/**
	 * Reads the input for the player and converts the result into game logic.
	 */
	public void readInput() {
		// Check to see if a GamePad is connected
		if (xbox != null && xbox.isConnected()) {
			readGamepad();
			readKeyboard(true); // Read as a back-up
		} else {
			readKeyboard(false);
		}

		// Don't allow both accel and decel
        boolean both = accel && decel;
        accel &= !both;
        decel &= !both;

		// Adjust the speed            
		if (accel && speed < MAX_SPEED || speed < 0 && !decel) {
            speed += BASE_ACCEL;
        }
        
        if (decel && speed > -MAX_SPEED || speed > 0 && !accel) {
            speed -= BASE_ACCEL;
        }

	}

	/**
	 * Reads input from an X-Box controller connected to this computer.
	 */
	private void readGamepad() {
		exit = xbox.getBack();

		// Check the acceleration
		accel = xbox.getRightX() > 0;
		decel = xbox.getRightX() < 0;
	}

	/**
	 * Reads input from the keyboard.
	 *
	 * @param secondary true if the keyboard should give priority to a gamepad
	 */
	private void readKeyboard(boolean secondary) {
		// Give priority to gamepad results
		exit  = (secondary && exit) || (Gdx.input.isKeyPressed(Input.Keys.ESCAPE));
		
		// Directional controls
		accel = (secondary ? accel : Gdx.input.isKeyPressed(Input.Keys.RIGHT));
		decel = (secondary ? decel : Gdx.input.isKeyPressed(Input.Keys.LEFT));
	}
}
