added ticket printer and improved other functionalities
This commit is contained in:
parent
aa2b21e515
commit
12ab19b864
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
transport_data.json
|
transport_data.json
|
||||||
|
ticket_counter.txt
|
||||||
|
todo
|
||||||
|
receipts/
|
||||||
target/
|
target/
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
!**/src/main/**/target/
|
!**/src/main/**/target/
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package dev.ksan.travelpathoptimizer.app;
|
package dev.ksan.travelpathoptimizer.app;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import dev.ksan.travelpathoptimizer.util.TicketPrinter;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Group;
|
import javafx.scene.Group;
|
||||||
@ -12,7 +14,7 @@ import javafx.stage.Stage;
|
|||||||
public class TravelPathOptimizerApplication extends Application {
|
public class TravelPathOptimizerApplication extends Application {
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws IOException {
|
public void start(Stage stage) throws IOException {
|
||||||
|
TicketPrinter.loadCounter();
|
||||||
FXMLLoader fxmlLoader =
|
FXMLLoader fxmlLoader =
|
||||||
new FXMLLoader(TravelPathOptimizerApplication.class.getResource("main.fxml"));
|
new FXMLLoader(TravelPathOptimizerApplication.class.getResource("main.fxml"));
|
||||||
|
|
||||||
|
@ -2,20 +2,32 @@ package dev.ksan.travelpathoptimizer.controller;
|
|||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.app.TransportDataGenerator;
|
import dev.ksan.travelpathoptimizer.app.TransportDataGenerator;
|
||||||
import dev.ksan.travelpathoptimizer.graph.Graph;
|
import dev.ksan.travelpathoptimizer.graph.Graph;
|
||||||
|
import dev.ksan.travelpathoptimizer.graph.PathResult;
|
||||||
import dev.ksan.travelpathoptimizer.model.City;
|
import dev.ksan.travelpathoptimizer.model.City;
|
||||||
import dev.ksan.travelpathoptimizer.model.Departure;
|
import dev.ksan.travelpathoptimizer.model.Departure;
|
||||||
import dev.ksan.travelpathoptimizer.model.Location;
|
import dev.ksan.travelpathoptimizer.model.Location;
|
||||||
import dev.ksan.travelpathoptimizer.service.CityManager;
|
import dev.ksan.travelpathoptimizer.service.CityManager;
|
||||||
import dev.ksan.travelpathoptimizer.util.JsonParser;
|
import dev.ksan.travelpathoptimizer.util.JsonParser;
|
||||||
|
import dev.ksan.travelpathoptimizer.util.TicketPrinter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.concurrent.Task;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ChoiceBox;
|
import javafx.scene.control.ChoiceBox;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TableCell;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.scene.layout.ColumnConstraints;
|
import javafx.scene.layout.ColumnConstraints;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
@ -41,9 +53,9 @@ public class MainController {
|
|||||||
@FXML private TextField endCityText;
|
@FXML private TextField endCityText;
|
||||||
@FXML private Button startCityButton;
|
@FXML private Button startCityButton;
|
||||||
@FXML private Button endCityButton;
|
@FXML private Button endCityButton;
|
||||||
|
private HashMap<Integer, Departure> departuresMap = new HashMap<>();
|
||||||
private Graph graph;
|
private Graph graph;
|
||||||
City[][] cities;
|
private City[][] cities;
|
||||||
private File selectedFile;
|
private File selectedFile;
|
||||||
@FXML private Button openFileButton;
|
@FXML private Button openFileButton;
|
||||||
@FXML private TextField nTextField;
|
@FXML private TextField nTextField;
|
||||||
@ -58,30 +70,132 @@ public class MainController {
|
|||||||
@FXML private HBox routeView;
|
@FXML private HBox routeView;
|
||||||
@FXML private Text totalTicketPriceText;
|
@FXML private Text totalTicketPriceText;
|
||||||
@FXML private Button buyButton;
|
@FXML private Button buyButton;
|
||||||
|
@FXML private TableView<Departure> resultTable;
|
||||||
|
@FXML private TableColumn<Departure, String> tabDepartureCol;
|
||||||
|
@FXML private TableColumn<Departure, String> tabArrivalCol;
|
||||||
|
@FXML private TableColumn<Departure, String> tabTypeCol;
|
||||||
|
@FXML private TableColumn<Departure, Double> tabCostCol;
|
||||||
|
@FXML private ChoiceBox<String> pathChoiceBox;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void buyTicket() {
|
||||||
|
|
||||||
|
TicketPrinter printer = new TicketPrinter();
|
||||||
|
printer.generateTicketReceipt(
|
||||||
|
updateUiGetList(), Double.parseDouble(totalTicketPriceText.getText()));
|
||||||
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void findTopPaths() {
|
private void findTopPaths() {
|
||||||
graph.reset();
|
graph.reset();
|
||||||
if (this.startCity != null && this.endCity != null) {
|
updateUiGetList();
|
||||||
List<City> path = new ArrayList<>();
|
pathChoiceBox.getItems().clear();
|
||||||
|
startButton.setDisable(true);
|
||||||
|
startCityText.setDisable(true);
|
||||||
|
startCityButton.setDisable(true);
|
||||||
|
endCityButton.setDisable(true);
|
||||||
|
endCityText.setDisable(true);
|
||||||
|
|
||||||
List<Integer> departuress = new ArrayList<>();
|
Task<Void> task =
|
||||||
|
new Task<Void>() {
|
||||||
|
@Override
|
||||||
|
protected Void call() throws Exception {
|
||||||
|
graph.reset();
|
||||||
|
if (startCity != null && endCity != null) {
|
||||||
|
List<City> path = new ArrayList<>();
|
||||||
|
List<Integer> departures = new ArrayList<>();
|
||||||
LocalTime currentTime = LocalTime.of(1, 0);
|
LocalTime currentTime = LocalTime.of(1, 0);
|
||||||
double totalCost = 0.0;
|
double totalCost = 0.0;
|
||||||
|
|
||||||
|
System.out.println(categoryBox.getValue().toString());
|
||||||
graph.calculateTopPaths(
|
graph.calculateTopPaths(
|
||||||
this.startCity,
|
startCity,
|
||||||
this.endCity,
|
endCity,
|
||||||
path,
|
path,
|
||||||
totalCost,
|
totalCost,
|
||||||
currentTime,
|
currentTime,
|
||||||
departuress,
|
departures,
|
||||||
categoryBox.getValue().toString());
|
categoryBox.getValue().toString());
|
||||||
|
|
||||||
System.out.println(graph.getTopPaths().size());
|
System.out.println(graph.getTopPaths().size());
|
||||||
// Output the top 5 paths
|
|
||||||
graph.printTopPaths();
|
|
||||||
System.out.println(startCity.getName() + endCity.getName());
|
System.out.println(startCity.getName() + endCity.getName());
|
||||||
|
if (graph.getTopPaths().isEmpty()) return null;
|
||||||
|
Platform.runLater(
|
||||||
|
() -> {
|
||||||
|
for (PathResult pathResult : graph.getSortedPaths()) {
|
||||||
|
pathChoiceBox.getItems().add("Route: " + String.valueOf(pathResult.getId()));
|
||||||
}
|
}
|
||||||
|
pathChoiceBox.setValue(
|
||||||
|
"Route: " + String.valueOf(graph.getSortedPaths().getFirst().getId()));
|
||||||
|
updateUiGetList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void succeeded() {
|
||||||
|
super.succeeded();
|
||||||
|
startButton.setDisable(false);
|
||||||
|
startCityText.setDisable(false);
|
||||||
|
startCityButton.setDisable(false);
|
||||||
|
endCityButton.setDisable(false);
|
||||||
|
endCityText.setDisable(false);
|
||||||
|
if (!routeView.isVisible()) showRouteView();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void failed() {
|
||||||
|
super.failed();
|
||||||
|
startButton.setDisable(false);
|
||||||
|
startCityText.setDisable(false);
|
||||||
|
startCityButton.setDisable(false);
|
||||||
|
endCityButton.setDisable(false);
|
||||||
|
endCityText.setDisable(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
new Thread(task).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized ObservableList<Departure> updateUiGetList() {
|
||||||
|
|
||||||
|
ObservableList<Departure> departureList = FXCollections.observableArrayList();
|
||||||
|
while (pathChoiceBox == null) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (graph.getTopPaths().size() > 0) {
|
||||||
|
Optional<List<Integer>> departuresOpt =
|
||||||
|
graph.getSortedPaths().stream()
|
||||||
|
.filter(
|
||||||
|
item ->
|
||||||
|
item.getId()
|
||||||
|
== Integer.parseInt(pathChoiceBox.getValue().replaceAll("[^0-9]", "")))
|
||||||
|
.map(PathResult::getDeparturesUsed)
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (departuresOpt.isPresent()) {
|
||||||
|
for (Integer dep : departuresOpt.get()) {
|
||||||
|
departureList.add(departuresMap.get(dep));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("No matching PathResult found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println(departureList.size());
|
||||||
|
resultTable.setItems(departureList);
|
||||||
|
resultTable.refresh();
|
||||||
|
|
||||||
|
double totalTicketPrice = calculateTotalCost(departureList);
|
||||||
|
Platform.runLater(
|
||||||
|
() -> {
|
||||||
|
totalTicketPriceText.setText(String.format("%.2f", totalTicketPrice));
|
||||||
|
});
|
||||||
|
return departureList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@ -153,12 +267,12 @@ public class MainController {
|
|||||||
startCity = cities[currentRow][currentCol];
|
startCity = cities[currentRow][currentCol];
|
||||||
startCityText.setText(startCity.getName());
|
startCityText.setText(startCity.getName());
|
||||||
selectingStart = false;
|
selectingStart = false;
|
||||||
updateMap(); // redraw grid with updated startCity style
|
updateMap();
|
||||||
} else if (selectingEnd) {
|
} else if (selectingEnd) {
|
||||||
endCity = cities[currentRow][currentCol];
|
endCity = cities[currentRow][currentCol];
|
||||||
endCityText.setText(endCity.getName());
|
endCityText.setText(endCity.getName());
|
||||||
selectingEnd = false;
|
selectingEnd = false;
|
||||||
updateMap(); // redraw grid with updated endCity style
|
updateMap();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
thisCell.setStyle("-fx-border-color: black; -fx-background-color: white;");
|
thisCell.setStyle("-fx-border-color: black; -fx-background-color: white;");
|
||||||
@ -200,10 +314,64 @@ public class MainController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
pathChoiceBox.setOnAction(
|
||||||
|
event -> {
|
||||||
|
updateUiGetList();
|
||||||
|
});
|
||||||
|
|
||||||
categoryBox.getItems().addAll("time", "price", "hops");
|
categoryBox.getItems().addAll("time", "price", "hops");
|
||||||
categoryBox.setValue("time");
|
categoryBox.setValue("time");
|
||||||
|
|
||||||
|
tabDepartureCol.setCellFactory(
|
||||||
|
column ->
|
||||||
|
new TableCell<Departure, String>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(String item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (empty || getTableRow() == null || getTableRow().getItem() == null) {
|
||||||
|
setText(null);
|
||||||
|
} else {
|
||||||
|
Departure dep = getTableRow().getItem();
|
||||||
|
String departureInfo =
|
||||||
|
dep.getFrom() + " (" + dep.getDepartureTime().toString() + ")";
|
||||||
|
setText(departureInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tabArrivalCol.setCellFactory(
|
||||||
|
column ->
|
||||||
|
new TableCell<Departure, String>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(String item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (empty || getTableRow() == null || getTableRow().getItem() == null) {
|
||||||
|
setText(null);
|
||||||
|
} else {
|
||||||
|
Departure dep = getTableRow().getItem();
|
||||||
|
String departureInfo = dep.getTo() + " (" + dep.getArrivalTime().toString() + ")";
|
||||||
|
setText(departureInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tabTypeCol.setCellFactory(
|
||||||
|
column ->
|
||||||
|
new TableCell<Departure, String>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(String item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (empty || getTableRow() == null || getTableRow().getItem() == null) {
|
||||||
|
setText(null);
|
||||||
|
} else {
|
||||||
|
Departure dep = getTableRow().getItem();
|
||||||
|
setText(dep.getType().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tabCostCol.setCellValueFactory(new PropertyValueFactory<>("price"));
|
||||||
|
|
||||||
endCityText
|
endCityText
|
||||||
.textProperty()
|
.textProperty()
|
||||||
.addListener(
|
.addListener(
|
||||||
@ -214,8 +382,8 @@ public class MainController {
|
|||||||
} else {
|
} else {
|
||||||
City match = CityManager.getCityByName(newText.trim());
|
City match = CityManager.getCityByName(newText.trim());
|
||||||
|
|
||||||
System.out.println("Selected end: " + match.getName());
|
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
|
System.out.println("Selected end: " + match.getName());
|
||||||
endCity = match;
|
endCity = match;
|
||||||
endCityText.setStyle("-fx-text-fill: green;");
|
endCityText.setStyle("-fx-text-fill: green;");
|
||||||
} else {
|
} else {
|
||||||
@ -236,8 +404,9 @@ public class MainController {
|
|||||||
} else {
|
} else {
|
||||||
City match = CityManager.getCityByName(newText.trim());
|
City match = CityManager.getCityByName(newText.trim());
|
||||||
|
|
||||||
System.out.println("Selected start: " + match.getName());
|
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
|
|
||||||
|
System.out.println("Selected start: " + match.getName());
|
||||||
startCity = match;
|
startCity = match;
|
||||||
startCityText.setStyle("-fx-text-fill: green;");
|
startCityText.setStyle("-fx-text-fill: green;");
|
||||||
} else {
|
} else {
|
||||||
@ -250,6 +419,14 @@ public class MainController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double calculateTotalCost(ObservableList<Departure> depList) {
|
||||||
|
double totalCost = 0.0;
|
||||||
|
for (Departure dep : depList) {
|
||||||
|
totalCost += dep.getPrice();
|
||||||
|
}
|
||||||
|
return totalCost;
|
||||||
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void generateNewMap() {
|
void generateNewMap() {
|
||||||
if (!nTextField.getText().isEmpty() && !mTextField.getText().isEmpty()) {
|
if (!nTextField.getText().isEmpty() && !mTextField.getText().isEmpty()) {
|
||||||
@ -272,7 +449,9 @@ public class MainController {
|
|||||||
CityManager.clear();
|
CityManager.clear();
|
||||||
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
|
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
|
||||||
List<Departure> departures = JsonParser.getDeparturesList("transport_data.json", "departures");
|
List<Departure> departures = JsonParser.getDeparturesList("transport_data.json", "departures");
|
||||||
|
|
||||||
for (Departure dep : departures) {
|
for (Departure dep : departures) {
|
||||||
|
this.departuresMap.put(dep.getIdCounter(), dep);
|
||||||
for (City city : cities) {
|
for (City city : cities) {
|
||||||
if (dep.getTo().equals(city.getName())) {
|
if (dep.getTo().equals(city.getName())) {
|
||||||
dep.setToCity(city);
|
dep.setToCity(city);
|
||||||
|
@ -78,6 +78,11 @@ public class Graph {
|
|||||||
printTopPaths();
|
printTopPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<PathResult> getSortedPaths(){
|
||||||
|
List<PathResult> pathList = new ArrayList<>(topPaths);
|
||||||
|
pathList.sort(Comparator.comparingDouble(PathResult::getCost));
|
||||||
|
return pathList;
|
||||||
|
}
|
||||||
public void reset() {
|
public void reset() {
|
||||||
topPaths.clear();
|
topPaths.clear();
|
||||||
pathIdCounter = 1;
|
pathIdCounter = 1;
|
||||||
@ -155,6 +160,7 @@ public class Graph {
|
|||||||
cost += dep.getPrice();
|
cost += dep.getPrice();
|
||||||
} else if (type.equals("hops")) {
|
} else if (type.equals("hops")) {
|
||||||
cost++;
|
cost++;
|
||||||
|
if(!topPaths.isEmpty() && totalCost + cost >= topPaths.peek().getCost()) continue;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ public class Departure {
|
|||||||
private String to;
|
private String to;
|
||||||
private int duration;
|
private int duration;
|
||||||
private LocalTime departureTime;
|
private LocalTime departureTime;
|
||||||
|
private LocalTime arrivalTime;
|
||||||
private double price;
|
private double price;
|
||||||
private int minTransferTime;
|
private int minTransferTime;
|
||||||
private City toCity;
|
private City toCity;
|
||||||
@ -32,6 +33,7 @@ public class Departure {
|
|||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
this.price = price;
|
this.price = price;
|
||||||
this.minTransferTime = minTransferTime;
|
this.minTransferTime = minTransferTime;
|
||||||
|
this.arrivalTime = this.departureTime.plusMinutes(duration);
|
||||||
}
|
}
|
||||||
public int getIdCounter() {
|
public int getIdCounter() {
|
||||||
return id;
|
return id;
|
||||||
@ -48,6 +50,9 @@ public class Departure {
|
|||||||
public LocalTime getDepartureTime() {
|
public LocalTime getDepartureTime() {
|
||||||
return departureTime;
|
return departureTime;
|
||||||
}
|
}
|
||||||
|
public LocalTime getArrivalTime() {
|
||||||
|
return arrivalTime;
|
||||||
|
}
|
||||||
public TransportType getType() {
|
public TransportType getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,103 @@
|
|||||||
|
package dev.ksan.travelpathoptimizer.util;
|
||||||
|
|
||||||
|
import dev.ksan.travelpathoptimizer.model.Departure;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TicketPrinter {
|
||||||
|
private static final String COUNTER_FILE = "ticket_counter.txt";
|
||||||
|
private static final String RECEIPTS_DIRECTORY = "receipts";
|
||||||
|
private static final double totalProfit = 0.0;
|
||||||
|
private static int ticketIdCounter = 0;
|
||||||
|
|
||||||
|
public static void generateTicketReceipt(List<Departure> departures, double totalPrice) {
|
||||||
|
LocalDate currentDate = LocalDate.now();
|
||||||
|
|
||||||
|
StringBuilder receipt = new StringBuilder();
|
||||||
|
|
||||||
|
receipt.append("=====================================================\n");
|
||||||
|
receipt.append(" TICKET RECEIPT\n");
|
||||||
|
receipt.append(" Ksan Travel Optimizer\n");
|
||||||
|
receipt.append("=====================================================\n");
|
||||||
|
|
||||||
|
receipt.append("Ticket ID: ").append(getNextId()).append("\n");
|
||||||
|
saveCounter();
|
||||||
|
receipt.append("Date: ").append(currentDate).append("\n");
|
||||||
|
receipt.append("From: ").append(departures.getFirst().getFrom()).append("\n");
|
||||||
|
receipt.append("To: ").append(departures.getLast().getTo()).append("\n");
|
||||||
|
receipt.append("-----------------------------------------------------\n");
|
||||||
|
|
||||||
|
receipt.append("Departure Prices:\n");
|
||||||
|
for (Departure dep : departures) {
|
||||||
|
receipt
|
||||||
|
.append(" - ")
|
||||||
|
.append(dep.getFrom())
|
||||||
|
.append(" -> ")
|
||||||
|
.append(dep.getTo())
|
||||||
|
.append(" | Price: $")
|
||||||
|
.append(String.format("%.2f", dep.getPrice()))
|
||||||
|
.append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
receipt.append("-----------------------------------------------------\n");
|
||||||
|
receipt.append("Total Price: $").append(String.format("%.2f", totalPrice)).append("\n");
|
||||||
|
|
||||||
|
receipt.append("=====================================================\n");
|
||||||
|
receipt.append("Thank you for choosing our service!\n");
|
||||||
|
folderExists();
|
||||||
|
|
||||||
|
writeReceipt(receipt.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeReceipt(String receipt) {
|
||||||
|
Path receiptFile = Paths.get(RECEIPTS_DIRECTORY, "receipt_" + ticketIdCounter + ".txt");
|
||||||
|
try {
|
||||||
|
Files.write(receiptFile, receipt.getBytes());
|
||||||
|
System.out.println("Receipt saved to: " + receiptFile.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void folderExists() {
|
||||||
|
Path path = Paths.get(RECEIPTS_DIRECTORY);
|
||||||
|
|
||||||
|
if (!Files.exists(path)) {
|
||||||
|
try {
|
||||||
|
Files.createDirectory(path);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadCounter() {
|
||||||
|
try {
|
||||||
|
Path path = Paths.get(COUNTER_FILE);
|
||||||
|
if (Files.exists(path)) {
|
||||||
|
String counter = new String(Files.readAllBytes(path)).trim();
|
||||||
|
ticketIdCounter = Integer.parseInt(counter);
|
||||||
|
} else {
|
||||||
|
ticketIdCounter = 0;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
ticketIdCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void saveCounter() {
|
||||||
|
try {
|
||||||
|
Files.write(Paths.get(COUNTER_FILE), String.valueOf(ticketIdCounter).getBytes());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getNextId() {
|
||||||
|
return ++ticketIdCounter;
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ module dev.ksan.travelpathoptimizer {
|
|||||||
requires javafx.fxml;
|
requires javafx.fxml;
|
||||||
requires java.desktop;
|
requires java.desktop;
|
||||||
requires javafx.graphics;
|
requires javafx.graphics;
|
||||||
|
requires javafx.base;
|
||||||
|
|
||||||
opens dev.ksan.travelpathoptimizer to
|
opens dev.ksan.travelpathoptimizer to
|
||||||
javafx.fxml;
|
javafx.fxml;
|
||||||
@ -38,4 +39,3 @@ module dev.ksan.travelpathoptimizer {
|
|||||||
opens dev.ksan.travelpathoptimizer.graph to
|
opens dev.ksan.travelpathoptimizer.graph to
|
||||||
javafx.fxml;
|
javafx.fxml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.ChoiceBox?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.control.TableColumn?>
|
||||||
|
<?import javafx.scene.control.TableView?>
|
||||||
<?import javafx.scene.control.TextField?>
|
<?import javafx.scene.control.TextField?>
|
||||||
<?import javafx.scene.image.Image?>
|
<?import javafx.scene.image.Image?>
|
||||||
<?import javafx.scene.image.ImageView?>
|
<?import javafx.scene.image.ImageView?>
|
||||||
@ -100,6 +103,7 @@
|
|||||||
</VBox>
|
</VBox>
|
||||||
<VBox fx:id="calculatorSideBar" managed="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="354.0" prefWidth="180.0" visible="true">
|
<VBox fx:id="calculatorSideBar" managed="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="354.0" prefWidth="180.0" visible="true">
|
||||||
<children>
|
<children>
|
||||||
|
<Text fx:id="sectionText1" strokeType="OUTSIDE" strokeWidth="0.0" text="Path Calculator" textAlignment="CENTER" wrappingWidth="179.2100067138672" />
|
||||||
<HBox prefHeight="32.0" prefWidth="180.0">
|
<HBox prefHeight="32.0" prefWidth="180.0">
|
||||||
<children>
|
<children>
|
||||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Map:" textAlignment="CENTER" wrappingWidth="37.562997817993164">
|
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Map:" textAlignment="CENTER" wrappingWidth="37.562997817993164">
|
||||||
@ -114,7 +118,6 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</children>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
<Text fx:id="sectionText1" strokeType="OUTSIDE" strokeWidth="0.0" text="Path Calculator" textAlignment="CENTER" wrappingWidth="179.2100067138672" />
|
|
||||||
<HBox prefHeight="39.0" prefWidth="180.0">
|
<HBox prefHeight="39.0" prefWidth="180.0">
|
||||||
<children>
|
<children>
|
||||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Start:">
|
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Start:">
|
||||||
@ -153,6 +156,25 @@
|
|||||||
<Insets left="10.0" right="10.0" top="-5.0" />
|
<Insets left="10.0" right="10.0" top="-5.0" />
|
||||||
</VBox.margin>
|
</VBox.margin>
|
||||||
</Button>
|
</Button>
|
||||||
|
<HBox prefHeight="52.0" prefWidth="180.0">
|
||||||
|
<children>
|
||||||
|
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Category:">
|
||||||
|
<HBox.margin>
|
||||||
|
<Insets left="10.0" top="13.0" />
|
||||||
|
</HBox.margin>
|
||||||
|
</Text>
|
||||||
|
<ChoiceBox fx:id="categoryBox" prefWidth="150.0">
|
||||||
|
<HBox.margin>
|
||||||
|
<Insets left="10.0" right="10.0" top="10.0" />
|
||||||
|
</HBox.margin>
|
||||||
|
</ChoiceBox>
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
<Button fx:id="startButton" mnemonicParsing="false" onAction="#findTopPaths" prefHeight="26.0" prefWidth="185.0" text="Start">
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets left="15.0" right="15.0" top="15.0" />
|
||||||
|
</VBox.margin>
|
||||||
|
</Button>
|
||||||
</children>
|
</children>
|
||||||
</VBox>
|
</VBox>
|
||||||
<GridPane fx:id="map" alignment="CENTER" gridLinesVisible="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" HBox.hgrow="ALWAYS">
|
<GridPane fx:id="map" alignment="CENTER" gridLinesVisible="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" HBox.hgrow="ALWAYS">
|
||||||
@ -175,6 +197,39 @@
|
|||||||
<Insets />
|
<Insets />
|
||||||
</VBox.margin>
|
</VBox.margin>
|
||||||
</HBox>
|
</HBox>
|
||||||
<HBox prefHeight="100.0" prefWidth="200.0" />
|
<HBox fx:id="routeView" prefHeight="148.0" prefWidth="1000.0">
|
||||||
|
<children>
|
||||||
|
<VBox prefHeight="148.0" prefWidth="807.0">
|
||||||
|
<children>
|
||||||
|
<TableView fx:id="resultTable" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0">
|
||||||
|
<columns>
|
||||||
|
<TableColumn fx:id="tabDepartureCol" prefWidth="300.0" text="Departure" />
|
||||||
|
<TableColumn fx:id="tabArrivalCol" prefWidth="300.0" text="Arrival" />
|
||||||
|
<TableColumn fx:id="tabTypeCol" prefWidth="100.0" text="Type" />
|
||||||
|
<TableColumn fx:id="tabCostCol" prefWidth="100.0" text="Cost" />
|
||||||
|
</columns>
|
||||||
|
</TableView>
|
||||||
|
</children></VBox>
|
||||||
|
<VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="148.0" prefWidth="194.0">
|
||||||
|
<children>
|
||||||
|
<ChoiceBox fx:id="pathChoiceBox" prefHeight="26.0" prefWidth="182.0">
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets left="15.0" right="15.0" top="2.0" />
|
||||||
|
</VBox.margin>
|
||||||
|
</ChoiceBox>
|
||||||
|
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Total:" textAlignment="CENTER" wrappingWidth="196.91699981689453">
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets top="15.0" />
|
||||||
|
</VBox.margin>
|
||||||
|
</Text>
|
||||||
|
<Text fx:id="totalTicketPriceText" strokeType="OUTSIDE" strokeWidth="0.0" text="0.0" textAlignment="CENTER" wrappingWidth="201.13000106811523" />
|
||||||
|
<Button fx:id="buyButton" mnemonicParsing="false" onAction="#buyTicket" prefHeight="45.0" prefWidth="142.0" text="Buy Ticket" textAlignment="CENTER">
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets left="30.0" right="30.0" top="15.0" />
|
||||||
|
</VBox.margin>
|
||||||
|
</Button>
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
</children></HBox>
|
||||||
</children>
|
</children>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user