package com.faforever.client.game;
import com.faforever.client.i18n.I18n;
import com.faforever.client.map.MapService;
import com.faforever.client.notification.NotificationService;
import com.faforever.client.preferences.PreferencesService;
import com.faforever.client.remote.domain.GameState;
import com.google.common.annotations.VisibleForTesting;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import static javafx.beans.binding.Bindings.createObjectBinding;
import static javafx.beans.binding.Bindings.createStringBinding;
public class GamesController {
private static final Collection<String> HIDDEN_FEATURED_MODS = Arrays.asList(
GameType.COOP.getString(),
GameType.LADDER_1V1.getString(),
GameType.GALACTIC_WAR.getString(),
GameType.MATCHMAKER.getString()
);
private static final Predicate<GameInfoBean> OPEN_CUSTOM_GAMES_PREDICATE = gameInfoBean ->
gameInfoBean.getStatus() == GameState.OPEN
&& !HIDDEN_FEATURED_MODS.contains(gameInfoBean.getFeaturedMod());
@FXML
ToggleButton tableButton;
@FXML
ToggleButton tilesButton;
@FXML
ToggleGroup viewToggleGroup;
@FXML
VBox teamListPane;
@FXML
Label mapLabel;
@FXML
Button createGameButton;
@FXML
Pane gameViewContainer;
@FXML
Node gamesRoot;
@FXML
ImageView mapImageView;
@FXML
Label gameTitleLabel;
@FXML
Label numberOfPlayersLabel;
@FXML
Label hostLabel;
@FXML
Label gameTypeLabel;
@FXML
ScrollPane gameDetailPane;
@Resource
ApplicationContext applicationContext;
@Resource
I18n i18n;
@Resource
GameService gameService;
@Resource
MapService mapService;
@Resource
CreateGameController createGameController;
@Resource
EnterPasswordController enterPasswordController;
@Resource
PreferencesService preferencesService;
@Resource
NotificationService notificationService;
private FilteredList<GameInfoBean> filteredItems;
private Stage mapDetailPopup;
private GameInfoBean currentGameInfoBean;
private InvalidationListener teamsChangeListener;
@PostConstruct
void postConstruct() {
ObservableList<GameInfoBean> gameInfoBeans = gameService.getGameInfoBeans();
filteredItems = new FilteredList<>(gameInfoBeans);
filteredItems.setPredicate(OPEN_CUSTOM_GAMES_PREDICATE);
if (tilesButton.getId().equals(preferencesService.getPreferences().getGamesViewMode())) {
viewToggleGroup.selectToggle(tilesButton);
tilesButton.getOnAction().handle(null);
} else {
viewToggleGroup.selectToggle(tableButton);
tableButton.getOnAction().handle(null);
}
viewToggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
preferencesService.getPreferences().setGamesViewMode(((ToggleButton) newValue).getId());
preferencesService.storeInBackground();
});
setSelectedGame(null);
}
@FXML
void onShowPrivateGames(ActionEvent actionEvent) {
CheckBox checkBox = (CheckBox) actionEvent.getSource();
boolean selected = checkBox.isSelected();
if (selected) {
filteredItems.setPredicate(OPEN_CUSTOM_GAMES_PREDICATE);
} else {
filteredItems.setPredicate(OPEN_CUSTOM_GAMES_PREDICATE.and(gameInfoBean -> !gameInfoBean.getPasswordProtected()));
}
}
@FXML
void onCreateGameButtonClicked(ActionEvent actionEvent) {
if (preferencesService.getPreferences().getForgedAlliance().getPath() == null) {
preferencesService.letUserChooseGameDirectory()
.thenAccept(path -> {
if (path != null) {
onCreateGameButtonClicked(actionEvent);
}
});
return;
}
Bounds screenBounds = createGameButton.localToScreen(createGameButton.getBoundsInLocal());
createGameController.show(gamesRoot.getScene().getWindow(), screenBounds.getMinX(), screenBounds.getMaxY());
}
private Stage getMapDetailPopup() {
if (mapDetailPopup == null) {
mapDetailPopup = new Stage(StageStyle.TRANSPARENT);
mapDetailPopup.initModality(Modality.NONE);
mapDetailPopup.initOwner(getRoot().getScene().getWindow());
}
return mapDetailPopup;
}
public Node getRoot() {
return gamesRoot;
}
@FXML
void onTableButtonClicked() {
GamesTableController gamesTableController = applicationContext.getBean(GamesTableController.class);
gamesTableController.selectedGameProperty()
.addListener((observable, oldValue, newValue) -> setSelectedGame(newValue));
Platform.runLater(() -> {
gamesTableController.initializeGameTable(filteredItems);
Node root = gamesTableController.getRoot();
populateContainer(root);
});
}
private void populateContainer(Node root) {
gameViewContainer.getChildren().setAll(root);
AnchorPane.setBottomAnchor(root, 0d);
AnchorPane.setLeftAnchor(root, 0d);
AnchorPane.setRightAnchor(root, 0d);
AnchorPane.setTopAnchor(root, 0d);
}
@FXML
void onTilesButtonClicked() {
GamesTilesContainerController gamesTilesContainerController = applicationContext.getBean(GamesTilesContainerController.class);
gamesTilesContainerController.selectedGameProperty()
.addListener((observable, oldValue, newValue) -> setSelectedGame(newValue));
gamesTilesContainerController.createTiledFlowPane(filteredItems);
Node root = gamesTilesContainerController.getRoot();
populateContainer(root);
}
@VisibleForTesting
void setSelectedGame(GameInfoBean gameInfoBean) {
if (gameInfoBean == null) {
gameDetailPane.setVisible(false);
return;
}
gameDetailPane.setVisible(true);
gameTitleLabel.textProperty().bind(gameInfoBean.titleProperty());
mapImageView.imageProperty().bind(createObjectBinding(
() -> mapService.loadLargePreview(gameInfoBean.getMapFolderName()),
gameInfoBean.mapFolderNameProperty()
));
numberOfPlayersLabel.textProperty().bind(createStringBinding(
() -> i18n.get("game.detail.players.format", gameInfoBean.getNumPlayers(), gameInfoBean.getMaxPlayers()),
gameInfoBean.numPlayersProperty(),
gameInfoBean.maxPlayersProperty()
));
hostLabel.textProperty().bind(gameInfoBean.hostProperty());
mapLabel.textProperty().bind(gameInfoBean.mapFolderNameProperty());
gameTypeLabel.textProperty().bind(createStringBinding(() -> {
GameTypeBean gameType = gameService.getGameTypeByString(gameInfoBean.getFeaturedMod());
String fullName = gameType != null ? gameType.getFullName() : null;
return StringUtils.defaultString(fullName);
}, gameInfoBean.featuredModProperty()));
if (currentGameInfoBean != null) {
currentGameInfoBean.getTeams().removeListener(teamsChangeListener);
}
teamsChangeListener = observable -> createTeams(gameInfoBean.getTeams());
teamsChangeListener.invalidated(gameInfoBean.getTeams());
gameInfoBean.getTeams().addListener(teamsChangeListener);
currentGameInfoBean = gameInfoBean;
}
private void createTeams(ObservableMap<? extends String, ? extends List<String>> playersByTeamNumber) {
teamListPane.getChildren().clear();
synchronized (playersByTeamNumber) {
for (Map.Entry<? extends String, ? extends List<String>> entry : playersByTeamNumber.entrySet()) {
TeamCardController teamCardController = applicationContext.getBean(TeamCardController.class);
teamCardController.setPlayersInTeam(entry.getKey(), entry.getValue());
teamListPane.getChildren().add(teamCardController.getRoot());
}
}
}
}