From 07a7a1cb3e4cfc1580bc05b0a6010a1e9f7e7508 Mon Sep 17 00:00:00 2001 From: Kostya Date: Sun, 16 Aug 2026 11:55:08 +0000 Subject: Rename Option/Account to Market/Ledger, add Result-based error handling Split GuessMarketContext into a separate CatalogContext for read-only event listing, wrap fallible operations in Result instead of throwing, and wire load/save of events and users through a JSON Wrapper. --- .../main/java/market/guess/ui/console/Menu.java | 2 +- .../guess/ui/console/command/BuyMenuCommand.java | 54 +++++++++++----------- .../console/command/EventDetailsMenuCommand.java | 6 --- .../guess/ui/console/command/ExitMenuCommand.java | 5 -- .../ui/console/command/ListEventsMenuCommand.java | 20 ++++---- .../ui/console/command/LoadFileMenuCommand.java | 33 ++++++------- .../command/LoadMarketStateMenuCommand.java | 26 +++++++---- .../guess/ui/console/command/MenuCommand.java | 2 - .../command/SaveMarketStateMenuCommand.java | 6 --- .../ui/console/command/SettleEventMenuCommand.java | 6 --- .../market/guess/ui/console/io/InputProcessor.java | 43 ++++++++++++++--- 11 files changed, 109 insertions(+), 94 deletions(-) (limited to 'ui-console/src/main/java/market/guess/ui') diff --git a/ui-console/src/main/java/market/guess/ui/console/Menu.java b/ui-console/src/main/java/market/guess/ui/console/Menu.java index 90ddd38..9041590 100644 --- a/ui-console/src/main/java/market/guess/ui/console/Menu.java +++ b/ui-console/src/main/java/market/guess/ui/console/Menu.java @@ -20,8 +20,8 @@ public final class Menu implements Startable { public void start() { var max = commands.stream().mapToInt(MenuCommand::getIndex).max().orElse(0); io.splashScreen(); - while (true) { + while (true) { io.newLine(); for (var command : commands) { io.println(" [%d]->> %s".formatted(command.getIndex(), command.getName())); diff --git a/ui-console/src/main/java/market/guess/ui/console/command/BuyMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/BuyMenuCommand.java index b8e2523..df40aa8 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/BuyMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/BuyMenuCommand.java @@ -1,17 +1,19 @@ package market.guess.ui.console.command; +import market.guess.api.CatalogContext; import market.guess.api.EventStatus; import market.guess.api.GuessMarketContext; -import market.guess.exception.GuessMarketException; import market.guess.ui.console.io.InputProcessor; public final class BuyMenuCommand implements MenuCommand { private final GuessMarketContext context; + private final CatalogContext catalog; private final InputProcessor io; - public BuyMenuCommand(GuessMarketContext context, InputProcessor io) { + public BuyMenuCommand(GuessMarketContext context, CatalogContext catalog, InputProcessor io) { super(); this.context = context; + this.catalog = catalog; this.io = io; } @@ -25,50 +27,46 @@ public final class BuyMenuCommand implements MenuCommand { return "Buy share(s) in an event"; } - @Override - public boolean allowed() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'allowed'"); - } - @Override public void execute() { - var active = - context.listEvents().stream() - .filter(event -> event.status() == EventStatus.ACTIVE) - .toList(); + var result = catalog.getAllEvents(); + + if (!result.isSuccess()) { + io.println("Failed to list events"); + return; + } + + var events = result.getData(); + var active = events.stream().filter(event -> event.status() == EventStatus.ACTIVE).toList(); if (active.isEmpty()) { io.println("There are currently no active events to trade on."); return; } - var pick = - io.readSelect( - "Pick an event: ", - active, - event -> "[%d] %s".formatted(event.displayId(), event.name())); - - var event = context.getEvent(pick.eventKey()); + var pick = io.readSelect("Pick an event: ", active, event -> "%s".formatted(event.name())); + var result2 = catalog.getEvent(pick.key()); + var event = result2.getData(); if (event == null) { io.println("That event is no longer available."); return; } - // TODO: print state + io.printState(event.state()); - var option = + var market = io.readSelect( - "Choose an option: ", event.state().options(), o -> "%s [value %d, %d shares helds]"); + "Choose a market: ", + event.state().markets(), + o -> "%s [value %d, %d shares helds]".formatted(o.name(), o.price(), o.volume())); var amount = io.readInt("How many shares? ", 1, Integer.MAX_VALUE); - try { - var receipt = context.buyShares("", option.optionKey(), option.optionKey(), amount); - } catch (GuessMarketException e) { - io.newLine(); - io.println("Purchase declined: %s".formatted(e.getMessage())); - } + var receipt = context.buyShares("", event.summary().key(), market.key(), amount); + if (receipt.isSuccess()) return; + + io.newLine(); + io.println("Purchase declined: %s".formatted(receipt.getMessage())); } } diff --git a/ui-console/src/main/java/market/guess/ui/console/command/EventDetailsMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/EventDetailsMenuCommand.java index e12caeb..ab60a1f 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/EventDetailsMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/EventDetailsMenuCommand.java @@ -12,12 +12,6 @@ public final class EventDetailsMenuCommand implements MenuCommand { return "Show event details"; } - @Override - public boolean allowed() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'allowed'"); - } - @Override public void execute() { // TODO Auto-generated method stub diff --git a/ui-console/src/main/java/market/guess/ui/console/command/ExitMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/ExitMenuCommand.java index 23ed9c9..4fcc448 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/ExitMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/ExitMenuCommand.java @@ -20,11 +20,6 @@ public final class ExitMenuCommand implements MenuCommand { return "Exit"; } - @Override - public boolean allowed() { - return true; - } - @Override public boolean isExit() { return true; diff --git a/ui-console/src/main/java/market/guess/ui/console/command/ListEventsMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/ListEventsMenuCommand.java index bad621d..a97ab9f 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/ListEventsMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/ListEventsMenuCommand.java @@ -1,16 +1,16 @@ package market.guess.ui.console.command; +import market.guess.api.CatalogContext; import market.guess.api.CommissionTiming; -import market.guess.api.GuessMarketContext; import market.guess.ui.console.io.InputProcessor; public final class ListEventsMenuCommand implements MenuCommand { - private final GuessMarketContext context; + private final CatalogContext catalog; private final InputProcessor io; - public ListEventsMenuCommand(GuessMarketContext context, InputProcessor io) { + public ListEventsMenuCommand(CatalogContext catalog, InputProcessor io) { super(); - this.context = context; + this.catalog = catalog; this.io = io; } @@ -24,14 +24,14 @@ public final class ListEventsMenuCommand implements MenuCommand { return "List events"; } - @Override - public boolean allowed() { - return !context.listEvents().isEmpty(); - } - @Override public void execute() { - var events = context.listEvents(); + var result = catalog.getAllEvents(); + + if (!result.isSuccess()) { + return; + } + var events = result.getData(); for (var event : events) { io.newLine(); diff --git a/ui-console/src/main/java/market/guess/ui/console/command/LoadFileMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/LoadFileMenuCommand.java index 7005632..065ac6e 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/LoadFileMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/LoadFileMenuCommand.java @@ -1,15 +1,15 @@ package market.guess.ui.console.command; import java.nio.file.Path; -import market.guess.api.GuessMarketContext; +import market.guess.api.CatalogContext; import market.guess.ui.console.io.InputProcessor; public final class LoadFileMenuCommand implements MenuCommand { - private final GuessMarketContext context; + private final CatalogContext catalog; private final InputProcessor io; - public LoadFileMenuCommand(GuessMarketContext context, InputProcessor io) { - this.context = context; + public LoadFileMenuCommand(CatalogContext catalog, InputProcessor io) { + this.catalog = catalog; this.io = io; } @@ -23,24 +23,25 @@ public final class LoadFileMenuCommand implements MenuCommand { return "Load events from file"; } - @Override - public boolean allowed() { - return true; - } - @Override public void execute() { - var path = io.readPath("Pleae enter the full file path to the XML file: "); - var result = context.loadEvents(Path.of(path)); - - if (result.success()) { - io.println("Loaded %d event(s) from %s.".formatted(result.eventsLoaded(), result.source())); + // var path = io.readPath("Pleae enter the full file path to the XML file: "); + // var result = context.loadEvents(Path.of(path)); + var result = + catalog.loadEvents( + Path.of("/home/hex-dev/projects/guess-market/test-data/ex-1/multiple.xml")); + + if (result.isSuccess()) { + io.println( + "Loaded %d event(s) from %s." + .formatted(result.getData().eventsLoaded(), result.getData().source())); return; } io.println( - "The file was not loaded. %d problem(s) were found: ".formatted(result.issues().size())); - for (var issue : result.issues()) { + "The file was not loaded. %d problem(s) were found: " + .formatted(result.getData().issues().size())); + for (var issue : result.getData().issues()) { io.println(" - %s: %s".formatted(issue.location(), issue.humanizedMessage())); } } diff --git a/ui-console/src/main/java/market/guess/ui/console/command/LoadMarketStateMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/LoadMarketStateMenuCommand.java index 3111044..defb402 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/LoadMarketStateMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/LoadMarketStateMenuCommand.java @@ -1,6 +1,18 @@ package market.guess.ui.console.command; +import java.nio.file.Path; +import market.guess.api.GuessMarketContext; +import market.guess.ui.console.io.InputProcessor; + public final class LoadMarketStateMenuCommand implements MenuCommand { + private final GuessMarketContext context; + private final InputProcessor io; + + public LoadMarketStateMenuCommand(GuessMarketContext context, InputProcessor io) { + super(); + this.context = context; + this.io = io; + } @Override public int getIndex() { @@ -12,15 +24,13 @@ public final class LoadMarketStateMenuCommand implements MenuCommand { return "Load market state"; } - @Override - public boolean allowed() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'allowed'"); - } - @Override public void execute() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'execute'"); + var path = io.readPath("Which state file to load? "); + var result = context.restoreState(Path.of(path)); + + if (result.isSuccess()) { + io.println("Restored %d event(s) from %s.".formatted(result.getData().eventsLoaded(), path)); + } } } diff --git a/ui-console/src/main/java/market/guess/ui/console/command/MenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/MenuCommand.java index 50acdac..8d35112 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/MenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/MenuCommand.java @@ -5,8 +5,6 @@ public interface MenuCommand { String getName(); - boolean allowed(); - void execute(); default boolean isExit() { diff --git a/ui-console/src/main/java/market/guess/ui/console/command/SaveMarketStateMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/SaveMarketStateMenuCommand.java index 2f950f0..27dfdde 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/SaveMarketStateMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/SaveMarketStateMenuCommand.java @@ -24,12 +24,6 @@ public final class SaveMarketStateMenuCommand implements MenuCommand { return "Save current state"; } - @Override - public boolean allowed() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'allowed'"); - } - @Override public void execute() { var path = io.readPath("Save to: "); diff --git a/ui-console/src/main/java/market/guess/ui/console/command/SettleEventMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/SettleEventMenuCommand.java index 9b62be5..b7344e3 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/SettleEventMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/SettleEventMenuCommand.java @@ -22,12 +22,6 @@ public final class SettleEventMenuCommand implements MenuCommand { return "Settle an event"; } - @Override - public boolean allowed() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'allowed'"); - } - @Override public void execute() { // TODO Auto-generated method stub diff --git a/ui-console/src/main/java/market/guess/ui/console/io/InputProcessor.java b/ui-console/src/main/java/market/guess/ui/console/io/InputProcessor.java index b6d5405..912ca25 100644 --- a/ui-console/src/main/java/market/guess/ui/console/io/InputProcessor.java +++ b/ui-console/src/main/java/market/guess/ui/console/io/InputProcessor.java @@ -3,6 +3,7 @@ package market.guess.ui.console.io; import java.util.List; import java.util.Scanner; import java.util.function.Function; +import market.guess.api.MarketStateDTO; public final class InputProcessor { private final Scanner scanner = new Scanner(System.in); @@ -21,14 +22,45 @@ public final class InputProcessor { public void splashScreen() { newLine(); - IO.println("<<- GUESS MARKET ->>"); + IO.println(padLeft("<<- GUESS MARKET ->>", 36)); } - public void printState() { - nextLine(); - println(" Option | Value | Shares "); - + public void printState(MarketStateDTO state) { + newLine(); + println( + "%s|%s%s|%s" + .formatted( + padAround("Option", 18), space(10), padLeft("Value", 8), padRight("Shares", 8))); + + for (var market : state.markets()) { + println( + "%s|%s%s|%s" + .formatted( + padAround(market.name(), 18), + space(10), + padLeft(market.price(), 8), + padRight(market.volume(), 8))); + } newLine(); + + print("Event ledger balance: ".formatted(state.accountBalance())); + print("Commission collected: ".formatted(state.commissionCollected())); + } + + private static String space(int width) { + return " ".repeat(width); + } + + private static String padAround(String input, int width) { + return input.length() >= width ? input : padRight(padLeft(input, width / 2), width / 2); + } + + private static String padRight(String input, int width) { + return input.length() >= width ? input : input + " ".repeat(width - input.length()); + } + + private static String padLeft(String input, int width) { + return input.length() >= width ? input : " ".repeat(width - input.length()) + input; } public String readLine(String prompt) { @@ -92,7 +124,6 @@ public final class InputProcessor { } public T readSelect(String prompt, List items, Function function) { - for (var i = 0; i < items.size(); i++) { IO.println(" [%d]->> %s".formatted(i + 1, function.apply(items.get(i)))); } -- cgit v1.2.3