1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
# calendar_manager.py
from datetime import datetime
from typing import List, Optional, Tuple
from file_service import FileService
from event_type_handler import EventTypeHandler
from date_service import DateService
from config import EventConfig
from calendar_entry import CalendarEntry
class CalendarManager:
"""Manages calendar entries with CRUD operations and data integrity"""
def __init__(self, filename: Optional[str] = None):
self.filename = filename
self.entries: List[CalendarEntry] = []
if filename:
self.load_file(filename)
def switch_file(self, new_filename: str):
"""Switch to a new file without loading data"""
self.filename = new_filename
def load_file(self, new_filename: str) -> bool:
"""Clear current entries and load entries from new file"""
self.clear_entries()
new_entries = FileService.load_calendar_from_file(new_filename)
if new_entries:
self.entries.extend(new_entries)
self.filename = new_filename
return True
return False
def add_entries_from_file(self, file_path: str) -> List[CalendarEntry]:
"""Add events from another JSON file to the current calendar"""
new_entries = FileService.load_calendar_from_file(file_path)
if new_entries:
self.entries.extend(new_entries)
self.save_entries()
return new_entries
def clear_entries(self):
"""Clear all entries from the calendar"""
self.entries = []
def save_entries(self) -> bool:
"""Save the current list of events to the file"""
if self.filename:
return FileService.save_calendar_to_file(self.entries, self.filename)
return False
def add_entry(self, start_date: str, end_date: str, keyword: str, commentary: str = "") -> Optional[CalendarEntry]:
"""Add a new event to the calendar with validation"""
try:
# Validate inputs
if not EventTypeHandler.validate_event_type(keyword):
raise ValueError(f"Invalid keyword: {keyword}")
# Create and add entry
new_entry = CalendarEntry(start_date, end_date, keyword, commentary=commentary)
self.entries.append(new_entry)
self.save_entries()
return new_entry
except Exception as e:
print(f"Error adding entry: {e}")
return None
def modify_entry(self, entry_id: str, start_date: Optional[str] = None,
end_date: Optional[str] = None, keyword: Optional[str] = None,
commentary: Optional[str] = None) -> Optional[CalendarEntry]:
"""Modify an existing event by ID with validation"""
entry = self.get_entry_by_id(entry_id)
if not entry:
return None
try:
if start_date:
entry.start_date = datetime.fromisoformat(start_date)
if end_date:
entry.end_date = datetime.fromisoformat(end_date)
if keyword:
if not EventTypeHandler.validate_event_type(keyword):
raise ValueError(f"Invalid keyword: {keyword}")
entry.keyword = keyword
if commentary is not None:
entry.commentary = commentary
self.save_entries()
return entry
except Exception as e:
print(f"Error modifying entry: {e}")
return None
def delete_entry(self, entry_id: str) -> Optional[CalendarEntry]:
"""Delete an event by ID"""
entry = self.get_entry_by_id(entry_id)
if entry:
self.entries.remove(entry)
self.save_entries()
return entry
return None
def get_entry_by_id(self, entry_id: str) -> Optional[CalendarEntry]:
"""Get an event by its ID"""
return next((entry for entry in self.entries if entry.id == entry_id), None)
def list_entries(self) -> List[CalendarEntry]:
"""List all calendar entries"""
return self.entries.copy() # Return copy to prevent external modification
def correct_dates(self, corrected_events: List[Tuple[datetime, datetime, str]]):
"""Apply corrected dates to calendar entries and calculate time_period"""
# Clear all corrections first
for entry in self.entries:
entry.corrected_start_date = None
entry.corrected_end_date = None
entry.time_period = None
# Apply corrections and calculate time_period
for start_date, end_date, original_id in corrected_events:
entry = self.get_entry_by_id(original_id)
if entry:
entry.corrected_start_date = start_date
entry.corrected_end_date = end_date
# Calculate and store time_period based on corrected dates
entry.time_period = self._calculate_time_period(entry)
def get_entries_by_keyword(self, keyword: str) -> List[CalendarEntry]:
"""Get all entries with a specific keyword"""
return [entry for entry in self.entries if entry.keyword == keyword]
def _calculate_time_period(self, entry: CalendarEntry) -> str:
"""Calculate time_period for an entry based on corrected dates"""
if not entry.corrected_start_date or not entry.corrected_end_date:
return ""
start_dt = entry.corrected_start_date
end_dt = entry.corrected_end_date
if end_dt < start_dt:
return ""
if entry.keyword == "Sonstige":
# For "Sonstige", show days
delta_days = DateService.calculate_days_between(start_dt, end_dt)
return f"{delta_days} Tage"
else:
# For EZ types, show months
total_months = DateService.calculate_months_between(start_dt, end_dt)
if entry.keyword == "EZ 50%":
# Half-time projects count as half months
total_months = (total_months + 1) // 2 # Round up
return f"{total_months} Monate"
def validate_entry_data(self, start_date: str, end_date: str, keyword: str) -> List[str]:
"""Validate entry data and return list of errors"""
errors = []
try:
start_dt = datetime.fromisoformat(start_date)
end_dt = datetime.fromisoformat(end_date)
if start_dt > end_dt:
errors.append("Start date cannot be after end date")
except ValueError:
errors.append("Invalid date format")
if not EventTypeHandler.validate_event_type(keyword):
errors.append(f"Invalid keyword: {keyword}")
return errors
|