diff --git a/src/main/java/core/basesyntax/HelloWorld.java b/src/main/java/core/basesyntax/HelloWorld.java deleted file mode 100644 index 97db782bf7..0000000000 --- a/src/main/java/core/basesyntax/HelloWorld.java +++ /dev/null @@ -1,8 +0,0 @@ -package core.basesyntax; - -/** - * Feel free to remove this class and create your own. - */ -public class HelloWorld { - -} diff --git a/src/main/java/core/basesyntax/Main.java b/src/main/java/core/basesyntax/Main.java new file mode 100644 index 0000000000..8fa102e659 --- /dev/null +++ b/src/main/java/core/basesyntax/Main.java @@ -0,0 +1,51 @@ +package core.basesyntax; + +import core.basesyntax.db.Storage; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.FruitService; +import core.basesyntax.service.ParseService; +import core.basesyntax.service.ReaderService; +import core.basesyntax.service.ReportService; +import core.basesyntax.service.WriterService; +import core.basesyntax.service.impl.FruitServiceImpl; +import core.basesyntax.service.impl.ParseServiceImpl; +import core.basesyntax.service.impl.ReaderServiceImpl; +import core.basesyntax.service.impl.ReportServiceImpl; +import core.basesyntax.service.impl.WriterServiceImpl; +import core.basesyntax.strategy.BalanceOperationStrategy; +import core.basesyntax.strategy.OperationStrategy; +import core.basesyntax.strategy.PurchaseOperationStrategy; +import core.basesyntax.strategy.ReturnOperationStrategy; +import core.basesyntax.strategy.SupplyOperationStrategy; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Main { + private static final String INPUT_FILE = "src/main/resources/input.csv"; + private static final String OUTPUT_FILE = "src/main/resources/output.csv"; + + public static void main(String[] args) { + ReaderService readerService = new ReaderServiceImpl(); + WriterService writerService = new WriterServiceImpl(); + ParseService parseService = new ParseServiceImpl(); + ReportService reportService = new ReportServiceImpl(); + Storage storage = Storage.getInstance(); + Map operationStrategies = initializeStrategies(); + FruitService fruitService = new FruitServiceImpl(operationStrategies); + List inputLines = readerService.readFromFile(INPUT_FILE); + List transactions = parseService.parseTransactions(inputLines); + fruitService.processTransactions(transactions); + List report = reportService.generateReport(storage); + writerService.writeToFile(OUTPUT_FILE, report); + } + + private static Map initializeStrategies() { + Map operationStrategies = new HashMap<>(); + operationStrategies.put("b", new BalanceOperationStrategy()); + operationStrategies.put("s", new SupplyOperationStrategy()); + operationStrategies.put("p", new PurchaseOperationStrategy()); + operationStrategies.put("r", new ReturnOperationStrategy()); + return operationStrategies; + } +} diff --git a/src/main/java/core/basesyntax/db/Storage.java b/src/main/java/core/basesyntax/db/Storage.java new file mode 100644 index 0000000000..643ee9f785 --- /dev/null +++ b/src/main/java/core/basesyntax/db/Storage.java @@ -0,0 +1,47 @@ +package core.basesyntax.db; + +import core.basesyntax.model.FruitTransaction; +import java.util.HashMap; +import java.util.Map; + +public class Storage { + private static Storage instance; + private final Map fruitInventory; + + private Storage() { + this.fruitInventory = new HashMap<>(); + } + + public static Storage getInstance() { + if (instance == null) { + instance = new Storage(); + } + return instance; + } + + public Map getFruitInventory() { + return new HashMap<>(fruitInventory); + } + + public void updateFruitQuantity(FruitTransaction.Operation operation, + String fruitName, int quantity) { + int currentQuantity = fruitInventory.getOrDefault(fruitName, 0); + switch (operation) { + case BALANCE: + case SUPPLY: + case RETURN: + currentQuantity += quantity; + break; + case PURCHASE: + currentQuantity -= quantity; + break; + default: + throw new IllegalArgumentException("Unknown operation type: " + operation); + } + if (currentQuantity < 0) { + throw new IllegalArgumentException("Negative fruit quantity not allowed: " + fruitName); + } + + fruitInventory.put(fruitName, currentQuantity); + } +} diff --git a/src/main/java/core/basesyntax/model/FruitTransaction.java b/src/main/java/core/basesyntax/model/FruitTransaction.java new file mode 100644 index 0000000000..f92340cbb1 --- /dev/null +++ b/src/main/java/core/basesyntax/model/FruitTransaction.java @@ -0,0 +1,62 @@ +package core.basesyntax.model; + +public class FruitTransaction { + private Operation operation; + private String fruit; + private int quantity; + + public FruitTransaction(Operation operation, String fruit, int quantity) { + this.operation = operation; + this.fruit = fruit; + this.quantity = quantity; + } + + public Operation getOperation() { + return operation; + } + + public void setOperation(Operation operation) { + this.operation = operation; + } + + public String getFruit() { + return fruit; + } + + public void setFruit(String fruit) { + this.fruit = fruit; + } + + public int getQuantity() { + return quantity; + } + + public void setQuantity(int quantity) { + this.quantity = quantity; + } + + public enum Operation { + BALANCE("b"), + SUPPLY("s"), + PURCHASE("p"), + RETURN("r"); + private final String code; + + Operation(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public static Operation fromCode(String code) { + for (Operation operation : Operation.values()) { + if (operation.getCode().equals(code)) { + return operation; + } + } + throw new IllegalArgumentException("Unknown operation code: " + code); + } + } +} diff --git a/src/main/java/core/basesyntax/service/FruitService.java b/src/main/java/core/basesyntax/service/FruitService.java new file mode 100644 index 0000000000..00a62ab8d7 --- /dev/null +++ b/src/main/java/core/basesyntax/service/FruitService.java @@ -0,0 +1,8 @@ +package core.basesyntax.service; + +import core.basesyntax.model.FruitTransaction; +import java.util.List; + +public interface FruitService { + void processTransactions(List transaction); +} diff --git a/src/main/java/core/basesyntax/service/ParseService.java b/src/main/java/core/basesyntax/service/ParseService.java new file mode 100644 index 0000000000..333c551181 --- /dev/null +++ b/src/main/java/core/basesyntax/service/ParseService.java @@ -0,0 +1,8 @@ +package core.basesyntax.service; + +import core.basesyntax.model.FruitTransaction; +import java.util.List; + +public interface ParseService { + List parseTransactions(List inputLines); +} diff --git a/src/main/java/core/basesyntax/service/ReaderService.java b/src/main/java/core/basesyntax/service/ReaderService.java new file mode 100644 index 0000000000..cb74fd70ee --- /dev/null +++ b/src/main/java/core/basesyntax/service/ReaderService.java @@ -0,0 +1,7 @@ +package core.basesyntax.service; + +import java.util.List; + +public interface ReaderService { + List readFromFile(String filePath); +} diff --git a/src/main/java/core/basesyntax/service/ReportService.java b/src/main/java/core/basesyntax/service/ReportService.java new file mode 100644 index 0000000000..80bb18f864 --- /dev/null +++ b/src/main/java/core/basesyntax/service/ReportService.java @@ -0,0 +1,8 @@ +package core.basesyntax.service; + +import core.basesyntax.db.Storage; +import java.util.List; + +public interface ReportService { + List generateReport(Storage storage); +} diff --git a/src/main/java/core/basesyntax/service/WriterService.java b/src/main/java/core/basesyntax/service/WriterService.java new file mode 100644 index 0000000000..f86b573439 --- /dev/null +++ b/src/main/java/core/basesyntax/service/WriterService.java @@ -0,0 +1,7 @@ +package core.basesyntax.service; + +import java.util.List; + +public interface WriterService { + void writeToFile(String filePath, List lines); +} diff --git a/src/main/java/core/basesyntax/service/impl/FruitServiceImpl.java b/src/main/java/core/basesyntax/service/impl/FruitServiceImpl.java new file mode 100644 index 0000000000..a33efb85ab --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/FruitServiceImpl.java @@ -0,0 +1,24 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.FruitService; +import core.basesyntax.strategy.OperationStrategy; +import java.util.List; +import java.util.Map; + +public class FruitServiceImpl implements FruitService { + private final Map operationStrategies; + + public FruitServiceImpl(Map operationStrategies) { + this.operationStrategies = operationStrategies; + } + + @Override + public void processTransactions(List transaction) { + for (FruitTransaction fruitTransaction : transaction) { + FruitTransaction.Operation operationType = fruitTransaction.getOperation(); + OperationStrategy strategy = operationStrategies.get(operationType.getCode()); + strategy.applyStrategy(fruitTransaction); + } + } +} diff --git a/src/main/java/core/basesyntax/service/impl/ParseServiceImpl.java b/src/main/java/core/basesyntax/service/impl/ParseServiceImpl.java new file mode 100644 index 0000000000..0aab858c6f --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/ParseServiceImpl.java @@ -0,0 +1,20 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.ParseService; +import java.util.ArrayList; +import java.util.List; + +public class ParseServiceImpl implements ParseService { + public List parseTransactions(List inputLines) { + List fruitList = new ArrayList<>(); + for (String line : inputLines) { + line = line.trim(); + String[] transaction = line.split("\\s*,\\s*"); + fruitList.add(new FruitTransaction(FruitTransaction.Operation.fromCode(transaction[0]), + transaction[1], + Integer.parseInt(transaction[2]))); + } + return fruitList; + } +} diff --git a/src/main/java/core/basesyntax/service/impl/ReaderServiceImpl.java b/src/main/java/core/basesyntax/service/impl/ReaderServiceImpl.java new file mode 100644 index 0000000000..ec16a76def --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/ReaderServiceImpl.java @@ -0,0 +1,24 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.service.ReaderService; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ReaderServiceImpl implements ReaderService { + @Override + public List readFromFile(String filePath) { + List lines = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader((filePath)))) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + } catch (IOException e) { + throw new RuntimeException("Error reading file: " + filePath, e); + } + return lines; + } +} diff --git a/src/main/java/core/basesyntax/service/impl/ReportServiceImpl.java b/src/main/java/core/basesyntax/service/impl/ReportServiceImpl.java new file mode 100644 index 0000000000..b1ca667911 --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/ReportServiceImpl.java @@ -0,0 +1,22 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.db.Storage; +import core.basesyntax.service.ReportService; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ReportServiceImpl implements ReportService { + public List generateReport(Storage storage) { + List report = new ArrayList<>(); + report.add("fruit,quantity"); + for (Map.Entry entry : storage.getFruitInventory().entrySet()) { + String fruitName = entry.getKey(); + int quantity = entry.getValue(); + String quantityString = (quantity >= 0) ? String.valueOf(quantity) : "-" + (-quantity); + String reportLine = fruitName + "," + quantityString; + report.add(reportLine); + } + return report; + } +} diff --git a/src/main/java/core/basesyntax/service/impl/WriterServiceImpl.java b/src/main/java/core/basesyntax/service/impl/WriterServiceImpl.java new file mode 100644 index 0000000000..04efe5b169 --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/WriterServiceImpl.java @@ -0,0 +1,21 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.service.WriterService; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +public class WriterServiceImpl implements WriterService { + @Override + public void writeToFile(String filePath, List lines) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter((filePath)))) { + for (String line : lines) { + writer.write(line); + writer.newLine(); + } + } catch (IOException e) { + throw new RuntimeException("Error writing to file: " + filePath, e); + } + } +} diff --git a/src/main/java/core/basesyntax/strategy/BalanceOperationStrategy.java b/src/main/java/core/basesyntax/strategy/BalanceOperationStrategy.java new file mode 100644 index 0000000000..c58fe7bcb9 --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/BalanceOperationStrategy.java @@ -0,0 +1,14 @@ +package core.basesyntax.strategy; + +import core.basesyntax.db.Storage; +import core.basesyntax.model.FruitTransaction; + +public class BalanceOperationStrategy implements OperationStrategy { + @Override + public void applyStrategy(FruitTransaction transaction) { + String fruitName = transaction.getFruit(); + int quantity = transaction.getQuantity(); + Storage storage = Storage.getInstance(); + storage.updateFruitQuantity(FruitTransaction.Operation.BALANCE, fruitName, quantity); + } +} diff --git a/src/main/java/core/basesyntax/strategy/OperationStrategy.java b/src/main/java/core/basesyntax/strategy/OperationStrategy.java new file mode 100644 index 0000000000..954cbc6cc5 --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/OperationStrategy.java @@ -0,0 +1,7 @@ +package core.basesyntax.strategy; + +import core.basesyntax.model.FruitTransaction; + +public interface OperationStrategy { + void applyStrategy(FruitTransaction transaction); +} diff --git a/src/main/java/core/basesyntax/strategy/PurchaseOperationStrategy.java b/src/main/java/core/basesyntax/strategy/PurchaseOperationStrategy.java new file mode 100644 index 0000000000..3eb1509bff --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/PurchaseOperationStrategy.java @@ -0,0 +1,15 @@ +package core.basesyntax.strategy; + +import core.basesyntax.db.Storage; +import core.basesyntax.model.FruitTransaction; + +public class PurchaseOperationStrategy implements OperationStrategy { + @Override + public void applyStrategy(FruitTransaction transaction) { + String fruitName = transaction.getFruit(); + int quantity = transaction.getQuantity(); + Storage storage = Storage.getInstance(); + storage.updateFruitQuantity(FruitTransaction + .Operation.PURCHASE, fruitName, quantity); + } +} diff --git a/src/main/java/core/basesyntax/strategy/ReturnOperationStrategy.java b/src/main/java/core/basesyntax/strategy/ReturnOperationStrategy.java new file mode 100644 index 0000000000..1b40e2f684 --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/ReturnOperationStrategy.java @@ -0,0 +1,14 @@ +package core.basesyntax.strategy; + +import core.basesyntax.db.Storage; +import core.basesyntax.model.FruitTransaction; + +public class ReturnOperationStrategy implements OperationStrategy { + @Override + public void applyStrategy(FruitTransaction transaction) { + String fruitName = transaction.getFruit(); + int quantity = transaction.getQuantity(); + Storage storage = Storage.getInstance(); + storage.updateFruitQuantity(FruitTransaction.Operation.RETURN, fruitName, quantity); + } +} diff --git a/src/main/java/core/basesyntax/strategy/SupplyOperationStrategy.java b/src/main/java/core/basesyntax/strategy/SupplyOperationStrategy.java new file mode 100644 index 0000000000..9464558b44 --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/SupplyOperationStrategy.java @@ -0,0 +1,14 @@ +package core.basesyntax.strategy; + +import core.basesyntax.db.Storage; +import core.basesyntax.model.FruitTransaction; + +public class SupplyOperationStrategy implements OperationStrategy { + @Override + public void applyStrategy(FruitTransaction transaction) { + String fruitName = transaction.getFruit(); + int quantity = transaction.getQuantity(); + Storage storage = Storage.getInstance(); + storage.updateFruitQuantity(FruitTransaction.Operation.SUPPLY, fruitName, quantity); + } +}