////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////

package pp.battleship.client.gui;

import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
import pp.battleship.model.Battleship;

import static pp.util.FloatMath.DEG_TO_RAD;
import static pp.util.FloatMath.TWO_PI;
import static pp.util.FloatMath.sin;

/**
 * Controls the oscillating pitch motion of a battleship model in the game.
 * The ship oscillates to simulate a realistic movement on water, based on its orientation and length.
 */
class ShipControl extends AbstractControl {
    /**
     * The axis of rotation for the ship's pitch (tilting forward and backward).
     */
    private final Vector3f axis;

    /**
     * The duration of one complete oscillation cycle in seconds.
     */
    private final float cycle;

    /**
     * The amplitude of the pitch oscillation in radians, determining how much the ship tilts.
     */
    private final float amplitude;

    /**
     * A quaternion representing the ship's current pitch rotation.
     */
    private final Quaternion pitch = new Quaternion();

    /**
     * The current time within the oscillation cycle, used to calculate the ship's pitch angle.
     */
    private float time;

    /**
     * Constructs a new ShipControl instance for the specified Battleship.
     * The ship's orientation determines the axis of rotation, while its length influences
     * the cycle duration and amplitude of the oscillation.
     *
     * @param ship the Battleship object to control
     */
    public ShipControl(Battleship ship) {
        // Determine the axis of rotation based on the ship's orientation
        axis = switch (ship.getRot()) {
            case LEFT, RIGHT -> Vector3f.UNIT_X;
            case UP, DOWN -> Vector3f.UNIT_Z;
        };

        // Set the cycle duration and amplitude based on the ship's length
        cycle = ship.getLength() * 2f;
        amplitude = 5f * DEG_TO_RAD / ship.getLength();
    }

    /**
     * Updates the ship's pitch oscillation each frame. The ship's pitch is adjusted
     * to create a continuous tilting motion, simulating the effect of waves.
     *
     * @param tpf time per frame (in seconds), used to calculate the new pitch angle
     */
    @Override
    protected void controlUpdate(float tpf) {
        // If spatial is null, do nothing
        if (spatial == null) return;

        // Update the time within the oscillation cycle
        time = (time + tpf) % cycle;

        // Calculate the current angle of the oscillation
        final float angle = amplitude * sin(time * TWO_PI / cycle);

        // Update the pitch Quaternion with the new angle
        pitch.fromAngleAxis(angle, axis);

        // Apply the pitch rotation to the spatial
        spatial.setLocalRotation(pitch);
    }

    /**
     * This method is called during the rendering phase, but it does not perform any
     * operations in this implementation as the control only influences the spatial's
     * transformation, not its rendering process.
     *
     * @param rm the RenderManager rendering the controlled Spatial (not null)
     * @param vp the ViewPort being rendered (not null)
     */
    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {
        // No rendering logic is needed for this control
    }
}
