StartView.java

package edu.ntnu.idi.idatt.view.entry;

import java.util.List;

import edu.ntnu.idi.idatt.view.components.AbstractView;
import edu.ntnu.idi.idatt.view.util.CssUtils;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;

/**
 * View class for StartView MVC.
 */
public class StartView extends AbstractView<StackPane> {

  // Globlal variables for model implementation
  private TextField nameField;
  private TextField balanceField;
  private Label fileLabel;
  private Label errorLabel;

  // Global buttons for controller implementation
  private VBox newGameWrapper;
  private HBox importCsvWrapper;
  private CheckBox csvPredefinedCheckBox;
  private Button csvButton;
  private Button startButton;

  /**
   * Constructor for StartView.
   */
  public StartView() {
    super(new StackPane());
    this.getInstance().getStyleClass().add("dark");
  }

  /**
   * Overriden method for createContent()
   * 
   * @see AbstractView
   * @return root node.
   */
  @Override
  public Parent createContent() {
    VBox root = new VBox();
    root.getStyleClass().add("light");
    root.setAlignment(Pos.TOP_CENTER);
    StackPane.setMargin(root, new Insets(40.0));

    Label title = new Label("Millions");
    title.getStyleClass().add("title");

    // Create and style wrappers
    VBox wrapper = new VBox();
    newGameWrapper = new VBox();
    HBox playerWrapper = new HBox();
    HBox balanceWrapper = new HBox();
    playerWrapper.setAlignment(Pos.CENTER_LEFT);
    balanceWrapper.setAlignment(Pos.CENTER_LEFT);

    // Player name label and input field
    Label playerName = new Label("Player name:");
    playerName.getStyleClass().add("big-text-32");

    nameField = new TextField();
    nameField.setPromptText("Leonardo Dicaprio");
    nameField.setFocusTraversable(false);
    nameField.getStyleClass().add("button");
    playerWrapper.getChildren().addAll(List.of(playerName, nameField));

    // Start balance label and input field
    Label startBalance = new Label("Start balance:");
    startBalance.getStyleClass().add("big-text-32");

    balanceField = new TextField();
    balanceField.setPromptText("2500");
    balanceField.setFocusTraversable(false);
    balanceField.getStyleClass().add("button");
    balanceWrapper.getChildren().addAll(List.of(startBalance, balanceField));

    // CSV import button and label

    HBox csvPredefinedWrapper = new HBox();
    csvPredefinedWrapper.setAlignment(Pos.CENTER_LEFT);
    VBox.setMargin(csvPredefinedWrapper, new Insets(0.0, 0.0, 0.0, 50.0));
    csvPredefinedCheckBox = new CheckBox();
    csvPredefinedCheckBox.setSelected(true);
    Label predefinedLabel = new Label("Use predefined stock CSV: ");
    predefinedLabel.getStyleClass().add("med-text-16");
    csvPredefinedWrapper.getChildren().addAll(predefinedLabel, csvPredefinedCheckBox);

    importCsvWrapper = new HBox();
    importCsvWrapper.setAlignment(Pos.CENTER_LEFT);

    csvButton = new Button("Import CSV");
    csvButton.getStyleClass().add("button");

    fileLabel = new Label();
    fileLabel.getStyleClass().add("med-text-16");

    importCsvWrapper.getChildren().addAll(csvButton, fileLabel);
    VBox.setMargin(importCsvWrapper, new Insets(0.0, 0.0, 0.0, 50.0));

    // Start game button and error log
    startButton = new Button("Proceed");
    startButton.getStyleClass().add("button");
    startButton.setMaxWidth(200);
    VBox.setMargin(startButton, new Insets(40.0));

    errorLabel = new Label();
    errorLabel.getStyleClass().add("med-text-16");
    errorLabel.setStyle("-fx-text-fill: red;");

    // Region filler
    Region filler = new Region();
    VBox.setVgrow(filler, Priority.ALWAYS);

    // Wrap components together and adjust positioning
    newGameWrapper.getChildren().addAll(balanceWrapper, csvPredefinedWrapper, importCsvWrapper);
    wrapper.getChildren().addAll(playerWrapper, newGameWrapper);
    wrapper.setAlignment(Pos.BASELINE_LEFT);

    root.getChildren().addAll(List.of(title, wrapper, filler, errorLabel, startButton));

    return root;
  }

  /**
   * Setter for StartModel.
   * <p>
   * Binds observable properties and model data.
   * </p>
   */
  public void setModel(StartModel model) {
    this.nameField.textProperty().bindBidirectional(model.getName());
    this.balanceField.textProperty().bindBidirectional(model.getBalance());
    this.errorLabel.textProperty().bind(model.getError());
    this.fileLabel.textProperty().bind(model.getFileName());
    this.newGameWrapper.visibleProperty().bind(model.isNewGame());
    this.newGameWrapper.visibleProperty()
        .addListener((obs) -> this.newGameWrapper.getChildren().forEach(c -> CssUtils.fadeInAnimation(c)));
    this.csvPredefinedCheckBox.selectedProperty().bindBidirectional(model.isPredefinedCSV());

    // Binding importCsvWrapper visibleProperty here for convenience
    this.importCsvWrapper.visibleProperty().bind(csvPredefinedCheckBox.selectedProperty().not());
  }

  /**
   * Setter for StartController.
   * <p>
   * Responds to actions and events for interactibility.
   * </p>
   */
  public void setController(StartController controller) {
    this.csvButton.setOnAction(e -> controller.obtainCSVFile());
    this.startButton.setOnAction(e -> controller.initializeGame());
  }

}