package seng302.Mock;

import seng302.Controllers.RaceController;
import seng302.GPSCoordinate;
import seng302.Model.Boat;
import seng302.Model.Leg;
import seng302.Model.Marker;
import seng302.Model.Race;
import seng302.Networking.Messages.BoatLocation;
import seng302.Networking.Messages.BoatStatus;
import seng302.Networking.Messages.Enums.BoatStatusEnum;
import seng302.VisualiserInput;

/**
 * Created by jjg64 on 21/04/17.
 */
public class StreamedRace extends Race {
    private final VisualiserInput visualiserInput;

    public StreamedRace(VisualiserInput visualiserInput, RaceController controller) {
        super(visualiserInput.getCourse(), controller, 1);
        this.visualiserInput = visualiserInput;
    }

    public void initialiseBoats() {
        Leg officialStart = legs.get(0);
        String name = officialStart.getName();
        Marker endMarker = officialStart.getEndMarker();

        for (int i = 0; i < startingBoats.size(); i++) {
            Boat boat = startingBoats.get(i);
            if (boat != null) {
                Leg startLeg = new Leg(name, 0);
                startLeg.setEndMarker(endMarker);
                boat.setCurrentLeg(startLeg);
            }
        }
    }

    /**
     * Checks if the boat cannot finish the race
     * @return True if boat cannot finish the race
     */
    protected boolean doNotFinish() {
        // DNF is no longer random and is now determined by a dnf packet
        return false;
    }

    /**
     * Checks the position of the boat.
     *
     * @param boat        Boat that the position is to be updated for.
     * @param timeElapsed Time that has elapse since the start of the the race.
     */
    protected void checkPosition(Boat boat, long timeElapsed) {
        StreamedCourse raceData = visualiserInput.getCourse();
        BoatStatus boatStatusMessage = visualiserInput.getBoatStatusMap().get(boat.getSourceID());
        if (boatStatusMessage != null) {
            BoatStatusEnum boatStatusEnum = BoatStatusEnum.fromByte(boatStatusMessage.getBoatStatus());

            int legNumber = boatStatusMessage.getLegNumber();

            if (legNumber >= 1 && legNumber < legs.size()) {
                boat.setCurrentLeg(legs.get(legNumber));
            }

            if (boatStatusEnum == BoatStatusEnum.RACING) {
                boat.addTrackPoint(boat.getCurrentPosition());
            } else if (boatStatusEnum == BoatStatusEnum.DNF) {
                boat.setDnf(true);
            } else if (boatStatusEnum == BoatStatusEnum.FINISHED || legNumber == raceData.getLegs().size()) {
                boatsFinished++;
                boat.setTimeFinished(timeElapsed);
                boat.setFinished(true);
                System.out.println("Boat finished");
            }
        }
        //Update the boat display table in the GUI to reflect the leg change
        updatePositions();
    }

    /**
     * Updates the boat's gps coordinates
     *
     * @param boat to be updated
     * @param millisecondsElapsed time since last update
     */
    protected void updatePosition(Boat boat, int millisecondsElapsed) {
        int sourceID = boat.getSourceID();
        BoatLocation boatLocation = visualiserInput.getBoatLocationMessage(sourceID);
        if(boatLocation != null) {
            double lat = boatLocation.getLatitudeDouble();
            double lon = boatLocation.getLongitudeDouble();
            boat.setCurrentPosition(new GPSCoordinate(lat, lon));
            boat.setHeading(boatLocation.getHeadingDegrees());
            double MMPS_TO_KN = 0.001944;
            boat.setVelocity(boatLocation.getBoatSOG() * MMPS_TO_KN);
        }
    }

    /**
     * sets the position of a boat from coordinate
     * @param boat the boat to set
     * @param coordinate the position of the boat
     */
    protected void setPosition(Boat boat, GPSCoordinate coordinate) {
        boat.setCurrentPosition(coordinate);
    }

}
