Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/.idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 75 additions & 0 deletions src/manager/CSVTaskConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package manager;

import model.Epic;
import model.Subtask;
import model.Task;
import model.TaskType;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class CSVTaskConverter {

public static String taskToString(Task task) {
StringBuilder sb = new StringBuilder();
sb.append(task.getId()).append(",");
sb.append(task.getType()).append(",");
sb.append(task.getTitle()).append(",");
sb.append(task.getStatus()).append(",");
sb.append(task.getDescription()).append(",");
if (task instanceof Subtask) {
sb.append(((Subtask) task).getEpicId());
} else {
sb.append("");
}
return sb.toString();
}

public static String historyToString(List<Task> history) {
return history.stream()
.map(t -> String.valueOf(t.getId()))
.collect(Collectors.joining(","));
}

public static Task fromString(String value) {
String[] parts = value.split(",", 6);
int id = Integer.parseInt(parts[0]);
TaskType type = TaskType.valueOf(parts[1]);
String title = parts[2];
Status status = Status.valueOf(parts[3]);
String description = parts[4];
String epicField = parts.length > 5 ? parts[5] : "";

switch (type) {
case TASK:
Task task = new Task(title, description, status);
task.setId(id);
return task;
case EPIC:
Epic epic = new Epic(title, description);
epic.setId(id);
return epic;
case SUBTASK:
int epicId = epicField.isEmpty() ? -1 : Integer.parseInt(epicField);
Subtask subtask = new Subtask(title, description, epicId, status);
subtask.setId(id);
return subtask;
default:
throw new IllegalArgumentException("Неизвестный тип задачи: " + type);
}
}

public static List<Integer> historyFromString(String value) {
if (value == null || value.isEmpty()) {
return Collections.emptyList();
}
String[] parts = value.split(",");
List<Integer> historyIds = new ArrayList<>();
for (String part : parts) {
historyIds.add(Integer.parseInt(part));
}
return historyIds;
}
}
208 changes: 208 additions & 0 deletions src/manager/FileBackedTaskManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
package manager;

import model.*;

import java.io.*;
import java.nio.file.Files;
import java.util.List;


public class FileBackedTaskManager extends InMemoryTaskManager {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В классе Managers метод getDefault() должен теперь возвращать FileBackedTaskManager, это будет основной реализацией
Тесты для InMemoryTaskManager надо подкорректировать, если там getDefault используется

private static final String CSV_HEADER = "id,type,name,status,description,epic";

private final File file;

public FileBackedTaskManager(File file) {
super(Managers.getDefaultHistory());
this.file = file;
}

protected void save() {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
writer.write(CSV_HEADER);
writer.newLine();

for (Task task : getAllTasks()) {
writer.write(CSVTaskConverter.taskToString(task));
writer.newLine();
}

for (Epic epic : getAllEpics()) {
writer.write(CSVTaskConverter.taskToString(epic));
writer.newLine();
}

for (Subtask subtask : getAllSubtasks()) {
writer.write(CSVTaskConverter.taskToString(subtask));
writer.newLine();
}

writer.newLine();

writer.write(CSVTaskConverter.historyToString(getHistory()));

} catch (IOException e) {
throw new ManagerSaveException("Ошибка сохранения в файл " + file.getAbsolutePath(), e);
}
}

public static FileBackedTaskManager loadFromFile(File file) {
FileBackedTaskManager manager = new FileBackedTaskManager(file);

try {
List<String> lines = Files.readAllLines(file.toPath());

int i = 0;
if (!lines.isEmpty() && lines.get(0).equals("id,type,name,status,description,epic")) {
i++;
}

while (i < lines.size() && !lines.get(i).isEmpty()) {
Task task = CSVTaskConverter.fromString(lines.get(i));
if (task.getType() == TaskType.EPIC) {
manager.epics.put(task.getId(), (Epic) task);
} else if (task.getType() == TaskType.SUBTASK) {
manager.subtasks.put(task.getId(), (Subtask) task);
} else {
manager.tasks.put(task.getId(), task);
}
if (task.getId() >= manager.idCounter) {
manager.idCounter = task.getId() + 1;
}
i++;
}

i++;

if (i < lines.size()) {
List<Integer> historyIds = CSVTaskConverter.historyFromString(lines.get(i));
for (Integer id : historyIds) {
Task task = manager.tasks.get(id);
if (task == null) {
task = manager.epics.get(id);
}
if (task == null) {
task = manager.subtasks.get(id);
}
if (task != null) {
manager.historyManager.add(task);
}
}
}

for (Subtask subtask : manager.subtasks.values()) {
Epic epic = manager.epics.get(subtask.getEpicId());
if (epic != null) {
if (!epic.getSubtaskIds().contains(subtask.getId())) {
epic.addSubtask(subtask.getId());
}
}
}

for (Epic epic : manager.epics.values()) {
manager.updateEpicStatus(epic);
}

} catch (IOException e) {
throw new ManagerSaveException("Ошибка загрузки из файла " + file.getAbsolutePath(), e);
}

return manager;
}

