diff --git a/src/main/java/core/basesyntax/HelloWorld.java b/src/main/java/core/basesyntax/HelloWorld.java deleted file mode 100644 index 05f94be41b..0000000000 --- a/src/main/java/core/basesyntax/HelloWorld.java +++ /dev/null @@ -1,9 +0,0 @@ -package core.basesyntax; - -/** - * Feel free to remove this class and create your own. - */ -public class HelloWorld { - // HINT: In the `public static void main(String[] args)` it is better to create instances of your classes, - // and call their methods, but do not write any business logic in the `main` method! -} diff --git a/src/main/java/core/basesyntax/Main.java b/src/main/java/core/basesyntax/Main.java new file mode 100644 index 0000000000..612bbf2c9b --- /dev/null +++ b/src/main/java/core/basesyntax/Main.java @@ -0,0 +1,54 @@ +package core.basesyntax; + +import db.Storage; +import java.io.FileNotFoundException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import model.FruitTransaction; +import service.DataConverter; +import service.FileReader; +import service.ReportGenerator; +import service.ShopService; +import service.impl.DataConverterImpl; +import service.impl.FileReaderImpl; +import service.impl.FileWriterImpl; +import service.impl.OperationStrategyImpl; +import service.impl.ReportGeneratorImpl; +import service.impl.ShopServiceImpl; +import service.operation.BalanceOperation; +import service.operation.OperationHandler; +import service.operation.PurchaseOperation; +import service.operation.ReturnOperation; +import service.operation.SupplyOperation; +import strategy.OperationStrategy; + +public class Main { + private static final String REPORT_TO_READ_FILE = "src/main/resources/reportToRead.csv"; + private static final String FINAL_REPORT_FILE = "src/main/resources/finalReport.csv"; + + public static void main(String[] args) throws FileNotFoundException { + FileReader fileReader = new FileReaderImpl(); + List inputReport = fileReader.read(REPORT_TO_READ_FILE); + + DataConverter dataConverter = new DataConverterImpl(); + + Map operationHandlers = new HashMap<>(); + operationHandlers.put(FruitTransaction.Operation.BALANCE, new BalanceOperation()); + operationHandlers.put(FruitTransaction.Operation.PURCHASE, new PurchaseOperation()); + operationHandlers.put(FruitTransaction.Operation.RETURN, new ReturnOperation()); + operationHandlers.put(FruitTransaction.Operation.SUPPLY, new SupplyOperation()); + OperationStrategy operationStrategy = new OperationStrategyImpl(operationHandlers); + + List transactions = dataConverter.convertToTransaction(inputReport); + ShopService shopService = new ShopServiceImpl(operationStrategy); + shopService.process(transactions); + + Storage storage = new Storage(); + ReportGenerator reportGenerator = new ReportGeneratorImpl(storage); + String resultingReport = reportGenerator.getReport(); + + FileWriterImpl fileWriter = new FileWriterImpl(); + fileWriter.write(FINAL_REPORT_FILE, resultingReport); + } +} diff --git a/src/main/java/db/Storage.java b/src/main/java/db/Storage.java new file mode 100644 index 0000000000..8c2ce06d6b --- /dev/null +++ b/src/main/java/db/Storage.java @@ -0,0 +1,27 @@ +package db; + +import java.util.HashMap; +import java.util.Map; + +public class Storage { + private static final Map fruits = new HashMap<>(); + + public static void add(String fruit, Integer amount) { + fruits.put(fruit, fruits.getOrDefault(fruit, 0) + amount); + } + + public static void remove(String fruit, Integer amount) { + if (!fruits.containsKey(fruit) || fruits.get(fruit) < amount) { + throw new IllegalArgumentException("Not enough " + fruit + " in storage."); + } + fruits.put(fruit, fruits.get(fruit) - amount); + } + + public static int getAmount(String fruit) { + return fruits.getOrDefault(fruit, 0); + } + + public Map getAllFruits() { + return new HashMap<>(fruits); + } +} diff --git a/src/main/java/model/FruitTransaction.java b/src/main/java/model/FruitTransaction.java new file mode 100644 index 0000000000..15b01e34af --- /dev/null +++ b/src/main/java/model/FruitTransaction.java @@ -0,0 +1,57 @@ +package model; + +public class FruitTransaction { + private Operation operation; + private String fruit; + private int 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 String code; + + Operation(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public static FruitTransaction.Operation getOperationFromCode(String code) { + for (FruitTransaction.Operation operation : FruitTransaction.Operation.values()) { + if (operation.getCode().equals(code)) { + return operation; + } + } + throw new IllegalArgumentException("Unknown operation: " + code); + } + } +} diff --git a/src/main/java/service/DataConverter.java b/src/main/java/service/DataConverter.java new file mode 100644 index 0000000000..ff03c46ce3 --- /dev/null +++ b/src/main/java/service/DataConverter.java @@ -0,0 +1,8 @@ +package service; + +import java.util.List; +import model.FruitTransaction; + +public interface DataConverter { + List convertToTransaction(List reportLines); +} diff --git a/src/main/java/service/FileReader.java b/src/main/java/service/FileReader.java new file mode 100644 index 0000000000..5b7963ea88 --- /dev/null +++ b/src/main/java/service/FileReader.java @@ -0,0 +1,8 @@ +package service; + +import java.io.FileNotFoundException; +import java.util.List; + +public interface FileReader { + List read(String fileName) throws FileNotFoundException; +} diff --git a/src/main/java/service/ReportGenerator.java b/src/main/java/service/ReportGenerator.java new file mode 100644 index 0000000000..3137dd0bae --- /dev/null +++ b/src/main/java/service/ReportGenerator.java @@ -0,0 +1,5 @@ +package service; + +public interface ReportGenerator { + String getReport(); +} diff --git a/src/main/java/service/ShopService.java b/src/main/java/service/ShopService.java new file mode 100644 index 0000000000..e7bb77b168 --- /dev/null +++ b/src/main/java/service/ShopService.java @@ -0,0 +1,8 @@ +package service; + +import java.util.List; +import model.FruitTransaction; + +public interface ShopService { + void process(List fruitTransactionList); +} diff --git a/src/main/java/service/impl/DataConverterImpl.java b/src/main/java/service/impl/DataConverterImpl.java new file mode 100644 index 0000000000..8a652885c1 --- /dev/null +++ b/src/main/java/service/impl/DataConverterImpl.java @@ -0,0 +1,32 @@ +package service.impl; + +import java.util.ArrayList; +import java.util.List; +import model.FruitTransaction; +import service.DataConverter; + +public class DataConverterImpl implements DataConverter { + private static final String COMMA_SEPARATOR = ","; + private static final int OPERATION_PARAMETER = 0; + private static final int FRUIT_PARAMETER = 1; + private static final int QUANTITY_PARAMETER = 2; + + @Override + public List convertToTransaction(List report) { + List fruitTransactionList = new ArrayList<>(); + for (int i = 1; i < report.size(); i++) { + FruitTransaction fruitTransaction = getFromCsvRow(report.get(i)); + fruitTransactionList.add(fruitTransaction); + } + return fruitTransactionList; + } + + private FruitTransaction getFromCsvRow(String row) { + String[] fields = row.split(COMMA_SEPARATOR); + FruitTransaction fruitTransaction = new FruitTransaction(); + fruitTransaction.setOperation(FruitTransaction.Operation.getOperationFromCode(fields[0])); + fruitTransaction.setFruit(fields[1]); + fruitTransaction.setQuantity(Integer.parseInt(fields[2])); + return fruitTransaction; + } +} diff --git a/src/main/java/service/impl/FileReaderImpl.java b/src/main/java/service/impl/FileReaderImpl.java new file mode 100644 index 0000000000..e996e6a9d9 --- /dev/null +++ b/src/main/java/service/impl/FileReaderImpl.java @@ -0,0 +1,27 @@ +package service.impl; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import service.FileReader; + +public class FileReaderImpl implements FileReader { + + public FileReaderImpl() { + + } + + @Override + public List read(String fileName) { + File file = new File(fileName); + if (!file.exists()) { + throw new IllegalArgumentException("File not found: " + fileName); + } + try { + return Files.readAllLines(file.toPath()); + } catch (IOException e) { + throw new RuntimeException("Error reading file: " + fileName, e); + } + } +} diff --git a/src/main/java/service/impl/FileWriterImpl.java b/src/main/java/service/impl/FileWriterImpl.java new file mode 100644 index 0000000000..6bec4688b8 --- /dev/null +++ b/src/main/java/service/impl/FileWriterImpl.java @@ -0,0 +1,17 @@ +package service.impl; + +import java.io.FileWriter; +import java.io.IOException; + +public class FileWriterImpl { + public void write(String filePath, String content) { + if (!AutoCloseable.class.isAssignableFrom(FileWriter.class)) { + throw new IllegalStateException("FileWriter does not implement AutoCloseable"); + } + try (FileWriter fileWriter = new FileWriter(filePath)) { + fileWriter.write(content); + } catch (IOException e) { + throw new RuntimeException("Error writing to file: " + filePath, e); + } + } +} diff --git a/src/main/java/service/impl/OperationStrategyImpl.java b/src/main/java/service/impl/OperationStrategyImpl.java new file mode 100644 index 0000000000..c254a26ecc --- /dev/null +++ b/src/main/java/service/impl/OperationStrategyImpl.java @@ -0,0 +1,20 @@ +package service.impl; + +import java.util.Map; +import model.FruitTransaction; +import service.operation.OperationHandler; +import strategy.OperationStrategy; + +public class OperationStrategyImpl implements OperationStrategy { + private Map operationHandlerMap; + + public OperationStrategyImpl(Map operationHandlerMap) { + this.operationHandlerMap = operationHandlerMap; + } + + @Override + public OperationHandler get(FruitTransaction.Operation operationType) { + return operationHandlerMap.get(operationType); + } +} diff --git a/src/main/java/service/impl/ReportGeneratorImpl.java b/src/main/java/service/impl/ReportGeneratorImpl.java new file mode 100644 index 0000000000..864d92c258 --- /dev/null +++ b/src/main/java/service/impl/ReportGeneratorImpl.java @@ -0,0 +1,31 @@ +package service.impl; + +import db.Storage; +import java.util.Map; +import service.ReportGenerator; + +public class ReportGeneratorImpl implements ReportGenerator { + private static final String HEADER = "fruit,amount"; + private static final String COMMA_DELIMITER = ","; + private final Storage storage; + + public ReportGeneratorImpl(Storage storage) { + this.storage = storage; + } + + @Override + public String getReport() { + StringBuilder report = new StringBuilder(); + Map fruits = storage.getAllFruits(); + + report.append(HEADER).append(System.lineSeparator()); + for (Map.Entry entry : fruits.entrySet()) { + report.append(entry.getKey()) + .append(COMMA_DELIMITER) + .append(entry.getValue()) + .append(System.lineSeparator()); + } + + return report.toString(); + } +} diff --git a/src/main/java/service/impl/ShopServiceImpl.java b/src/main/java/service/impl/ShopServiceImpl.java new file mode 100644 index 0000000000..c14a264f68 --- /dev/null +++ b/src/main/java/service/impl/ShopServiceImpl.java @@ -0,0 +1,23 @@ +package service.impl; + +import java.util.List; +import model.FruitTransaction; +import service.ShopService; +import service.operation.OperationHandler; +import strategy.OperationStrategy; + +public class ShopServiceImpl implements ShopService { + private final OperationStrategy operationStrategy; + + public ShopServiceImpl(OperationStrategy operationStrategy) { + this.operationStrategy = operationStrategy; + } + + @Override + public void process(List fruitTransactionList) { + for (FruitTransaction transaction : fruitTransactionList) { + OperationHandler handler = operationStrategy.get(transaction.getOperation()); + handler.performOperation(transaction); + } + } +} diff --git a/src/main/java/service/operation/BalanceOperation.java b/src/main/java/service/operation/BalanceOperation.java new file mode 100644 index 0000000000..0b92f515f5 --- /dev/null +++ b/src/main/java/service/operation/BalanceOperation.java @@ -0,0 +1,11 @@ +package service.operation; + +import db.Storage; +import model.FruitTransaction; + +public class BalanceOperation implements OperationHandler { + @Override + public void performOperation(FruitTransaction fruitTransaction) { + Storage.add(fruitTransaction.getFruit(), fruitTransaction.getQuantity()); + } +} diff --git a/src/main/java/service/operation/OperationHandler.java b/src/main/java/service/operation/OperationHandler.java new file mode 100644 index 0000000000..42da5ad189 --- /dev/null +++ b/src/main/java/service/operation/OperationHandler.java @@ -0,0 +1,7 @@ +package service.operation; + +import model.FruitTransaction; + +public interface OperationHandler { + void performOperation(FruitTransaction fruitTransaction); +} diff --git a/src/main/java/service/operation/PurchaseOperation.java b/src/main/java/service/operation/PurchaseOperation.java new file mode 100644 index 0000000000..840c68a4b2 --- /dev/null +++ b/src/main/java/service/operation/PurchaseOperation.java @@ -0,0 +1,11 @@ +package service.operation; + +import db.Storage; +import model.FruitTransaction; + +public class PurchaseOperation implements OperationHandler { + @Override + public void performOperation(FruitTransaction fruitTransaction) { + Storage.remove(fruitTransaction.getFruit(), fruitTransaction.getQuantity()); + } +} diff --git a/src/main/java/service/operation/ReturnOperation.java b/src/main/java/service/operation/ReturnOperation.java new file mode 100644 index 0000000000..8f6a6ce230 --- /dev/null +++ b/src/main/java/service/operation/ReturnOperation.java @@ -0,0 +1,11 @@ +package service.operation; + +import db.Storage; +import model.FruitTransaction; + +public class ReturnOperation implements OperationHandler { + @Override + public void performOperation(FruitTransaction fruitTransaction) { + Storage.add(fruitTransaction.getFruit(), fruitTransaction.getQuantity()); + } +} diff --git a/src/main/java/service/operation/SupplyOperation.java b/src/main/java/service/operation/SupplyOperation.java new file mode 100644 index 0000000000..2096dd30ee --- /dev/null +++ b/src/main/java/service/operation/SupplyOperation.java @@ -0,0 +1,11 @@ +package service.operation; + +import db.Storage; +import model.FruitTransaction; + +public class SupplyOperation implements OperationHandler { + @Override + public void performOperation(FruitTransaction fruitTransaction) { + Storage.add(fruitTransaction.getFruit(), fruitTransaction.getQuantity()); + } +} diff --git a/src/main/java/strategy/OperationStrategy.java b/src/main/java/strategy/OperationStrategy.java new file mode 100644 index 0000000000..41daa7213d --- /dev/null +++ b/src/main/java/strategy/OperationStrategy.java @@ -0,0 +1,8 @@ +package strategy; + +import model.FruitTransaction; +import service.operation.OperationHandler; + +public interface OperationStrategy { + OperationHandler get(FruitTransaction.Operation operationType); +} diff --git a/src/main/resources/finalReport.csv b/src/main/resources/finalReport.csv new file mode 100644 index 0000000000..558daa08e4 --- /dev/null +++ b/src/main/resources/finalReport.csv @@ -0,0 +1,3 @@ +fruit,amount +banana,152 +apple,90 diff --git a/src/main/resources/reportToRead.csv b/src/main/resources/reportToRead.csv new file mode 100644 index 0000000000..c771f259d3 --- /dev/null +++ b/src/main/resources/reportToRead.csv @@ -0,0 +1,9 @@ +type,fruit,quantity +b,banana,20 +b,apple,100 +s,banana,100 +p,banana,13 +r,apple,10 +p,apple,20 +p,banana,5 +s,banana,50 \ No newline at end of file