package com.brackeen.javagamebook.input;

/**
    Klasa GameAction jest klasą abstrakcyjną dla akcji inicjowanych
    przez użytkownika, na przykład poruszania się lub skakania. Obiekty
    GameAction mogą być kojarzone z klawiszami poprzez InputManager.
*/
public class GameAction {

    /**
        Normalne działanie. Dopóki klawisz jest przyciśnięty,
        metoda isPressed() zwraca wartość true.
    */
    public static final int NORMAL = 0;

    /**
        Początkowa obsługa przyciśnięcia. Metoda isPressed() zwraca
        wartość true jedynie po pierwszym naciśnięciu klawisza.
    */
    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;

    /**
        Tworzenie nowego obiektu GameAction z działaniem NORMAL.
    */
    public GameAction(String name) {
        this(name, NORMAL);
    }

    /**
        Tworzenie nowego obiektu GameAction z podanym działaniem.
    */
    public GameAction(String name, int behavior) {
        this.name = name;
        this.behavior = behavior;
        reset();
    }

    /**
        Zwraca nazwę tego obiektu GameAction.
    */
    public String getName() {
        return name;
    }

    /**
        Kasuje stan obiektu GameAction, dzięki czemu zachowuje 
        się on tak, jakby nie został naciśnięty klawisz.
    */
    public void reset() {
        state = STATE_RELEASED;
        amount = 0;
    }

    /**
        Programowe przyciśnięcie w bieżącym obiekcie GameAction. 
        Ma to samo działanie, co wywołanie press(), a następnie release().
    */
    public synchronized void tap() {
        press();
        release();
    }

    /**
        Sygnalizacja naciśnięcia klawisza.
    */
    public synchronized void press() {
        press(1);
    }

    /**
        Sygnalizacja naciśnięcia klawisza określoną liczbę razy
        lub przesunięcia myszy o określony dystans.
    */
    public synchronized void press(int amount) {
        if (state != STATE_WAITING_FOR_RELEASE) {
            this.amount+=amount;
            state = STATE_PRESSED;
        }
    }

    /**
        Sygnalizuje zwolnienie klawisza.
    */
    public synchronized void release() {
        state = STATE_RELEASED;
    }

    /**
        Zwraca informację o tym, czy od ostatniego sprawdzenia 
        został naciśnięty jakiś klawisz.
    */
    public synchronized boolean isPressed() {
        return (getAmount() != 0);
    }

    /**
        W przypadku klawiszy jest to liczba naciśnięć klawisza 
        od ostatniego sprawdzenia.
        W przypadku przesunięcia myszy jest to odległość.
    */
    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;
    }
}
