package com.brackeen.javagamebook.game;

import com.brackeen.javagamebook.math3D.*;

/**
    GameObject jest klasą bazową dla obiektów dowolnego typu,
    które występują w grze i są przechowywane w obiekcie klasy
    PolygonGroup. Przykładowo, obiekt klasy GameObject może
    reprezentować obiekt statyczny (np. skrzynię), obiekt w
    ruchu (np. pocisk lub przeciwnika) lub dowolny inny typ
    obiektu (np. apteczkę). Obiekty klasy GameObject mają trzy
    podstawowe stany: STATE_IDLE, STATE_ACTIVE lub STATE_DESTROYED.
*/
public class GameObject {

    protected static final int STATE_IDLE = 0;

    protected static final int STATE_ACTIVE = 1;

    protected static final int STATE_DESTROYED = 2;

    private PolygonGroup polygonGroup;
    private PolygonGroupBounds bounds;
    private int state;
    private boolean isJumping;
    private float floorHeight;
    private float ceilHeight;

    /**
        Tworzy nowy obiekt klasy GameObject reprezentowany przez
        wskazany obiekt klasy PolygonGroup. Obiekt PolygonGroup
        może być równy null.
    */
    public GameObject(PolygonGroup polygonGroup) {
        this.polygonGroup = polygonGroup;
        bounds = new PolygonGroupBounds(polygonGroup);
        state = STATE_IDLE;
    }


    /**
        Zwraca położenie tego obiektu GameObject w oparciu o
        metodę klasy Transform3D.
    */
    public Vector3D getLocation() {
        return polygonGroup.getTransform().getLocation();
    }


    /**
        Zwraca informacje o ruchu obiektu.
    */
    public MovingTransform3D getTransform() {
        return polygonGroup.getTransform();
    }


    /**
        Zwraca obiekt PolygonGroup, do którego należy ten obiekt.
    */
    public PolygonGroup getPolygonGroup() {
        return polygonGroup;
    }


    /**
        Zwraca ograniczenia obiektu PolygonGroup.
    */
    public PolygonGroupBounds getBounds() {
        return bounds;
    }


    /**
        Zwraca współrzędną X tego obiektu GameObject.
    */
    public float getX() {
        return getLocation().x;
    }


    /**
        Zwraca współrzędną Y tego obiektu GameObject.
    */
    public float getY() {
        return getLocation().y;
    }


    /**
        Zwraca współrzędną Z tego obiektu GameObject.
    */
    public float getZ() {
        return getLocation().z;
    }


    /**
        Rejestruje wysokość podłogi pod tym obiektem GameObject.
    */
    public void setFloorHeight(float floorHeight) {
        this.floorHeight = floorHeight;
    }


    /**
        Rejestruje wysokość sufitu nad tym obiektem GameObject.
    */
    public void setCeilHeight(float ceilHeight) {
        this.ceilHeight = ceilHeight;
    }


    /**
        Zwraca wysokość podłogi ustawioną za pomocą metody setFloorHeight.
    */
    public float getFloorHeight() {
        return floorHeight;
    }


    /**
        Zwraca wysokość sufitu ustawioną za pomocą metody setCeilHeight.
    */
    public float getCeilHeight() {
        return ceilHeight;
    }


    /**
        Ustawia stan tego obiektu. Dostępne wartości to:
        STATE_IDLE, STATE_ACTIVE lub STATE_DESTROYED.
    */
    protected void setState(int state) {
        this.state = state;
    }


    /**
        Ustawia stan wskazanego obiektu. W ten sposób dowolny obiekt
        GameObject może ustawiać stan dowolnego innego obiektu GameObject.
        Dostępne wartości to: STATE_IDLE, STATE_ACTIVE lub STATE_DESTROYED.
    */
    protected void setState(GameObject object, int state) {
        object.setState(state);
    }


    /**
        Sprawdza, czy ten obiekt GameObject aktualnie leci. Lecące
        obiekty nie powinny podlegać wpływowi siły grawitacji.
        Domyślnie zwraca false.
    */
    public boolean isFlying() {
        return false;
    }


    /**
        Sprawdza, czy dla tego obiektu GameObject jest ustawiona flaga skakania.
        GameObjectManager może inaczej traktować skaczące obiekty.
    */
    public boolean isJumping() {
        return isJumping;
    }


    /**
        Ustawia flagę skakania tego obiektu GameObject.
        GameObjectManager może inaczej traktować skaczące obiekty.
    */
    public void setJumping(boolean b) {
        isJumping = b;
    }


    /**
        Zwraca true, jeśli ten obiekt GameObject jest w stanie bezczynności.
    */
    public boolean isIdle() {
        return (state == STATE_IDLE);
    }


    /**
        Zwraca true, jeśli ten obiekt GameObject jest aktywny.
    */
    public boolean isActive() {
        return (state == STATE_ACTIVE);
    }


    /**
        Zwraca true, jeśli ten obiekt GameObject jest zniszczony.
    */
    public boolean isDestroyed() {
        return (state == STATE_DESTROYED);
    }


    /**
        Jeśli ten GameObject jest w stanie aktywności, metoda
        aktualizuje jego obiekt PolygonGroup. W przeciwnym przypadku,
        metoda nie podejmuje żadnych działań.
    */
    public void update(GameObject player, long elapsedTime) {
        if (isActive()) {
            polygonGroup.update(elapsedTime);
        }
    }


    /**
        Informuje ten GameObject o tym, czy jest widoczny po ostatniej
        aktualizacji. Jeśli GameObject jest w stanie bezczynności i otrzymuje
        informację, że stał się widoczyn, domyślnie przechodzi w stan
        aktywności.
    */
    public void notifyVisible(boolean visible) {
        if (visible && isIdle()) {
            state = STATE_ACTIVE;
        }
    }


    /**
        Informuje ten GameObject, że podczas ruchu wystąpiła kolizja ze
        wskazanym obiektem. Metoda domyślnie nie podejmuje żadnych działań.
    */
    public void notifyObjectCollision(GameObject otherObject) {
        // nic nie rób
    }


    /**
        Informuje ten GameObject, że podczas ruchu wystąpiła kolizja z
        podłogą. Metoda domyślnie nie podejmuje żadnych działań.
    */
    public void notifyFloorCollision() {
        // nic nie rób
    }


    /**
        Informuje ten GameObject, że podczas ruchu wystąpiła kolizja z
        sufitem. Metoda domyślnie nie podejmuje żadnych działań.
    */
    public void notifyCeilingCollision() {
        // nic nie rób
    }


    /**
        Informuje ten GameObject, że podczas ruchu wystąpiła kolizja ze
        ścianą. Metoda domyślnie nie podejmuje żadnych działań.
    */
    public void notifyWallCollision() {
        // nic nie rób
    }

}
