fix
[enigma2.git] / lib / python / Components / TimerSanityCheck.py
1 import string
2 import NavigationInstance
3 from time import localtime
4 from Components.NimManager import nimmanager
5 from ServiceReference import ServiceReference
6 from enigma import iServiceInformation, eServiceCenter
7
8 class TimerSanityCheck:
9         def __init__(self, timerlist, newtimer=None):
10                 print "sanitycheck"
11                 self.timerlist = timerlist
12                 self.newtimer = newtimer
13                 self.simultimer = []
14                 self.rep_eventlist = []
15                 self.nrep_eventlist = []
16                 self.bflag = -1
17                 self.eflag = 1
18
19         def check(self, ext_timer=1):
20                 print "check"
21                 if ext_timer != 1:
22                         self.newtimer = ext_timer
23                 if self.newtimer is None:
24                         self.simultimer = []
25                 else:
26                         self.simultimer = [ self.newtimer ]
27                 return self.checkTimerlist()
28
29         def getSimulTimerList(self):
30                 return self.simultimer
31
32         def doubleCheck(self):
33                 if self.newtimer is not None and self.newtimer.service_ref.ref.valid():
34                         self.simultimer = [ self.newtimer ]
35                         for timer in self.timerlist:
36                                 if (timer == self.newtimer):
37                                         return True
38                                 else:
39                                         if timer.begin == self.newtimer.begin:
40                                                 getUnsignedDataRef1 = timer.service_ref.ref.getUnsignedData
41                                                 getUnsignedDataRef2 = self.newtimer.service_ref.ref.getUnsignedData
42                                                 for x in range(1,5):
43                                                         if getUnsignedDataRef1(x) != getUnsignedDataRef2(x):
44                                                                 break;
45                                                 else:
46                                                         return True
47                 return False
48
49         def checkTimerlist(self, ext_timer=1):
50                 #with special service for external plugins
51                 # Entries in eventlist
52                 # timeindex
53                 # index -1 for the new Timer, 0..n index of the existing timers
54                 # BeginEndFlag -1 for begin, +1 for end
55                 # count of running timers
56
57                 print "checkTimerlist"
58 # create a list with all start and end times
59 # split it into recurring and singleshot timers
60
61 ##################################################################################
62 # process the new timer
63                 self.rep_eventlist = []
64                 self.nrep_eventlist = []
65                 if ext_timer != 1:
66                         self.newtimer = ext_timer
67                 if (self.newtimer is not None) and (not self.newtimer.disabled):
68                         if not self.newtimer.service_ref.ref.valid():
69                                 return False
70                         rflags = self.newtimer.repeated
71                         rflags = ((rflags & 0x7F)>> 3)|((rflags & 0x07)<<4)
72                         if rflags:
73                                 begin = self.newtimer.begin % 86400 # map to first day
74                                 while rflags: # then arrange on the week
75                                         if rflags & 1:
76                                                 self.rep_eventlist.append((begin, -1))
77                                         begin += 86400
78                                         rflags >>= 1
79                         else:
80                                 self.nrep_eventlist.extend([(self.newtimer.begin,-1,self.bflag),(self.newtimer.end,-1,self.eflag)])
81
82 ##################################################################################
83 # now process existing timers
84                 idx = 0
85                 for timer in self.timerlist:
86                         if (timer != self.newtimer) and (not timer.disabled):
87                                 if timer.repeated:
88                                         rflags = timer.repeated
89                                         rflags = ((rflags & 0x7F)>> 3)|((rflags & 0x07)<<4)
90                                         begin = timer.begin % 86400 # map all to first day
91                                         while rflags:
92                                                 if rflags & 1:
93                                                         self.rep_eventlist.append((begin, idx))
94                                                 begin += 86400
95                                                 rflags >>= 1
96                                 else:
97                                         self.nrep_eventlist.extend([(timer.begin,idx,self.bflag),(timer.end,idx,self.eflag)])
98                         idx += 1
99
100 ################################################################################
101 # journalize timer repeations
102                 if self.nrep_eventlist:
103                         interval_begin = min(self.nrep_eventlist)[0]
104                         interval_end = max(self.nrep_eventlist)[0]
105                         offset_0 = interval_begin - (interval_begin % 604800)
106                         weeks = (interval_end - offset_0) / 604800
107                         if ((interval_end - offset_0) % 604800):
108                                 weeks += 1
109                         for cnt in range(weeks):
110                                 for event in self.rep_eventlist:
111                                         if event[1] == -1: # -1 is the identifier of the changed timer
112                                                 event_begin = self.newtimer.begin
113                                                 event_end = self.newtimer.end
114                                         else:
115                                                 event_begin = self.timerlist[event[1]].begin
116                                                 event_end = self.timerlist[event[1]].end
117                                         new_event_begin = event[0] + offset_0 + (cnt * 604800)
118                                         # summertime correction
119                                         new_lth = localtime(new_event_begin).tm_hour
120                                         new_event_begin += 3600 * (localtime(event_begin).tm_hour - new_lth)
121                                         new_event_end = new_event_begin + (event_end - event_begin)
122                                         if event[1] == -1:
123                                                 if new_event_begin >= self.newtimer.begin: # is the soap already running?
124                                                         self.nrep_eventlist.extend([(new_event_begin, event[1], self.bflag),(new_event_end, event[1], self.eflag)])
125                                         else:
126                                                 if new_event_begin >= self.timerlist[event[1]].begin: # is the soap already running?
127                                                         self.nrep_eventlist.extend([(new_event_begin, event[1], self.bflag),(new_event_end, event[1], self.eflag)])
128                 else:
129                         offset_0 = 345600 # the Epoch begins on Thursday
130                         weeks = 2 # test two weeks to take care of Sunday-Monday transitions
131                         for cnt in range(weeks):
132                                 for event in self.rep_eventlist:
133                                         if event[1] == -1: # -1 is the identifier of the changed timer
134                                                 event_begin = self.newtimer.begin
135                                                 event_end = self.newtimer.end
136                                         else:
137                                                 event_begin = self.timerlist[event[1]].begin
138                                                 event_end = self.timerlist[event[1]].end
139                                         new_event_begin = event[0] + offset_0 + (cnt * 604800)
140                                         new_event_end = new_event_begin + (event_end - event_begin)
141                                         self.nrep_eventlist.extend([(new_event_begin, event[1], self.bflag),(new_event_end, event[1], self.eflag)])
142
143                 def sort_func(x, y):
144                         ret = cmp(x[0], y[0])
145                         if not ret:
146                                 ret = cmp(y[2], x[2])
147                                 if not ret:
148                                         return cmp(x[1], y[1])
149                         return ret
150 ################################################################################
151 # order list chronological
152                 self.nrep_eventlist.sort(sort_func)
153
154 ##################################################################################
155 # detect overlapping timers and overlapping times
156                 fakeRecList = []
157                 ConflictTimer = None
158                 ConflictTunerType = None
159                 ConflictSlot = None
160                 newTimerTunerType = None
161                 newTimerTunerSlot = None
162                 cnt = 0
163                 idx = 0
164                 overlaplist = []
165                 for event in self.nrep_eventlist:
166                         cnt -= event[2]
167                         if event[1] == -1: # new timer
168                                 timer = self.newtimer
169                         else:
170                                 timer = self.timerlist[event[1]]
171                         if event[2] == self.bflag:
172                                 fakeRecService = NavigationInstance.instance.recordService(timer.service_ref)
173                                 fakeRecResult = fakeRecService.start(True)
174                                 feinfo = fakeRecService.frontendInfo().getFrontendData()
175                                 tunerType = feinfo.get("tuner_type")
176                                 tunerSlot = feinfo.get("tuner_number")
177                                 if event[1] == -1: # new timer
178                                         newTimerTunerType = tunerType
179                                         newTimerTunerSlot = tunerSlot
180                                 overlaplist.append((fakeRecResult, timer, tunerType, tunerSlot))
181                                 fakeRecList.append((timer, fakeRecService))
182                                 if fakeRecResult:
183                                         if ConflictTimer is None: # just take care of the first conflict
184                                                 ConflictTimer = timer
185                                                 ConflictTunerType = tunerType
186                                                 ConflictTunerSlot = tunerSlot
187                         elif event[2] == self.eflag:
188                                 for fakeRec in fakeRecList:
189                                         if timer == fakeRec[0]:
190                                                 NavigationInstance.instance.stopRecordService(fakeRec[1])
191                                                 fakeRecList.remove(fakeRec)
192                                 del fakeRec
193                                 for entry in overlaplist:
194                                         if entry[1] == timer:
195                                                 overlaplist.remove(entry)
196                         else:
197                                 print "Bug: unknown flag!"
198                         self.nrep_eventlist[idx] = (event[0],event[1],event[2],cnt,overlaplist[:]) # insert a duplicate into current overlaplist
199                         idx += 1
200
201                 if ConflictTimer is None: # no conflict found :)
202                         return True
203
204 ##################################################################################
205 # we have detected a conflict, now we must figure out the involved timers
206
207                 if self.newtimer is not None: # new timer?
208                         if self.newtimer is not ConflictTimer: # the new timer is not the conflicting timer?
209                                 for event in self.nrep_eventlist:
210                                         if len(event[4]) > 1: # entry in overlaplist of this event??
211                                                 kt = False
212                                                 nt = False
213                                                 for entry in event[4]:
214                                                         if entry[1] is ConflictTimer:
215                                                                 kt = True
216                                                         if entry[1] is self.newtimer:
217                                                                 nt = True
218                                                 if nt and kt:
219                                                         ConflictTimer = self.newtimer
220                                                         ConflictTunerType = newTimerTunerType
221                                                         ConflictSlot = newTimerTunerSlot
222                                                         break
223
224                 self.simultimer = [ ConflictTimer ]
225                 for event in self.nrep_eventlist:
226                         if len(event[4]) > 1: # entry in overlaplist of this event??
227                                 for entry in event[4]:
228                                         if entry[1] is ConflictTimer:
229                                                 break
230                                 else:
231                                         continue
232                                 for entry in event[4]:
233                                         if not self.simultimer.count(entry[1]) and (entry[2] == ConflictTunerType or entry[3] == ConflictTunerSlot):
234                                                 self.simultimer.append(entry[1])
235
236                 if len(self.simultimer) < 2:
237                         print "Bug: unknown Conflict!"
238
239                 return False # conflict detected!