summaryrefslogtreecommitdiff
path: root/calendar_manager.py
blob: 72a7b3bd3d0ed99557fb43502289cc21a8e1ab84 (plain)
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