package de.thdeg.greiner.superpangworld.graphics.base;

import de.thdeg.greiner.superpangworld.game.managers.GamePlayManager;
import de.thdeg.greiner.superpangworld.gameview.GameView;

import java.util.Objects;

/**
 * A basic game object.
 */
public abstract class GameObject implements Cloneable{

    /** The game view to display the game object on. */
    protected final GameView gameView;
    /** The position of the game object. */
    protected Position position;
    /** The size of the game object. */
    protected double size;
    /** The speed in pixel per tick of the game object. */
    protected double speedInPixel;
    /** The rotation of the game object. */
    protected double rotation;
    /** The width of the game object. */
    protected int width;
    /** The height of the game object. */
    protected int height;
    /** The responsible GamePlayManager */
    protected GamePlayManager gamePlayManager;

    /**
     * Create a game object with default values.
     *
     * @param gameView the gameView
     */
    protected GameObject(GameView gameView){
        this.gameView = gameView;
        position = new Position(0,0);
    }

    /**
     * Add the game object to the canvas.
     */
    public abstract void addToCanvas();

    /**
     * Updates the game object's status.
     */
    protected abstract void updateStatus();

    /**
     * Update the status and the position is applicable.
     */
    public void update(){
        if(this instanceof MovingGameObject ){
            if(!(Bubble.class.isAssignableFrom(this.getClass()) && gamePlayManager.movementFroze)){
                ((MovingGameObject)this).updatePosition();
            }
        }
        updateStatus();
    }

    /**
     * Set the responsible GamePlayManager.
     *
     * @param gamePlayManager the responsible GamePlayManager
     */
    public void setGamePlayManager(GamePlayManager gamePlayManager){
        this.gamePlayManager = gamePlayManager;
    }

    /**
     * Get the position of the game object.
     *
     * @return the position
     */
    public Position getPosition(){
        return position;
    }

    /**
     * Set the position with x and y coordinates.
     *
     * @param x the new x coordinate
     * @param y the new y coordinate
     */
    public void setPosition(double x, double y){
        position.x = x;
        position.y = y;
    }

    /**
     * Adapts the position of this game object, in case the whole game world is moved.
     *
     * @param adaptX Adaption to the right.
     * @param adaptY Adaption downwards.
     */
    public void adaptPosition(double adaptX, double adaptY){
        position.x += adaptX;
        position.y += adaptY;
    }

    @Override
    public GameObject clone() {
        GameObject gameObject = null;
        try {
            gameObject = (GameObject) super.clone();
            gameObject.position = position.clone();
        } catch (CloneNotSupportedException ignored) {
        }
        return gameObject;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        GameObject that = (GameObject) o;
        return Double.compare(that.speedInPixel, speedInPixel) == 0
                && Double.compare(that.rotation, rotation) == 0
                && Double.compare(that.size, size) == 0 && width == that.width
                && height == that.height && position.equals(that.position);
    }

    @Override
    public int hashCode() {
        return Objects.hash(position, speedInPixel, rotation, size, width, height);
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + ": " + position;
    }

}
