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