package dev.llan.view.game;
import dev.llan.controller.Controller;
import dev.llan.model.GameRecord;
import dev.llan.model.pieces.Entity;
import dev.llan.view.RenderComponent;
import dev.llan.view.GameComponent;
import dev.llan.view.View;
import dev.llan.view.game.map.Direction.*;
import dev.llan.view.game.map.MapView;
import dev.llan.view.game.utilities.UtilitiesView;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.util.Duration;
import static dev.llan.view.game.map.Constants.MAP_PROPORTION;
import static dev.llan.view.game.map.Constants.MARGIN;
public class GameView implements RenderComponent, GameComponent {
private final HBox box;
private final StackPane mapContainer;
private final StackPane utilContainer;
private final MapView mapView;
private final UtilitiesView utilView;
private boolean controlsEnabled;
private boolean shouldScroll;
private Scene scene;
private View view;
private Controller controller;
private GameRecord gameRecord;
private Timeline timeline;
public GameView(View view, Controller controller, Scene scene, Pane parent) {
this.scene = scene;
this.view = view;
this.controller = controller;
box = new HBox();
box.prefWidthProperty().bind(parent.widthProperty());
box.maxWidthProperty().bind(parent.widthProperty());
box.minWidthProperty().bind(parent.widthProperty());
box.prefHeightProperty().bind(parent.heightProperty());
box.maxHeightProperty().bind(parent.heightProperty());
box.minHeightProperty().bind(parent.heightProperty());
mapContainer = new StackPane();
utilContainer = new StackPane();
mapView = new MapView(view, controller, mapContainer);
utilView = new UtilitiesView(view, controller, utilContainer);
mapContainer.minWidthProperty().bind(box.widthProperty().multiply(MAP_PROPORTION));
mapContainer.prefWidthProperty().bind(box.widthProperty().multiply(MAP_PROPORTION));
mapContainer.maxWidthProperty().bind(box.widthProperty().multiply(MAP_PROPORTION));
mapContainer.minHeightProperty().bind(box.heightProperty());
mapContainer.prefHeightProperty().bind(box.heightProperty());
mapContainer.maxHeightProperty().bind(box.heightProperty());
utilContainer.minWidthProperty().bind(box.widthProperty().multiply(1 - MAP_PROPORTION));
utilContainer.prefWidthProperty().bind(box.widthProperty().multiply(1 - MAP_PROPORTION));
utilContainer.maxWidthProperty().bind(box.widthProperty().multiply(1 - MAP_PROPORTION));
utilContainer.minHeightProperty().bind(box.heightProperty());
utilContainer.prefHeightProperty().bind(box.heightProperty());
utilContainer.maxHeightProperty().bind(box.heightProperty());
mapContainer.getChildren().add(mapView.getRoot());
utilContainer.getChildren().add(utilView.render());
box.getChildren().add(mapContainer);
box.getChildren().add(utilContainer);
}
public void setScrolling(boolean shouldScroll) {
this.shouldScroll = shouldScroll;
}
public void initHandlers() {
shouldScroll = true;
controlsEnabled = true;
scene.setOnMouseMoved(mouseEvent -> handleMouseMoved(mouseEvent));
scene.setOnKeyPressed(keyEvent -> handleKeyPress(keyEvent));
mapView.initListeners(mapContainer);
timeline = getTimeline();
timeline.play();
}
public void removeHandlers() {
shouldScroll = false;
scene.setOnMouseMoved(mouseEvent -> {});
scene.setOnKeyPressed(keyEvent -> {});
timeline.stop();
}
@Override
public void updateGameRecord(GameRecord gameRecord) {
this.gameRecord = gameRecord;
mapView.updateGameRecord(gameRecord);
utilView.updateGameRecord(gameRecord);
}
public void setControlsEnabled(boolean enabled) {
this.controlsEnabled = enabled;
}
@Override
public Parent render() {
return box;
}
private void handleMouseMoved(MouseEvent e) {
if (controlsEnabled && shouldScroll) {
double x = e.getX();
double y = e.getY();
double mapWidth = scene.getWidth();
double mapHeight = scene.getHeight();
if (x < MARGIN) {
mapView.setXScrollDirection(XScrollDirection.LEFT);
} else if (x > mapWidth - MARGIN && x < mapWidth) {
mapView.setXScrollDirection(XScrollDirection.RIGHT);
} else {
mapView.setXScrollDirection(XScrollDirection.NONE);
}
if (y < MARGIN && x < mapWidth) {
mapView.setYScrollDirection(YScrollDirection.UP);
} else if (y > mapHeight - MARGIN && x < mapWidth) {
mapView.setYScrollDirection(YScrollDirection.DOWN);
} else {
mapView.setYScrollDirection(YScrollDirection.NONE);
}
} else {
mapView.setXScrollDirection(XScrollDirection.NONE);
mapView.setYScrollDirection(YScrollDirection.NONE);
}
}
private void handleKeyPress(KeyEvent keyEvent) {
if(controlsEnabled) {
KeyCode code = keyEvent.getCode();
switch (code) {
case ESCAPE -> {
if (view.getModalManager().isCollectionModalOn()) {
view.getModalManager().setCollectionModalOn(false);
}
if (view.getModalManager().isCardModalOn()) {
view.getModalManager().setCardModalOn(false, null);
}
if (view.getModalManager().isEntityModalOn()) {
view.getModalManager().setEntityModalOn(false, null);
}
if (view.getModalManager().isEquipmentModalOn()) {
view.getModalManager().setEquipmentModalOn(false, null);
}
if (view.getModalManager().isStatusModalOn()) {
view.getModalManager().setStatusModalOn(false, null);
}
controller.cancelSelectedCard();
}
case C -> view.getModalManager().setCollectionModalOn(true);
case F -> mapView.setViewPoint(gameRecord.getPlayer().getPosition());
}
if (gameRecord.getCurrentTurn().isPresent()) {
Entity currentTurn = gameRecord.getCurrentTurn().get();
if (currentTurn == gameRecord.getPlayer()) {
switch (code) {
case E -> controller.endTurn();
case W -> controller.waitTurn();
}
}
}
}
}
private Timeline getTimeline() {
Timeline timeline =
new Timeline(
new KeyFrame(
Duration.millis(20),
e -> {
if (gameRecord != null && controlsEnabled) {
mapView.periodic();
}
}));
timeline.setCycleCount(Animation.INDEFINITE);
return timeline;
}
}