@Override
public Task createTask(Task task) {
Task t = super.createTask(task);
save();
return t;
}

@Override
public Epic createEpic(Epic epic) {
Epic e = super.createEpic(epic);
save();
return e;
}

@Override
public Subtask createSubtask(Subtask subtask) {
Subtask s = super.createSubtask(subtask);
save();
return s;
}

@Override
public void updateTask(Task task) {
super.updateTask(task);
save();
}

@Override
public void updateEpic(Epic epic) {
super.updateEpic(epic);
save();
}

@Override
public void updateSubtask(Subtask subtask) {
super.updateSubtask(subtask);
save();
}

@Override
public void deleteTask(int taskId) {
super.deleteTask(taskId);
save();
}

@Override
public void deleteEpic(int epicId) {
super.deleteEpic(epicId);
save();
}

@Override
public void deleteSubtask(int subtaskId) {
super.deleteSubtask(subtaskId);
save();
}

@Override
public void deleteAllTasks() {
super.deleteAllTasks();
save();
}

@Override
public void deleteAllEpics() {
super.deleteAllEpics();
save();
}

@Override
public void deleteAllSubtasks() {
super.deleteAllSubtasks();
save();
}

@Override
public Task getTaskById(int id) {
Task task = super.getTaskById(id);
save();
return task;
}

@Override
public Epic getEpicById(int id) {
Epic epic = super.getEpicById(id);
save();
return epic;
}

@Override
public Subtask getSubtaskById(int id) {
Subtask subtask = super.getSubtaskById(id);
save();
return subtask;
}
}
12 changes: 6 additions & 6 deletions src/manager/InMemoryTaskManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
import java.util.List;

public class InMemoryTaskManager implements TaskManager {
private HashMap<Integer, Task> tasks = new HashMap<>();
private HashMap<Integer, Subtask> subtasks = new HashMap<>();
private HashMap<Integer, Epic> epics = new HashMap<>();
private HistoryManager historyManager;
private int idCounter = 1;
protected HashMap<Integer, Task> tasks = new HashMap<>();
protected HashMap<Integer, Subtask> subtasks = new HashMap<>();
protected HashMap<Integer, Epic> epics = new HashMap<>();
protected HistoryManager historyManager;
protected int idCounter = 1;

public InMemoryTaskManager(HistoryManager historyManager) {
this.historyManager = historyManager;
Expand Down Expand Up @@ -196,7 +196,7 @@ public List<Subtask> getSubtasksByEpicId(int epicId) {
return epicSubtasks;
}

private void updateEpicStatus(Epic epic) {
protected void updateEpicStatus(Epic epic) {
int doneCount = 0;
int newCount = 0;

Expand Down
7 changes: 7 additions & 0 deletions src/manager/ManagerSaveException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package manager;

public class ManagerSaveException extends RuntimeException {
public ManagerSaveException(String message, Throwable cause) {
super(message, cause);
}
}
8 changes: 7 additions & 1 deletion src/manager/Managers.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package manager;

import java.io.File;

public class Managers {

public static TaskManager getDefault() {
return new InMemoryTaskManager(getDefaultHistory());
File file = new File("tasks.csv");
if (!file.exists()) {
return new FileBackedTaskManager(file);
}
return FileBackedTaskManager.loadFromFile(file);
}

public static HistoryManager getDefaultHistory() {
Expand Down
5 changes: 5 additions & 0 deletions src/model/Epic.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,9 @@ public boolean addSubtask(int subtaskId) {
public List<Integer> getSubtaskIds() {
return subtaskIds;
}

@Override
public TaskType getType() {
return TaskType.EPIC;
}
}
5 changes: 5 additions & 0 deletions src/model/Subtask.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ public Subtask(String title, String description, int epicId, Status status) {
public int getEpicId() {
return epicId;
}

@Override
public TaskType getType() {
return TaskType.SUBTASK;
}
}
6 changes: 5 additions & 1 deletion src/model/Task.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class Task {
public Task(String title, String description, Status status) {
this.title = title;
this.description = description;
this.status = Status.NEW;
this.status = status;
}

public String getTitle() {
Expand Down Expand Up @@ -48,6 +48,10 @@ public void setId(int id) {
this.id = id;
}

public TaskType getType() {
return TaskType.TASK;
}


@Override
public boolean equals(Object o) {
Expand Down
7 changes: 7 additions & 0 deletions src/model/TaskType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package model;

public enum TaskType {
TASK,
EPIC,
SUBTASK
}
1 change: 1 addition & 0 deletions src/out/production/java-kanban/.idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading