package worms.facade;

import worms.model.Worm;
import worms.util.IllegalNameException;
import worms.util.ModelException;
import worms.util.Tuple;

public class Facade implements IFacade {
    /**
     * Create and return a new worm that is positioned at the given location, looks
     * in the given direction, has the given radius and the given name.
     *
     * @param location  
     * 		  An array containing the x-coordinate of the position of the new
     *        worm followed by the y-coordinate of the position of the new worm
     *        (in meter)
     * @param direction 
     *        The direction of the new worm (in radians)
     * @param radius    
     * 		  The radius of the new worm (in meter)
     * @param name
     * 		  the name of the new worm
     * @post  the new worm has the given location, direction, name and radius
     * 		  |new Worm(Tuple.create(location), direction, name, radius)
     * @throws ModelException(e)
     * 		   the worm throws an IllegalArgumentException
     * 		   |catch(IllegalArgumentException e)
     */
    @Override
    public Worm createWorm(double[] location, double direction, double radius, String name) throws ModelException {

        try {
            return new Worm(Tuple.create(location), direction, name, radius);
        }
        catch(IllegalArgumentException e) {
            throw new ModelException(e);
        }


    }

    /**
     * Moves the given worm by the given number of steps.
     * 
     * @param worm
     * 		  the worm who is going to move
     * @param nbSteps
     * 		  the number of steps the worm is going to take
     * @post the worm has taken the given number of steps
     * 		 |worm.move(nbSteps)
     * @throws ModelException(e)
     * 		   the worm throws an IllegalArgumentException
     * 		   |catch(IllegalArgumentException e)
     */
    @Override
    public void move(Worm worm, int nbSteps) throws ModelException {
        try {
            worm.move(nbSteps);
        }
        catch(IllegalArgumentException e) {
            throw new ModelException(e);
        }
    }

    /**
     * Turns the given worm by the given angle.
     * 
     * @param worm
     * 		  the worm who is going to move
     * @param angle
     * 		  the angle the worm should turn
     * @post the worm has turned with the given angle
     * 		 |worm.turn(angle)
     */
    @Override
    public void turn(Worm worm, double angle) throws ModelException {

        worm.turn(angle);
    }

    /**
     * Makes the given worm jump.
     * 
     * @param worm
     * 		  the worm who is going to move
     * @post the worm has jumped
     * @throws ModelException(e)
     * 		   the worm throws an IllegalStateException
     * 		   |catch(IllegalStateException e)
     */
    @Override
    public void jump(Worm worm) throws ModelException {
        try {
            worm.jump();
        }
        catch(IllegalStateException e) {
            throw new ModelException(e);
        }
    }

    /**
     * Returns the total amount of time (in seconds) that a jump of the given worm
     * would take.
     * 
     * @param worm
     * 		  the worm who is going to move
     * @throws ModelException(e)
     * 		   the worm throws an IllegalStateException
     * 		   |catch(IllegalStateException e)
     */
    @Override
    public double getJumpTime(Worm worm) throws ModelException {

        try {
            return worm.jumpTime();
        }
        catch(IllegalStateException e) {
            throw new ModelException(e);
        }
    }

    /**
     * Returns the location on the jump trajectory of the given worm after a time t.
     * 
     * @param worm
     * 		  the worm who is going to move
     * @param t
     * 		  the time the worm should jump
     * @return An array with two elements, with the first element being the
     * 		   x-coordinate and the second element the y-coordinate.
     * @throws ModelException(e)
     * 		   the worm throws an IllegalArgumentException
     * 		   |catch (IllegalArgumentException e)
     */
    @Override
    public double[] getJumpStep(Worm worm, double t) throws ModelException {

        try {
            Tuple<Double, Double> jumpStep = worm.jumpStep(t);
            return new double[]{jumpStep.item1, jumpStep.item2};
        }
        catch (IllegalArgumentException e) {
            throw new ModelException(e);
        }
    }

    /**
     * Returns the x-coordinate of the current location of the given worm.
     * 
     * @param worm
     * 		  the worm who is going to move
     */
    @Override
    public double getX(Worm worm) throws ModelException {
        return worm.getLocation().item1;
    }

    /**
     * Returns the y-coordinate of the current location of the given worm.
     * 
     * @param worm
     * 		  the worm who is going to move
     */
    @Override
    public double getY(Worm worm) throws ModelException {
        return worm.getLocation().item2;
    }

    /**
     * Returns the current orientation of the given worm (in radians).
     * 
     * @param worm
     * 		  the worm who is going to move
     */
    @Override
    public double getOrientation(Worm worm) throws ModelException {
        return worm.getOrientation();
    }

    /**
     * Returns the radius of the given worm.
     * 
     * @param worm
     * 		  the worm who is going to move
     */
    @Override
    public double getRadius(Worm worm) throws ModelException {
        return worm.getRadius();
    }

    /**
     * Sets the radius of the given worm to the given value.
     * 
     * @param worm
     * 		  the worm who is going to move
     * @param newRadius
     * 		  the new radius of the worm
     * @post the new radius is equal to the given newRadius
     * 		 |worm.setRadius(newRadius)
     * @throws ModelException(e)
     * 		   the worm throws an IllegalArgumentException
     * 		   |catch(IllegalArgumentException e)
     */
    @Override
    public void setRadius(Worm worm, double newRadius) throws ModelException {
        try {
            worm.setRadius(newRadius);
        }
        catch(IllegalArgumentException e) {
            throw new ModelException(e);
        }
    }

    /**
     * Returns the current number of action points of the given worm.
     * 
     * @param worm
     * 		  the worm who is going to move
     */
    @Override
    public long getNbActionPoints(Worm worm) throws ModelException {
        return worm.getActionPoints();
    }

    /**
     * Decreases the current number of action points of the given worm with the
     * given delta.
     * 
     * @param worm
     * 		  the worm who is going to move
     * @param delta
     * 		  the value that schould be decreased
     * @post the action points are decreased with delta
     * 		 |worm.decreaseActionPoints((int) delta)
     */
    @Override
    public void decreaseNbActionPoints(Worm worm, long delta) throws ModelException {
        worm.decreaseActionPoints((int) delta);
    }

    /**
     * Returns the maximum number of action points of the given worm.
     * 
     * @param worm
     * 		  the worm who is going to move
     */
    @Override
    public long getMaxNbActionPoints(Worm worm) throws ModelException {
        return worm.getMaxActionPoints();
    }

    /**
     * Returns the name the given worm.
     * 
     * @param worm
     * 		  the worm who is going to move
     */
    @Override
    public String getName(Worm worm) throws ModelException {
        return worm.getName();
    }

    /**
     * Renames the given worm.
     * 
     * @param worm
     *        the worm who is going to move
     * @param newName
     * 		  the new name for the worm
     * @post the new name of the worm is equal to the given newName
     * 		 |worm.setName(newName)
     * @throws ModelException(e)
     * 		   the worm throws an IllegalNameException
     * 		   |catch(IllegalNameException e)
     */
    @Override
    public void rename(Worm worm, String newName) throws ModelException {
        try {
            worm.setName(newName);
        }
        catch(IllegalNameException e) {
            throw new ModelException(e);
        }
    }

    /**
     * Returns the mass of the given worm.
     * 
     * @param worm
     * 		  the worm who is going to move
     */
    @Override
    public double getMass(Worm worm) throws ModelException {
        return worm.getMass();
    }
}
