summaryrefslogtreecommitdiff
path: root/calendar_manager.py
diff options
context:
space:
mode:
authormatin <matin.kaufmann@gmail.com>2025-09-12 20:45:28 +0200
committermatin <matin.kaufmann@gmail.com>2025-09-12 20:45:28 +0200
commit95d784fb414c6270e560fc0cf7ed289765ddd3ab (patch)
tree31f66d2c230634d9325beb82f1125876a3a63e30 /calendar_manager.py
parent315bdeffd7b8c7c1a1792cb91d25ff0ac17fecda (diff)
AI refactoring (see architecture analysis and refactoring_summary)
Diffstat (limited to 'calendar_manager.py')
-rw-r--r--calendar_manager.py234
1 files changed, 130 insertions, 104 deletions
diff --git a/calendar_manager.py b/calendar_manager.py
index f6ec0db..72a7b3b 100644
--- a/calendar_manager.py
+++ b/calendar_manager.py
@@ -1,122 +1,99 @@
# calendar_manager.py
-import json
-import uuid
from datetime import datetime
-
-class CalendarEntry:
- def __init__(self, start_date, end_date, keyword, entry_id=None, corrected_start_date=None, corrected_end_date=None, time_period=None, commentary: str = ""):
- self.id = entry_id if entry_id else str(uuid.uuid4())
- # Convert string dates to datetime if necessary
- self.start_date = (
- datetime.fromisoformat(start_date)
- if isinstance(start_date, str)
- else start_date
- )
- self.end_date = (
- datetime.fromisoformat(end_date)
- if isinstance(end_date, str)
- else end_date
- )
- self.keyword = keyword
- self.corrected_start_date = corrected_start_date
- self.corrected_end_date = corrected_end_date
- self.time_period = time_period
- self.commentary = commentary
- def to_dict(self):
- return {
- 'id': self.id,
- 'start_date': self.start_date.isoformat(),
- 'end_date': self.end_date.isoformat(),
- 'keyword': self.keyword,
- 'corrected_start_date': self.corrected_start_date.isoformat() if self.corrected_start_date else None,
- 'corrected_end_date': self.corrected_end_date.isoformat() if self.corrected_end_date else None,
- 'commentary': self.commentary,
- }
-
- @classmethod
- def from_dict(cls, data):
- return cls(
- start_date=datetime.fromisoformat(data['start_date']),
- end_date=datetime.fromisoformat(data['end_date']),
- keyword=data['keyword'],
- entry_id=data['id'],
- corrected_start_date=datetime.fromisoformat(data['corrected_start_date']) if data.get('corrected_start_date') else None,
- corrected_end_date=datetime.fromisoformat(data['corrected_end_date']) if data.get('corrected_end_date') else None,
- commentary=data.get('commentary', ""),
- )
-
- def __repr__(self):
- return (f"CalendarEntry(id={self.id}, start_date={self.start_date}, "
- f"end_date={self.end_date}, keyword='{self.keyword}', "
- f"corrected_start_date={self.corrected_start_date}, corrected_end_date={self.corrected_end_date})")
+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:
- def __init__(self, filename=None):
+ """Manages calendar entries with CRUD operations and data integrity"""
+
+ def __init__(self, filename: Optional[str] = None):
self.filename = filename
- self.entries = []
+ self.entries: List[CalendarEntry] = []
if filename:
- self.entries = self.add_entries_from_file(filename)
+ self.load_file(filename)
- def switch_file(self, new_filename):
- """Switch to a new file."""
+ 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):
- """Clears current entries and loads entries from new file."""
+ def load_file(self, new_filename: str) -> bool:
+ """Clear current entries and load entries from new file"""
self.clear_entries()
- self.add_entries_from_file(new_filename)
- self.switch_file(new_filename)
+ 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):
- """Add events from another JSON file to the current calendar."""
- try:
- with open(file_path, 'r') as f:
- data = json.load(f)
- new_entries = [CalendarEntry.from_dict(entry) for entry in data]
- self.entries.extend(new_entries)
- self.save_entries()
- return new_entries
- except (FileNotFoundError, json.JSONDecodeError) as e:
- print(f"Error reading file {file_path}: {e}")
- return []
+ 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):
- """Save the current list of events to the file."""
+ def save_entries(self) -> bool:
+ """Save the current list of events to the file"""
if self.filename:
- try:
- with open(self.filename, 'w') as f:
- json.dump([entry.to_dict() for entry in self.entries], f, indent=4)
- except Exception as e:
- print(f"Error writing to file {self.filename}: {e}")
+ return FileService.save_calendar_to_file(self.entries, self.filename)
+ return False
- def add_entry(self, start_date, end_date, keyword, commentary: str = ""):
- """Add a new event to the calendar."""
- new_entry = CalendarEntry(start_date, end_date, keyword, commentary=commentary)
- self.entries.append(new_entry)
- self.save_entries()
- return new_entry
+ 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, start_date=None, end_date=None, keyword=None, commentary=None):
- """Modify an existing event by ID."""
+ 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 entry:
+ if not entry:
+ return None
+
+ try:
if start_date:
- entry.start_date = start_date
+ entry.start_date = datetime.fromisoformat(start_date)
if end_date:
- entry.end_date = 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
- return None
+
+ except Exception as e:
+ print(f"Error modifying entry: {e}")
+ return None
- def delete_entry(self, entry_id):
- """Delete an event by ID."""
+ 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)
@@ -124,27 +101,76 @@ class CalendarManager:
return entry
return None
- def get_entry_by_id(self, entry_id):
- """Get an event by its ID."""
+ 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 all calendar entries."""
- return self.entries
+ def list_entries(self) -> List[CalendarEntry]:
+ """List all calendar entries"""
+ return self.entries.copy() # Return copy to prevent external modification
- def correct_dates(self, list_of_events):
+ 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
- for start_date, end_date, original_id in list_of_events:
+ # 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 not entry:
- continue
-
- entry.corrected_start_date = start_date
- entry.corrected_end_date = end_date
+ 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")
- \ No newline at end of file
+ except ValueError:
+ errors.append("Invalid date format")
+
+ if not EventTypeHandler.validate_event_type(keyword):
+ errors.append(f"Invalid keyword: {keyword}")
+
+ return errors \ No newline at end of file