package seng302.Controllers;


import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import seng302.Mock.StreamedRace;
import seng302.Model.*;
import seng302.VisualiserInput;

import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;

/**
 * Created by fwy13 on 15/03/2017.
 */
public class RaceController extends Controller {
    @FXML GridPane canvasBase;

    //user saved data for annotation display
    private ArrayList<Boolean> presetAnno;

    private ResizableRaceCanvas raceMap;
    private ResizableRaceMap raceBoundaries;
    @FXML SplitPane race;
    @FXML CheckBox showFPS;
    @FXML CheckBox showBoatPath;
    @FXML CheckBox showAnnotations;
    @FXML Label timer;
    @FXML Label FPS;
    @FXML Label timeZone;
    @FXML CheckBox showName;
    @FXML CheckBox showAbbrev;
    @FXML CheckBox showSpeed;
    @FXML Button saveAnno;
    @FXML Button showSetAnno;
    @FXML TableView<Boat> boatInfoTable;
    @FXML TableColumn<Boat, String> boatPlacingColumn;
    @FXML TableColumn<Boat, String> boatTeamColumn;
    @FXML TableColumn<Boat, String> boatMarkColumn;
    @FXML TableColumn<Boat, String> boatSpeedColumn;

    /**
     * Updates the ResizableRaceCanvas (raceMap) with most recent data
     *
     * @param boats boats that are to be displayed in the race
     * @see ResizableRaceCanvas
     */
    public void updateMap(ObservableList<Boat> boats) {
        raceMap.setBoats(boats);
        raceMap.update();
        raceBoundaries.draw();
        //stop if the visualiser is no longer running
    }

    /**
     * Updates the array listened by the TableView (boatInfoTable) that displays the boat information.
     *
     * @param race Race to listen to.
     */
    public void setInfoTable(Race race) {
        //boatInfoTable.getItems().clear();
        ObservableList<Boat> startingBoats = race.getStartingBoats();
        boatInfoTable.setItems(race.getStartingBoats());
        boatTeamColumn.setCellValueFactory(cellData -> cellData.getValue().getName());
        boatSpeedColumn.setCellValueFactory(cellData -> cellData.getValue().getVelocityProp());
        boatMarkColumn.setCellValueFactory(cellData -> cellData.getValue().getCurrentLegName());
        boatPlacingColumn.setCellValueFactory(cellData -> cellData.getValue().positionProperty());
    }


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        //listener for fps
        showFPS.selectedProperty().addListener((ov, old_val, new_val) -> {
            if (showFPS.isSelected()) {
                FPS.setVisible(true);
            } else {
                FPS.setVisible(false);
            }
        });
    }

    /**
     * Initializes and runs the race, based on the user's chosen scale factor
     * Currently uses an example racecourse
     *
     * @param visualiserInput input from network
     * @param raceClock The RaceClock to use for the race's countdown/elapsed duration + timezone.
     */
    public void startRace(VisualiserInput visualiserInput, RaceClock raceClock) {
        StreamedRace newRace = new StreamedRace(visualiserInput, this);
        //newRace.initialiseBoats();

        raceMap = new ResizableRaceCanvas(visualiserInput.getCourse());
        raceMap.setMouseTransparent(true);
        raceMap.widthProperty().bind(canvasBase.widthProperty());
        raceMap.heightProperty().bind(canvasBase.heightProperty());
        //raceMap.setBoats(newRace.getStartingBoats());
        raceMap.draw();
        raceMap.setVisible(true);

        canvasBase.getChildren().add(0, raceMap);

        raceBoundaries = new ResizableRaceMap(visualiserInput.getCourse());
        raceBoundaries.setMouseTransparent(true);
        raceBoundaries.widthProperty().bind(canvasBase.widthProperty());
        raceBoundaries.heightProperty().bind(canvasBase.heightProperty());
        raceBoundaries.draw();
        raceBoundaries.setVisible(true);
        canvasBase.getChildren().add(0, raceBoundaries);

        race.setVisible(true);

        //Initialize save annotation array, fps listener, and annotation listeners
        timeZone.setText(raceClock.getTimeZone());
        timer.textProperty().bind(raceClock.durationProperty());
        initializeFPS();
        initializeAnnotations();

        new Thread((newRace)).start();
    }

    public void finishRace(ObservableList<Boat> boats){
        race.setVisible(false);
        parent.enterFinish(boats);
    }


    /**
     * Set the value for the race clock label
     *
     * @param time time that the label will be updated to
     */
    public void setTimer(String time) {
        //timer.setText(time);
    }

    /**
     * Set the value for the fps label
     *
     * @param fps fps that the label will be updated to
     */
    public void setFrames(String fps) {
        FPS.setText((fps));
    }

    /**
     * Set up FPS display at bottom of screen
     */
    private void initializeFPS() {
        showFPS.setVisible(true);
        showFPS.selectedProperty().addListener((ov, old_val, new_val) -> {
            if (showFPS.isSelected()) {
                FPS.setVisible(true);
            } else {
                FPS.setVisible(false);
            }
        });
    }

    /**
     * Set up boat annotations
     */
    private void initializeAnnotations() {
        presetAnno = new ArrayList<>();
        //listener for annotation
        showAnnotations.selectedProperty().addListener((ov, old_val, new_val) -> {
            raceMap.toggleAnnotations();
            raceMap.update();
        });
        //listener for show name in annotation
        showName.selectedProperty().addListener((ov, old_val, new_val) -> {
            raceMap.toggleAnnoName();
            raceMap.update();
        });
        //listener for show abbreviation for annotation
        showAbbrev.selectedProperty().addListener((ov, old_val, new_val) -> {
            raceMap.toggleAnnoAbbrev();
            raceMap.update();
        });

        //listener for show boat path for annotation
        showBoatPath.selectedProperty().addListener((ov, old_val, new_val) -> {
            raceMap.toggleBoatPath();
            raceMap.update();
        });
        //listener to show speed for annotation
        showSpeed.selectedProperty().addListener((ov, old_val, new_val) -> {
            raceMap.toggleAnnoSpeed();
            raceMap.update();
        });
        //listener to save currently selected annotation
        saveAnno.setOnAction(event -> {
            presetAnno.clear();
            presetAnno.add(showName.isSelected());
            presetAnno.add(showAbbrev.isSelected());
            presetAnno.add(showSpeed.isSelected());
            presetAnno.add(showBoatPath.isSelected());
        });
        //listener to show saved annotation
        showSetAnno.setOnAction(event -> {
            if (presetAnno.size() > 0) {
                showName.setSelected(presetAnno.get(0));
                showAbbrev.setSelected(presetAnno.get(1));
                showSpeed.setSelected(presetAnno.get(2));
                showBoatPath.setSelected(presetAnno.get(3));
                raceMap.update();
            }
        });
    }
}
