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