package simogl.input;

/**
 * This class represents an input action of the application. It can
 * be used to determine whether an input key was pressed 
 * or mouse movement occured.
 * <br>
 * <b>Note: </b>This class was strongly inspired by the 
 * book "Developing Games In Java" by David Brackeen
 * @author Frank Bruns
 *
 */
public class InputAction {

    /**
     * This state is used, to signal that every produced KeyEvent shall be 
     * considered. If a key is held down the whole sequence of KeyEvents
     * will be processed.
    */
    public static final int NORMAL = 0;

    /**
     * This state is used, to represent that only the first KeyEvent
     * shall be considered, if a key is held down and hence a sequence
     * of KeyEvent would be produced.
     */
    public static final int DETECT_INITAL_PRESS_ONLY = 1;

    private static final int STATE_RELEASED = 0;
    private static final int STATE_PRESSED = 1;
    private static final int STATE_WAITING_FOR_RELEASE = 2;

    private String name;
    private int behavior;
    private int amount;
    private int state;

    /**
     * Create a new InputAction using the NORMAL state
     * @param name name of the input action
     */
    public InputAction(String name) {
        this(name, NORMAL);
    }


    /**
     * Create a new InputAction with the specified  behavior 
     * state constant.
     * @param name name of the input action
     * @param behavior InputAction.NORMAL or InputAction.DETECT_INITAL_PRESS_ONLY
     */
    public InputAction(String name, int behavior) {
        this.name = name;
        this.behavior = behavior;
        reset();
    }


    /**
     * Returns the name of this InputAction.
    */
    public String getName() {
        return name;
    }


    /**
     * Resets the input action. The effect of this is, that the input action
     * appears to was never pressed 
     */
    public void reset() {
        state = STATE_RELEASED;
        amount = 0;
    }


    /**
     * Pretends that the key assigned to this input action was pressed once.
     */
    public synchronized void press() {
        press(1);
    }


    /**
     * Pretends that the key assigned to this input action was pressed
     * the specified amount of times or that the mouse was moved a dinstance
     * according to the specified amount
     * @param amount pretended amount of key presses or mouse move distances
     */
    public synchronized void press(int amount) {
        if (state != STATE_WAITING_FOR_RELEASE) {
            this.amount+=amount;
            state = STATE_PRESSED;
        }

    }


    /**
     * Signals that the key assigned to this input action was released
     */
    public synchronized void release() {
        state = STATE_RELEASED;
    }


    /**
     * Returns whether the input action's key was pressed or not 
     * since last checked.
     */
    public synchronized boolean isPressed() {
        return (getAmount() != 0);
    }


    /**
     * Returns either the number of times the input action's key was
     * pressed or the distance the mouse has been moved
    */
    public synchronized int getAmount() {
        int retVal = amount;
        if (retVal != 0) {
            if (state == STATE_RELEASED) {
                amount = 0;
            }
            else if (behavior == DETECT_INITAL_PRESS_ONLY) {
                state = STATE_WAITING_FOR_RELEASE;
                amount = 0;
            }
        }
        return retVal;
    }
}
