Skip to content

Commit

Permalink
the great merge
Browse files Browse the repository at this point in the history
  • Loading branch information
peretr committed May 18, 2026
2 parents 059cf1b + db2b77a commit 0df0c01
Show file tree
Hide file tree
Showing 14 changed files with 353 additions and 361 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import edu.ntnu.idi.idatt2003.gruppe42.model.transaction.Transaction;
import edu.ntnu.idi.idatt2003.gruppe42.view.apps.StockApp;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
Expand All @@ -17,39 +20,30 @@
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;

/**
* Controller for the Stock application.
*
* <p>This controller manages:
* <ul>
* <li>Displaying and updating stock market data</li>
* <li>Searching and filtering stocks</li>
* <li>Navigating between stock overview and detail views</li>
* <li>Handling buy and sell transactions</li>
* <li>Updating UI state based on game conditions (e.g. weekends)</li>
* </ul>
*
* <p>It acts as the bridge between the market model, player portfolio,
* and the stock trading UI.
*/
/** Controller for StockApp. */
public final class StockAppController implements AppController {

private final MarketController marketController;
private final StockApp stockApp;
private final Player player;
private Stock currentStock;

private enum SortType {
ALPHA, GAINER, PRICE
}

private SortType currentSort = SortType.ALPHA;
private boolean isDescending = false;

/** True while the game is on Saturday or Sunday. */
private boolean isWeekend = false;

/** Called when the player clicks Trade during a weekend. */
private Runnable onMarketClosed;

private Runnable onInsufficientFunds;

/**
* Constructs the Stock application controller and initializes stock data,
* UI listeners, and trading actions.
*
* @param stockApp the stock application view
* @param marketController the market controller providing stock data and trading logic
* @param player the player performing trades
*/
/** Constructs the controller. */
public StockAppController(
final StockApp stockApp,
final MarketController marketController,
Expand All @@ -59,8 +53,7 @@ public StockAppController(
this.marketController = marketController;
this.player = player;

stockApp.getStockList().getItems()
.addAll(marketController.getExchange().getAllStocks());
updateStockList();

stockApp.getStockList().setCellFactory(lv -> createStockCell());

Expand All @@ -69,10 +62,39 @@ public StockAppController(
if (currentStock != null && !newValue.isEmpty()) {
navigateToSearch();
}
stockApp.getStockList().getItems()
.setAll(marketController.getMarket(newValue));
updateStockList();
});

stockApp.getAlphaButton().setOnAction(e -> {
if (currentSort == SortType.ALPHA) {
isDescending = !isDescending;
} else {
currentSort = SortType.ALPHA;
isDescending = false;
}
updateStockList();
});

stockApp.getGainerButton().setOnAction(e -> {
if (currentSort == SortType.GAINER) {
isDescending = !isDescending;
} else {
currentSort = SortType.GAINER;
isDescending = false;
}
updateStockList();
});

stockApp.getPriceButton().setOnAction(e -> {
if (currentSort == SortType.PRICE) {
isDescending = !isDescending;
} else {
currentSort = SortType.PRICE;
isDescending = true;
}
updateStockList();
});

stockApp.getQuantitySpinner().valueProperty().addListener(
(obs, old, newValue) -> {
if (currentStock != null) {
Expand All @@ -85,11 +107,7 @@ public StockAppController(
stockApp.getBackButton().setOnAction(e -> navigateToSearch());
}

/**
* Navigates the UI to display details for a selected stock.
*
* @param stock the stock to display
*/
/** Navigates to stock detail page. */
public void navigateToStock(final Stock stock) {
currentStock = stock;
stock.getStockGraph().setVisibility(true);
Expand All @@ -98,6 +116,7 @@ public void navigateToStock(final Stock stock) {
updateReceipt();
}

/** Navigates to search page. */
private void navigateToSearch() {
if (currentStock != null) {
currentStock.getStockGraph().setVisibility(false);
Expand All @@ -106,6 +125,7 @@ private void navigateToSearch() {
stockApp.showSearchPage();
}

/** Creates list cell for stock row. */
private ListCell<Stock> createStockCell() {
return new ListCell<>() {
private final HBox row = new HBox(15);
Expand All @@ -119,7 +139,7 @@ private ListCell<Stock> createStockCell() {
row.setAlignment(Pos.CENTER_LEFT);
row.getStyleClass().add("stock-list-item");

final VBox names = new VBox(2, symbolLabel, companyLabel);
VBox names = new VBox(2, symbolLabel, companyLabel);
symbolLabel.getStyleClass().add("stock-symbol");
companyLabel.getStyleClass().add("stock-company");

Expand Down Expand Up @@ -167,20 +187,14 @@ protected void updateItem(final Stock stock, final boolean empty) {
};
}

/**
* Sets whether the market is currently in weekend mode.
*
* <p>When weekend mode is active, trading is disabled.
*
* @param weekend true if it is weekend, false otherwise
*/
/** Sets weekend status. */
public void setWeekend(final boolean weekend) {
this.isWeekend = weekend;
Platform.runLater(this::updateTradeUi);
Platform.runLater(this::updateTradeUI);
}

/** Updates the Trade button and spinner state. */
private void updateTradeUi() {
private void updateTradeUI() {
Button tradeButton = stockApp.getConfirmButton();
var spinner = stockApp.getQuantitySpinner();

Expand Down Expand Up @@ -212,24 +226,17 @@ private void updateTradeUi() {
}
}

/**
* Sets a callback executed when the user attempts to trade while the market is closed.
*
* @param callback action to run when market is closed
*/
/** Sets market closed callback. */
public void setOnMarketClosed(final Runnable callback) {
this.onMarketClosed = callback;
}

/**
* Sets a callback executed when a buy transaction fails due to insufficient funds.
*
* @param callback action to run when funds are insufficient
*/
/** Sets insufficient funds callback. */
public void setOnInsufficientFunds(final Runnable callback) {
this.onInsufficientFunds = callback;
}

/** Handles trade button action. */
private void handleTransaction() {
if (isWeekend) {
if (onMarketClosed != null) {
Expand Down Expand Up @@ -261,15 +268,18 @@ private void handleTransaction() {
}
}

/** Buys given stock. */
private void handleBuy(final Stock stock, final BigDecimal quantity) throws Exception {
Transaction transaction = marketController.getExchange()
.buy(stock.getSymbol(), quantity);
if (transaction != null) {
transaction.commit(player);
player.getPortfolio().addShare(transaction.getShare());
player.updateStatus();
}
}

/** Sells given stock. */
private void handleSell(final Stock stock, final BigDecimal quantity) {
player.getPortfolio().getShares().stream()
.filter(share -> share.getStock().getSymbol().equals(stock.getSymbol()))
Expand All @@ -288,28 +298,47 @@ private void handleSell(final Stock stock, final BigDecimal quantity) {
System.out.println("Transaction failed");
}
player.getPortfolio().removeShare(transaction.getShare());
player.updateStatus();
}
});
}

/** Updates receipt view. */
private void updateReceipt() {
if (currentStock != null) {
Platform.runLater(() -> {
stockApp.getReceipt().update(
stockApp.getReceipt().update(
currentStock,
new BigDecimal(stockApp.getQuantitySpinner().getValue())
);
updateTradeUi();
);
updateTradeUI();
});
}
}

/**
* Advances the stock market simulation by one tick.
*
* <p>This updates stock prices, refreshes the UI list, and updates
* the currently selected stock view if applicable.
*/
/** Updates the stock list with current sort and filter. */
private void updateStockList() {
List<Stock> stocks = new ArrayList<>(marketController.getMarket(stockApp.getSearchField().getText()));
Comparator<Stock> comparator;
switch (currentSort) {
case GAINER:
comparator = Comparator.comparing(Stock::getLatestPriceChange);
break;
case PRICE:
comparator = Comparator.comparing(Stock::getSalesPrice);
break;
default:
comparator = Comparator.comparing(Stock::getSymbol);
break;
}
if (isDescending) {
comparator = comparator.reversed();
}
stocks.sort(comparator);
stockApp.getStockList().getItems().setAll(stocks);
}

/** Processes next tick. */
@Override
public void nextTick() {
marketController.updateMarket();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public DesktopViewController(
() -> {
News news = new News(event.company(), event.trend());
mailController.createMessage(
news.generateAuthor(), event.company(), news.generateNews());
news.generateAuthor(), "BREAKING NEWS", news.generateNews());
}));
}

Expand Down Expand Up @@ -215,8 +215,10 @@ private void setupDesktopUi() {
}

private void setupListeners() {
timeAndWeatherController.hourProperty().addListener((obs, ov, nv) ->
desktopView.updateClock(timeAndWeatherController.getTimeString()));
timeAndWeatherController.hourProperty().addListener((obs, ov, nv) -> {
desktopView.updateClock(timeAndWeatherController.getTimeString());
player.updateStatus();
});

timeAndWeatherController.dayIndexProperty().addListener((obs, ov, nv) -> {
String dayName = timeAndWeatherController.getDayOfWeekString();
Expand All @@ -235,6 +237,7 @@ private void setupListeners() {
player.getNameProperty().addListener((obs, ov, nv) ->
desktopView.updatePlayerName(nv));

player.updateStatus();
player.getStatusProperty().addListener((obs, ov, nv) ->
desktopView.updatePlayerStatus(nv.name()));

Expand Down Expand Up @@ -264,6 +267,7 @@ private void doAdvanceWeek() {
marketController.advanceWeek();
timeAndWeatherController.advanceWeek();
mailController.clearMessages();
player.updateStatus();
}

private void showMarketClosedWarning() {
Expand Down
Loading

0 comments on commit 0df0c01

Please sign in to comment.