Skip to content

Commit af61b2a

Browse files
Update TaskManager handles all task operations including CRUD, file I/O, and filtering
1 parent fc3e972 commit af61b2a

File tree

1 file changed

+370
-0
lines changed

1 file changed

+370
-0
lines changed

src/main/java/TaskManager.java

Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
import com.google.gson.Gson;
2+
import com.google.gson.GsonBuilder;
3+
import com.google.gson.reflect.TypeToken;
4+
5+
import java.io.*;
6+
import java.lang.reflect.Type;
7+
import java.util.*;
8+
import java.util.stream.Collectors;
9+
10+
/**
11+
* TaskManager handles all task operations including CRUD, file I/O, and filtering
12+
*/
13+
public class TaskManager {
14+
private static final String TASKS_FILE = "tasks.json";
15+
private List<Task> tasks;
16+
private Gson gson;
17+
18+
public TaskManager() {
19+
this.tasks = new ArrayList<>();
20+
this.gson = new GsonBuilder().setPrettyPrinting().create();
21+
loadTasks();
22+
}
23+
24+
/**
25+
* Adds a new task with auto-categorization
26+
*
27+
* @param title The task title
28+
* @return The created task
29+
*/
30+
public Task addTask(String title) {
31+
if (title == null || title.trim().isEmpty()) {
32+
throw new IllegalArgumentException("Task title cannot be empty");
33+
}
34+
35+
String category = AICategorizer.categorizeTask(title);
36+
Task task = new Task(title.trim(), category);
37+
tasks.add(task);
38+
saveTasks();
39+
40+
System.out.println("\n✅ Task added successfully!");
41+
System.out.println("📝 Title: " + task.getTitle());
42+
System.out.println("🏷️ Category: " + task.getCategoryEmoji() + " " + task.getCategory());
43+
System.out.println("🎯 Confidence: " + String.format("%.0f%%", AICategorizer.getConfidenceScore(title, category) * 100));
44+
System.out.println(AICategorizer.getSuggestion(title));
45+
46+
return task;
47+
}
48+
49+
/**
50+
* Adds a task with manual category override
51+
*
52+
* @param title The task title
53+
* @param category The manual category
54+
* @return The created task
55+
*/
56+
public Task addTask(String title, String category) {
57+
if (title == null || title.trim().isEmpty()) {
58+
throw new IllegalArgumentException("Task title cannot be empty");
59+
}
60+
61+
if (!isValidCategory(category)) {
62+
category = AICategorizer.categorizeTask(title);
63+
System.out.println("⚠️ Invalid category provided. Auto-categorized as: " + category);
64+
}
65+
66+
Task task = new Task(title.trim(), category);
67+
tasks.add(task);
68+
saveTasks();
69+
70+
System.out.println("\n✅ Task added with manual category!");
71+
System.out.println("📝 Title: " + task.getTitle());
72+
System.out.println("🏷️ Category: " + task.getCategoryEmoji() + " " + task.getCategory());
73+
74+
return task;
75+
}
76+
77+
/**
78+
* Views all tasks with optional filtering
79+
*/
80+
public void viewAllTasks() {
81+
if (tasks.isEmpty()) {
82+
System.out.println("\n📭 No tasks found. Add some tasks to get started!");
83+
return;
84+
}
85+
86+
System.out.println("\n📋 ALL TASKS");
87+
System.out.println("=" .repeat(50));
88+
89+
for (int i = 0; i < tasks.size(); i++) {
90+
System.out.printf("%d. %s\n", i + 1, tasks.get(i).toString());
91+
}
92+
93+
printTaskSummary();
94+
}
95+
96+
/**
97+
* Views tasks by category
98+
*
99+
* @param category The category to filter by
100+
*/
101+
public void viewTasksByCategory(String category) {
102+
List<Task> filteredTasks = tasks.stream()
103+
.filter(task -> task.getCategory().equalsIgnoreCase(category))
104+
.collect(Collectors.toList());
105+
106+
if (filteredTasks.isEmpty()) {
107+
System.out.println("\n📭 No tasks found in category: " + category);
108+
return;
109+
}
110+
111+
System.out.println("\n📋 TASKS IN CATEGORY: " + category.toUpperCase());
112+
System.out.println("=" .repeat(50));
113+
114+
for (int i = 0; i < filteredTasks.size(); i++) {
115+
System.out.printf("%d. %s\n", i + 1, filteredTasks.get(i).toString());
116+
}
117+
}
118+
119+
/**
120+
* Views only pending tasks
121+
*/
122+
public void viewPendingTasks() {
123+
List<Task> pendingTasks = tasks.stream()
124+
.filter(task -> !task.isCompleted())
125+
.collect(Collectors.toList());
126+
127+
if (pendingTasks.isEmpty()) {
128+
System.out.println("\n🎉 Congratulations! No pending tasks. You're all caught up!");
129+
return;
130+
}
131+
132+
System.out.println("\n⏳ PENDING TASKS");
133+
System.out.println("=" .repeat(50));
134+
135+
for (int i = 0; i < pendingTasks.size(); i++) {
136+
System.out.printf("%d. %s\n", i + 1, pendingTasks.get(i).toString());
137+
}
138+
}
139+
140+
/**
141+
* Views only completed tasks
142+
*/
143+
public void viewCompletedTasks() {
144+
List<Task> completedTasks = tasks.stream()
145+
.filter(Task::isCompleted)
146+
.collect(Collectors.toList());
147+
148+
if (completedTasks.isEmpty()) {
149+
System.out.println("\n📭 No completed tasks yet. Complete some tasks to see them here!");
150+
return;
151+
}
152+
153+
System.out.println("\n✅ COMPLETED TASKS");
154+
System.out.println("=" .repeat(50));
155+
156+
for (int i = 0; i < completedTasks.size(); i++) {
157+
System.out.printf("%d. %s\n", i + 1, completedTasks.get(i).toString());
158+
}
159+
}
160+
161+
/**
162+
* Marks a task as complete by index
163+
*
164+
* @param index The task index (1-based)
165+
* @return true if successful, false otherwise
166+
*/
167+
public boolean completeTask(int index) {
168+
if (index < 1 || index > tasks.size()) {
169+
System.out.println("❌ Invalid task number. Please enter a number between 1 and " + tasks.size());
170+
return false;
171+
}
172+
173+
Task task = tasks.get(index - 1);
174+
if (task.isCompleted()) {
175+
System.out.println("ℹ️ Task is already completed: " + task.getTitle());
176+
return false;
177+
}
178+
179+
task.markComplete();
180+
saveTasks();
181+
182+
System.out.println("\n🎉 Task completed successfully!");
183+
System.out.println("✅ " + task.getTitle());
184+
185+
return true;
186+
}
187+
188+
/**
189+
* Deletes a task by index
190+
*
191+
* @param index The task index (1-based)
192+
* @return true if successful, false otherwise
193+
*/
194+
public boolean deleteTask(int index) {
195+
if (index < 1 || index > tasks.size()) {
196+
System.out.println("❌ Invalid task number. Please enter a number between 1 and " + tasks.size());
197+
return false;
198+
}
199+
200+
Task task = tasks.get(index - 1);
201+
tasks.remove(index - 1);
202+
saveTasks();
203+
204+
System.out.println("\n🗑️ Task deleted successfully!");
205+
System.out.println("❌ " + task.getTitle());
206+
207+
return true;
208+
}
209+
210+
/**
211+
* Searches tasks by keyword
212+
*
213+
* @param keyword The search keyword
214+
*/
215+
public void searchTasks(String keyword) {
216+
if (keyword == null || keyword.trim().isEmpty()) {
217+
System.out.println("❌ Search keyword cannot be empty");
218+
return;
219+
}
220+
221+
List<Task> matchingTasks = tasks.stream()
222+
.filter(task -> task.getTitle().toLowerCase().contains(keyword.toLowerCase()))
223+
.collect(Collectors.toList());
224+
225+
if (matchingTasks.isEmpty()) {
226+
System.out.println("\n🔍 No tasks found matching: " + keyword);
227+
return;
228+
}
229+
230+
System.out.println("\n🔍 SEARCH RESULTS FOR: " + keyword);
231+
System.out.println("=" .repeat(50));
232+
233+
for (int i = 0; i < matchingTasks.size(); i++) {
234+
System.out.printf("%d. %s\n", i + 1, matchingTasks.get(i).toString());
235+
}
236+
}
237+
238+
/**
239+
* Prints task summary statistics
240+
*/
241+
public void printTaskSummary() {
242+
int total = tasks.size();
243+
int completed = (int) tasks.stream().filter(Task::isCompleted).count();
244+
int pending = total - completed;
245+
246+
Map<String, Long> categoryCount = tasks.stream()
247+
.collect(Collectors.groupingBy(Task::getCategory, Collectors.counting()));
248+
249+
System.out.println("\n📊 TASK SUMMARY");
250+
System.out.println("-" .repeat(30));
251+
System.out.println("📝 Total Tasks: " + total);
252+
System.out.println("✅ Completed: " + completed);
253+
System.out.println("⏳ Pending: " + pending);
254+
255+
if (!categoryCount.isEmpty()) {
256+
System.out.println("\n📂 By Category:");
257+
categoryCount.forEach((category, count) -> {
258+
String emoji = getEmojiForCategory(category);
259+
System.out.println(" " + emoji + " " + category + ": " + count);
260+
});
261+
}
262+
263+
if (total > 0) {
264+
double completionRate = (double) completed / total * 100;
265+
System.out.printf("\n🎯 Completion Rate: %.1f%%\n", completionRate);
266+
}
267+
}
268+
269+
/**
270+
* Loads tasks from JSON file
271+
*/
272+
private void loadTasks() {
273+
File file = new File(TASKS_FILE);
274+
if (!file.exists()) {
275+
System.out.println("📁 Creating new tasks file: " + TASKS_FILE);
276+
return;
277+
}
278+
279+
try (FileReader reader = new FileReader(file)) {
280+
Type taskListType = new TypeToken<List<Task>>(){}.getType();
281+
List<Task> loadedTasks = gson.fromJson(reader, taskListType);
282+
283+
if (loadedTasks != null) {
284+
this.tasks = loadedTasks;
285+
System.out.println("📂 Loaded " + tasks.size() + " tasks from " + TASKS_FILE);
286+
}
287+
} catch (IOException e) {
288+
System.err.println("❌ Error loading tasks: " + e.getMessage());
289+
} catch (Exception e) {
290+
System.err.println("❌ Error parsing tasks file: " + e.getMessage());
291+
System.out.println("🔄 Starting with empty task list");
292+
}
293+
}
294+
295+
/**
296+
* Saves tasks to JSON file
297+
*/
298+
private void saveTasks() {
299+
try (FileWriter writer = new FileWriter(TASKS_FILE)) {
300+
gson.toJson(tasks, writer);
301+
} catch (IOException e) {
302+
System.err.println("❌ Error saving tasks: " + e.getMessage());
303+
}
304+
}
305+
306+
/**
307+
* Validates if a category is valid
308+
*
309+
* @param category The category to validate
310+
* @return true if valid, false otherwise
311+
*/
312+
private boolean isValidCategory(String category) {
313+
String[] validCategories = AICategorizer.getAvailableCategories();
314+
return Arrays.stream(validCategories)
315+
.anyMatch(cat -> cat.equalsIgnoreCase(category));
316+
}
317+
318+
/**
319+
* Gets emoji for a category
320+
*
321+
* @param category The category name
322+
* @return The corresponding emoji
323+
*/
324+
private String getEmojiForCategory(String category) {
325+
switch (category.toLowerCase()) {
326+
case "work": return "💼";
327+
case "personal": return "👤";
328+
case "urgent": return "🚨";
329+
default: return "📝";
330+
}
331+
}
332+
333+
/**
334+
* Gets the total number of tasks
335+
*
336+
* @return The total task count
337+
*/
338+
public int getTaskCount() {
339+
return tasks.size();
340+
}
341+
342+
/**
343+
* Gets the list of all tasks (read-only)
344+
*
345+
* @return Unmodifiable list of tasks
346+
*/
347+
public List<Task> getTasks() {
348+
return Collections.unmodifiableList(tasks);
349+
}
350+
351+
/**
352+
* Clears all completed tasks
353+
*
354+
* @return Number of tasks cleared
355+
*/
356+
public int clearCompletedTasks() {
357+
int initialSize = tasks.size();
358+
tasks.removeIf(Task::isCompleted);
359+
int removedCount = initialSize - tasks.size();
360+
361+
if (removedCount > 0) {
362+
saveTasks();
363+
System.out.println("\n🧹 Cleared " + removedCount + " completed task(s)");
364+
} else {
365+
System.out.println("\n📭 No completed tasks to clear");
366+
}
367+
368+
return removedCount;
369+
}
370+
}

0 commit comments

Comments
 (0)