· 7 years ago · Oct 26, 2018, 07:26 AM
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Text;
6using System.Threading.Tasks;
7using Microsoft.Azure.WebJobs;
8using System.Net.Mail;
9using CloudBeatHeavyDutyFcts.Code;
10using Microsoft.WindowsAzure.Storage.Queue;
11using CloudBeat.Code;
12using System.Text.RegularExpressions;
13using Microsoft.WindowsAzure.Storage;
14using System.Threading;
15using System.Data;
16
17namespace CloudBeatHeavyDutyFcts
18{
19 public class Functions
20 {
21 // This function will get triggered/executed when a new message is written
22 // on an Azure Queue called queue.
23 public static void ProcessQueueMessage([QueueTrigger("savedevents")] string message, TextWriter log)
24 {
25 SaveChangesToEpisodes(int.Parse(message));
26 }
27
28 /// <summary>
29 /// When a new event is accepted or rejected, it will affect the burden calcualtion.
30 /// It has to be included in the burden calculations and hence integrated in the Episodes table.
31 /// This function is only called for accepted events
32 /// </summary>
33 /// <param name="eventId">The ID of the event recently saved</param>
34 /// <returns></returns>
35 public static void SaveChangesToEpisodes(int eventId)
36 {
37
38 var parameters = eventId.ToString();
39 var context = new LifeSenseDBEntities();
40 try
41 {
42
43 var savedEvent = context.Events.FirstOrDefault(o => o.Id == eventId);
44 var savedEventPref = context.EventPreferences.FirstOrDefault(o => o.EventId == eventId);
45
46 var deviceEvents = new List<string>();
47 using (var storageContext = new StorageContext())
48 {
49 var studiesContainer = storageContext.BlobClient.GetContainerReference("studies");
50 studiesContainer.CreateIfNotExists();
51
52 var deviceActivityFile = studiesContainer.GetAppendBlobReference(savedEvent.StudyId + "/activity.csv");
53 if (deviceActivityFile.Exists())
54 {
55 OperationContext ctxt = new OperationContext();
56 ctxt.SendingRequest += (sender, e) =>
57 {
58 e.Request.Headers["if-match"] = "*";
59 };
60
61 using (AutoResetEvent waitHandle = new AutoResetEvent(false))
62 {
63 deviceActivityFile.StreamMinimumReadSizeInBytes = 16385;
64 var result = deviceActivityFile.BeginOpenRead(null, null, ctxt,
65 ar => waitHandle.Set(),
66 null);
67 waitHandle.WaitOne();
68 using (Stream blobStream = deviceActivityFile.EndOpenRead(result))
69 {
70
71 byte[] buffer = new byte[16 * 1024];
72 using (MemoryStream ms = new MemoryStream())
73 {
74 int read;
75 while ((read = blobStream.Read(buffer, 0, buffer.Length)) > 0)
76 {
77 ms.Write(buffer, 0, read);
78 }
79 string text = System.Text.Encoding.UTF8.GetString(ms.ToArray());
80 deviceEvents = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).Where(o => o.Length > 0).ToList();
81
82 }
83
84 }
85 }
86
87 }
88 }
89
90 //Check if the episode already exists
91 var eventDescription = savedEventPref.ActualEventDescription;
92 //Get the actual description of the event
93 //If the event is not an entry nor an exit, it's an episode on its own
94 var episode = context.Episodes.FirstOrDefault(o => o.StartEventId == eventId || o.EndEventId == eventId);
95 var settings = context.DeviceSettings.FirstOrDefault(o => o.StudyId == savedEvent.StudyId);
96 var samplingFrequency = 256;
97 if (settings != null)
98 {
99 samplingFrequency = settings.Rec_SampleRate.Value;
100 }
101 if (episode != null)
102 {
103 #region Previously Saved Event
104 //The event exists as a part of an episode, remove it to calculate
105
106 if (episode.StartEventId == eventId)
107 {
108 if (episode.EndEventId == eventId)
109 {
110 //The episode is removed from db
111 context.Episodes.Remove(episode);
112 if (savedEventPref.Accepted == false)
113 {
114 //Don't proceed to checking the event
115 context.SaveChanges();
116 context.Dispose();
117 return;
118 }
119
120 }
121 else
122 {
123 if (episode.EpisodeNoteType.Name == "Entry Exit")
124 {
125 //Those two parameters are used to check if there's episodes between the entry and the exit that were neglected and have to be reconsidered
126 var oldEpisodeStartTime = episode.StartTime;
127 var oldEpisodeEndTime = episode.EndTime;
128
129
130 //The event was the entry of the episode
131 episode.StartEventId = episode.EndEventId;
132
133 //Get the exit event
134 var currentExitEvent = context.Events.FirstOrDefault(o => o.Id == episode.EndEventId);
135
136 episode.StartTime = currentExitEvent.StartTime;
137 episode.EndTime = ((DateTime)currentExitEvent.StartTime).AddSeconds(((double)currentExitEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
138 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
139 context.SaveChanges();
140
141 //If the event is rejected, we must reconsider the episodes between the entry and the exit
142 if (savedEventPref.Accepted == false)
143 {
144 var eventType = eventDescription.Replace(" Entry", "").Replace(" Exit", "");
145 var episodeBetweenEntryExit = context.Events.Where(o => o.EventPreferences.Any(e => e.ActualEventDescription.Contains(eventType) && e.Accepted == true) && o.StartTime > oldEpisodeStartTime && o.StartTime < oldEpisodeEndTime);
146 if (episodeBetweenEntryExit != null)
147 {
148 var episodeBetweenEntryExitList = episodeBetweenEntryExit.ToList();
149 foreach (Event ev in episodeBetweenEntryExitList)
150 {
151 using (var storageContext = new StorageContext())
152 {
153 //Create a Queue Message
154 CloudQueueClient queueClient = storageContext.QueueClient;
155 // Retrieve a reference to a queue
156 CloudQueue queue = queueClient.GetQueueReference("savedevents");
157 // Create the queue if it doesn't already exist
158 queue.CreateIfNotExists();
159 // Create a message and add it to the queue.
160 CloudQueueMessage queueMessage = new CloudQueueMessage(ev.Id.ToString());
161
162 Console.WriteLine("Adding New Message: " + ev.Id);
163 queue.AddMessage(queueMessage);
164 }
165 }
166 }
167 }
168
169 if (savedEventPref.Accepted == false || !(eventDescription.Contains("Tachy") || eventDescription.Contains("Brady") || eventDescription.Contains("Atrial Fibrillation")))
170 {
171 using (var storageContext = new StorageContext())
172 {
173 //Create a Queue Message
174 CloudQueueClient queueClient = storageContext.QueueClient;
175 // Retrieve a reference to a queue
176 CloudQueue queue = queueClient.GetQueueReference("savedevents");
177 // Create the queue if it doesn't already exist
178 queue.CreateIfNotExists();
179 // Create a message and add it to the queue.
180 CloudQueueMessage queueMessage = new CloudQueueMessage(episode.StartEventId.ToString());
181
182 Console.WriteLine("Adding New Message: " + episode.StartEventId);
183 queue.AddMessage(queueMessage);
184 }
185
186 }
187 }
188 else
189 {
190 context.Episodes.Remove(episode);
191 context.SaveChanges();
192 }
193 }
194 }
195 else if (episode.EndEventId == eventId)
196 {
197 if (episode.EpisodeNoteType.Name == "Entry Exit")
198 {
199 //Those two parameters are used to check if there's episodes between the entry and the exit that were neglected and have to be reconsidered
200 var oldEpisodeStartTime = episode.StartTime;
201 var oldEpisodeEndTime = episode.EndTime;
202
203 //The event was the exit of the episode
204 episode.EndEventId = episode.StartEventId;
205
206 //Get the entry event
207 var currentEntryEvent = context.Events.FirstOrDefault(o => o.Id == episode.StartEventId);
208
209 episode.StartTime = ((DateTime)currentEntryEvent.StartTime).AddSeconds(((double)currentEntryEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
210 episode.EndTime = currentEntryEvent.EndTime;
211 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
212 context.SaveChanges();
213
214 //If the event is rejected, we must reconsider the episodes between the entry and the exit
215 if (savedEventPref.Accepted == false)
216 {
217 var eventType = eventDescription.Replace(" Entry", "").Replace(" Exit", "");
218 var episodeBetweenEntryExit = context.Events.Where(o => o.EventPreferences.Any(e => e.ActualEventDescription.Contains(eventType) && e.Accepted == true) && o.StartTime > oldEpisodeStartTime && o.StartTime < oldEpisodeEndTime);
219 if (episodeBetweenEntryExit != null)
220 {
221 var episodeBetweenEntryExitList = episodeBetweenEntryExit.ToList();
222 foreach (Event ev in episodeBetweenEntryExitList)
223 {
224 using (var storageContext = new StorageContext())
225 {
226 //Create a Queue Message
227 CloudQueueClient queueClient = storageContext.QueueClient;
228 // Retrieve a reference to a queue
229 CloudQueue queue = queueClient.GetQueueReference("savedevents");
230 // Create the queue if it doesn't already exist
231 queue.CreateIfNotExists();
232 // Create a message and add it to the queue.
233 CloudQueueMessage queueMessage = new CloudQueueMessage(ev.Id.ToString());
234 Console.WriteLine("Adding New Messasge: " + ev.Id);
235 queue.AddMessage(queueMessage);
236 }
237 }
238 }
239 }
240
241 if (savedEventPref.Accepted == false || !(eventDescription.Contains("Tachy") || eventDescription.Contains("Brady") || eventDescription.Contains("Atrial Fibrillation")))
242 {
243 using (var storageContext = new StorageContext())
244 {
245 //Create a Queue Message
246 CloudQueueClient queueClient = storageContext.QueueClient;
247 // Retrieve a reference to a queue
248 CloudQueue queue = queueClient.GetQueueReference("savedevents");
249 // Create the queue if it doesn't already exist
250 queue.CreateIfNotExists();
251 // Create a message and add it to the queue.
252 CloudQueueMessage queueMessage = new CloudQueueMessage(episode.StartEventId.ToString());
253 Console.WriteLine("Adding New Messasge: " + episode.StartEventId);
254 queue.AddMessage(queueMessage);
255 }
256 context.Dispose();
257 context = new LifeSenseDBEntities();
258 }
259 }
260 else
261 {
262 context.Episodes.Remove(episode);
263 context.SaveChanges();
264 }
265 }
266 #endregion
267 }
268
269
270 if (eventDescription.Contains("Tachy") || eventDescription.Contains("Brady") || eventDescription.Contains("Atrial Fibrillation"))
271 {
272 #region Re-calculating the episodes
273 //The episode doens't exist, Add the event as an episode if it's accepted
274 if (savedEventPref.Accepted == true)
275 {
276
277 //Check if it's an entry, an exit or an episode
278 var studyId = savedEvent.StudyId;
279 if (!eventDescription.Contains("Entry") && !eventDescription.Contains("Exit"))
280 {
281 #region Episode
282 //The event is an episode
283 var type = "";
284 if (eventDescription.Contains("Tachy"))
285 {
286 type = "Tachycardia";
287 }
288 else if (eventDescription.Contains("Brady"))
289 {
290 type = "Bradycardia";
291 }
292 else if (eventDescription.Contains("Atrial Fibrillation"))
293 {
294 type = "Atrial Fibrillation";
295 }
296 //Check if it's between an entry and an exit of the same type
297 var episodeContainingTheEvent = context.Episodes.FirstOrDefault(o => o.EventsType.Description.Contains(type) && o.StartTime < savedEvent.StartTime && o.EndTime > savedEvent.StartTime && o.CalculationInfo == 5 && o.StudyId == studyId);//5 stands for the Entry Exit Episode Type
298 if (episodeContainingTheEvent == null)
299 {
300 //if there's no episode containing the saved event, consider as an episode itself
301 //Otherwise, Don't add it to the list of episodes
302 episode = new Episode
303 {
304 StudyId = (int)studyId,
305 StartTime = ((DateTime)savedEvent.StartTime).AddSeconds(((double)savedEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency),
306 EndTime = savedEvent.EndTime,
307 StartEventId = savedEvent.Id,
308 EndEventId = savedEvent.Id,
309 EventType = context.EventsTypes.FirstOrDefault(o => o.Description == savedEventPref.ActualEventDescription).Id,
310 CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id
311 };
312 context.Episodes.Add(episode);
313 context.SaveChanges();
314 }
315 #endregion
316
317 }
318 else
319 {
320
321 //Get the accepted events in that day
322 var study = context.Studies.FirstOrDefault(o => o.Id == studyId);
323 var patientUTC = context.Patients.FirstOrDefault(o => o.Id == study.PatientId).UTCMinutes;
324 var date = ((DateTime)savedEvent.StartTime).AddMinutes(double.Parse(patientUTC.ToString())).Date.AddMinutes(-double.Parse(patientUTC.ToString()));
325 var nextDate = date.AddDays(1);
326 var allAcceptedEvents = context.Events.Where(o => o.StudyId == studyId && o.StartTime >= date && o.EndTime <= nextDate && o.EventPreferences.Any(e => e.Accepted == true)).OrderBy(o => o.StartTime).ToList();
327
328 //Get the current accepted event index from the list above
329 var currentEventIndex = allAcceptedEvents.FindIndex(o => o.Id == eventId);
330
331 //Check if it's entry or an exit
332 if (eventDescription.Contains("Entry"))
333 {
334 //It's an entry, look for the exit
335 //Look for an exit next to the event
336 //Get the event type
337 var eventType = Regex.Replace(savedEventPref.ActualEventDescription, " Entry", "");
338 //Get the next Exit event of the same type
339 var nextEvent = new Event();
340 if (currentEventIndex < allAcceptedEvents.Count() - 1)
341 {
342 nextEvent = allAcceptedEvents.FirstOrDefault(o => o.StartTime > savedEvent.StartTime && o.EventPreferences.First().ActualEventDescription.Contains("Exit") && o.EventPreferences.First().ActualEventDescription.Contains(eventType));
343 }
344 else
345 {
346 //The last event in the list
347 nextEvent = null;
348 }
349 if (nextEvent != null)
350 {
351 //There's an Exit Event of the same type
352 //Check if there's an entry in between
353 var entryInBetween = allAcceptedEvents.FirstOrDefault(o => o.StartTime > savedEvent.StartTime && o.StartTime < nextEvent.StartTime && o.EventPreferences.First().ActualEventDescription.Contains("Entry") && o.EventPreferences.First().ActualEventDescription.Contains(eventType));
354 if (entryInBetween != null)
355 {
356 #region consecutive entries
357
358
359 //Consider it as an episode
360 episode = new Episode();
361 episode.EventType = context.EventsTypes.FirstOrDefault(o => o.Description == savedEventPref.ActualEventDescription.Replace(" Entry", "")).Id;
362 episode.StudyId = (int)studyId;
363 episode.StartTime = ((DateTime)savedEvent.StartTime).AddSeconds(((double)savedEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
364 episode.EndTime = (DateTime)savedEvent.EndTime;
365 episode.StartEventId = savedEvent.Id;
366 episode.EndEventId = savedEvent.Id;
367 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
368 context.Episodes.Add(episode);
369 context.SaveChanges();
370 #endregion
371 }
372 else
373 {
374 #region Look for the real Exit
375 //Next we need to specify the exit
376 //Check if there's a 'Recording suspended' event
377
378 var deviceEvent = deviceEvents.FirstOrDefault(o => DateTime.Parse(o.Split(',')[0]) >= savedEvent.StartTime && DateTime.Parse(o.Split(',')[0]) <= nextEvent.StartTime && o.Split(',')[1] == "Recording Suspended");
379 if (deviceEvent != null)
380 {
381 //Add the "Recording Suspended" to the Results list as the exit of the entry
382 episode = new Episode();
383 episode.EventType = context.EventsTypes.FirstOrDefault(o => o.Description == savedEventPref.ActualEventDescription.Replace(" Entry", "")).Id;
384 episode.StudyId = (int)studyId;
385 episode.StartEventId = savedEvent.Id;
386 episode.StartTime = ((DateTime)savedEvent.StartTime).AddSeconds(((double)savedEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
387 var deviceEventTime = DateTime.Parse(deviceEvent.Split(',')[0]);
388 var existingEventsInBetween = context.Events.Any(o => o.StudyId == studyId && o.StartTime > savedEvent.StartTime && o.StartTime <= deviceEventTime);
389 if (!existingEventsInBetween)
390 {
391
392 //Add the "Recording Suspended" to the Results list as the exit of the entry
393 episode.EndTime = deviceEventTime;
394 episode.EndEventId = null;
395 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Recording Suspended").Id;
396
397 }
398 else
399 {
400 episode.EndTime = savedEvent.EndTime;
401 episode.EndEventId = savedEvent.Id;
402 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
403 }
404
405 context.Episodes.Add(episode);
406 context.SaveChanges();
407 }
408 else
409 {
410 //Check if there's an episode with this Exit Event
411 episode = context.Episodes.FirstOrDefault(o => o.EndEventId == nextEvent.Id);
412
413 if (episode != null)
414 {
415 if (episode.StartEventId != episode.EndEventId && episode.CalculationInfo == 5)
416 {
417 //Make the entry an episode itself
418 var oldStartEvent = context.Events.FirstOrDefault(o => o.Id == episode.StartEventId);
419 episode.EndTime = oldStartEvent.EndTime;
420 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
421 episode.EndEventId = episode.StartEventId;
422 context.SaveChanges();
423 context.Dispose();
424 context = new LifeSenseDBEntities();
425
426 }
427 else
428 {
429 context.Episodes.Remove(episode);
430 context.SaveChanges();
431 context.Dispose();
432 context = new LifeSenseDBEntities();
433 }
434 }
435
436 //Add a new Episode
437 episode = new Episode();
438 episode.EventType = context.EventsTypes.FirstOrDefault(o => o.Description == savedEventPref.ActualEventDescription.Replace(" Entry", "")).Id;
439 episode.StudyId = (int)studyId;
440 episode.StartEventId = savedEvent.Id;
441 episode.StartTime = ((DateTime)savedEvent.StartTime).AddSeconds(((double)savedEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
442 episode.EndTime = ((DateTime)nextEvent.StartTime).AddSeconds(((double)nextEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
443 episode.EndEventId = nextEvent.Id;
444 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Entry Exit").Id;
445 context.Episodes.Add(episode);
446 context.SaveChanges();
447
448 //Check if there are episodes of the same type in between (No entry and No exit)
449 var type = "";
450 if (eventDescription.Contains("Tachy"))
451 {
452 type = "Tachycardia";
453 }
454 else if (eventDescription.Contains("Brady"))
455 {
456 type = "Bradycardia";
457 }
458 else if (eventDescription.Contains("Atrial Fibrillation"))
459 {
460 type = "Atrial Fibrillation";
461 }
462 var existingEpisodesInBetween = context.Episodes.Where(o => o.EventsType.Description.Contains(type) && o.StartTime > episode.StartTime && o.EndTime < episode.EndTime && o.CalculationInfo == 1);//1 stands for the 'Episode' episode calculation type
463 if (existingEpisodesInBetween != null)
464 {
465 var existingEpisodesInBetweenList = existingEpisodesInBetween.ToList();
466 //Delete all the episodes as they are taken in consideration of the entry exit episode
467 foreach (Episode ep in existingEpisodesInBetweenList)
468 {
469 context.Episodes.Remove(ep);
470 context.SaveChanges();
471 }
472 }
473 }
474
475
476 #endregion
477 }
478 }
479 else
480 {
481 //No exit is detected
482 #region No Exit is Detected
483
484
485 //Add a new Episode
486 episode = new Episode();
487 episode.EventType = context.EventsTypes.FirstOrDefault(o => o.Description == savedEventPref.ActualEventDescription.Replace(" Entry", "")).Id;
488 episode.StudyId = (int)studyId;
489 //Make the event as the start of the episode
490 episode.StartEventId = savedEvent.Id;
491 episode.StartTime = ((DateTime)savedEvent.StartTime).AddSeconds(((double)savedEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
492
493 //Add the default end paramteres as the event is an episode
494 episode.EndEventId = savedEvent.Id;
495 episode.EndTime = savedEvent.EndTime;
496 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
497
498 //Check if it's the last event in the list
499 var eventDate = (DateTime)savedEvent.StartTime;
500 var endOfDay = eventDate.AddMinutes(double.Parse(patientUTC.ToString())).AddDays(1).Date.AddMinutes(-double.Parse(patientUTC.ToString()));
501
502
503
504 if (currentEventIndex == allAcceptedEvents.Count() - 1)
505 {
506 //Check if there's a 'Recording suspended' eventdeviceEvents
507 var deviceEvent = deviceEvents.FirstOrDefault(o => DateTime.Parse(o.Split(',')[0]) >= savedEvent.StartTime && DateTime.Parse(o.Split(',')[0]) <= endOfDay && o.Split(',')[1] == "Recording Suspended");
508 if (deviceEvent != null)
509 {
510 //Found a 'Recording suspended' event after that event
511
512 //Check if there's events between the event and the recording suspended event
513 var deviceEventTime = DateTime.Parse(deviceEvent.Split(',')[0]);
514 var existingEventsInBetween = context.Events.Any(o => o.StudyId == studyId && o.StartTime > savedEvent.StartTime && o.StartTime < deviceEventTime);
515 if (!existingEventsInBetween)
516 {
517
518 //Add the "Recording Suspended" to the Results list as the exit of the entry
519 episode.EndTime = deviceEventTime;
520 episode.EndEventId = null;
521 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Recording Suspended").Id;
522 context.SaveChanges();
523 }
524 //Else keep the default values saved when the episode is added
525 }
526 else
527 {
528 //No recording suspended, The end of the episode will be by the end of the day
529 episode.EndTime = endOfDay;
530 episode.EndEventId = savedEvent.Id;
531 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "End of Day").Id;
532 var eventsBeforeEndofDay = context.Events.Any(o => o.StudyId == studyId && o.StartTime > savedEvent.StartTime && o.StartTime <= endOfDay);
533 if (eventsBeforeEndofDay)
534 {
535 //Consider the event as an episode, and the Exit is the end of the Event
536 episode.EndTime = savedEvent.EndTime;
537 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
538
539 }
540
541 //Check the study start time. Note that study time is in the real time not utc
542 var studyEndTime = ((DateTime)study.EndTime).AddMinutes(-double.Parse(patientUTC.ToString()));
543 if (endOfDay > studyEndTime)
544 {
545 //Make the study end time as the exit and convert it to UTC (Because it is saved on patient time)
546 episode.EndTime = studyEndTime;
547
548 }
549 context.SaveChanges();
550 }
551 }
552 else
553 {
554 //It's not the last one in the list
555
556
557 //check if there's recording suspended in between
558 var deviceEvent = deviceEvents.FirstOrDefault(o => DateTime.Parse(o.Split(',')[0]) > savedEvent.StartTime && DateTime.Parse(o.Split(',')[0]) <= endOfDay && o.Split(',')[1] == "Recording Suspended");
559 if (deviceEvent != null)
560 {
561 var deviceEventTime = DateTime.Parse(deviceEvent.Split(',')[0]);
562 var eventExistsInBetween = context.Events.Any(o => o.StudyId == studyId && o.StartTime > savedEvent.StartTime && o.StartTime <= deviceEventTime);
563 if (!eventExistsInBetween)
564 {
565
566 episode.EndTime = deviceEventTime;
567 episode.EndEventId = null;
568 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Recording Suspended").Id;
569
570
571
572 }
573 //Else keep the default values saved when the episode is added
574 }
575 }
576 context.Episodes.Add(episode);
577 #endregion
578 }
579 }
580
581
582 else
583 {
584 //It's an exit, look for the entry
585 //Look for an entry that precedes the event
586 var lastEvent = new Event();
587 //Get the event type
588 var eventType = Regex.Replace(savedEventPref.ActualEventDescription, " Exit", "");
589
590 if (currentEventIndex > 0)
591 {
592
593 lastEvent = allAcceptedEvents.LastOrDefault(o => o.StartTime < savedEvent.StartTime && o.EventPreferences.First().ActualEventDescription.Contains("Entry") && o.EventPreferences.First().ActualEventDescription.Contains(eventType));
594 }
595 else
596 {
597 //The first event in the list
598 lastEvent = null;
599 }
600 if (lastEvent != null)
601 {
602 //There's an Entry Event of the same type
603 //Check if there's an exit in between in between
604 var exitInBetween = allAcceptedEvents.FirstOrDefault(o => o.StartTime < savedEvent.StartTime && o.StartTime > lastEvent.StartTime && o.EventPreferences.First().ActualEventDescription.Contains("Exit") && o.EventPreferences.First().ActualEventDescription.Contains(eventType));
605 if (exitInBetween != null)
606 {
607 //Consider it as an episode
608 episode = new Episode();
609 episode.EventType = context.EventsTypes.FirstOrDefault(o => o.Description == savedEventPref.ActualEventDescription.Replace(" Exit", "")).Id;
610 episode.StudyId = (int)studyId;
611 episode.StartTime = (DateTime)savedEvent.StartTime;
612 episode.EndTime = ((DateTime)savedEvent.StartTime).AddSeconds(((double)savedEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
613 episode.StartEventId = savedEvent.Id;
614 episode.EndEventId = savedEvent.Id;
615 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
616 context.Episodes.Add(episode);
617 context.SaveChanges();
618 }
619 else
620 {
621
622 //Next we need to specify the actual entry
623 //Check if there's a 'Recording suspended' event
624 var deviceEvent = deviceEvents.FirstOrDefault(o => DateTime.Parse(o.Split(',')[0]) >= lastEvent.StartTime && DateTime.Parse(o.Split(',')[0]) <= savedEvent.StartTime && o.Split(',')[1] == "Recording Suspended");
625 if (deviceEvent != null)
626 {
627 //Add the "Recording Suspended" to the Results list as the exit of the entry
628 episode = new Episode();
629 episode.EventType = context.EventsTypes.FirstOrDefault(o => o.Description == savedEventPref.ActualEventDescription.Replace(" Exit", "")).Id;
630 episode.StudyId = (int)studyId;
631 episode.EndEventId = savedEvent.Id;
632 episode.EndTime = ((DateTime)savedEvent.StartTime).AddSeconds(((double)savedEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
633 var deviceEventTime = DateTime.Parse(deviceEvent.Split(',')[0]);
634 var existingEventsInBetween = context.Events.Any(o => o.StudyId == studyId && o.StartTime < savedEvent.StartTime && o.StartTime >= deviceEventTime);
635 if (!existingEventsInBetween)
636 {
637
638 //Add the "Recording Suspended" to the Results list as the exit of the entry
639 episode.StartTime = deviceEventTime;
640 episode.StartEventId = null;
641 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Recording Suspended").Id;
642
643 }
644 else
645 {
646 episode.StartTime = savedEvent.StartTime;
647 episode.StartEventId = savedEvent.Id;
648 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
649
650 }
651
652 context.Episodes.Add(episode);
653 context.SaveChanges();
654 }
655 else
656 {
657 //Check if there's an episode with this Entry Event
658 episode = context.Episodes.FirstOrDefault(o => o.StartEventId == lastEvent.Id);
659 if (episode != null)
660 {
661 if (episode.StartEventId != episode.EndEventId && episode.CalculationInfo == 5)
662 {
663 //Make the entry an episode itself
664 var oldExit = context.Events.FirstOrDefault(o => o.Id == episode.EndEventId);
665 episode.StartEventId = episode.EndEventId;
666 episode.StartTime = oldExit.StartTime;
667 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
668 context.SaveChanges();
669 context.Dispose();
670 context = new LifeSenseDBEntities();
671 }
672 else
673 {
674 context.Episodes.Remove(episode);
675 context.SaveChanges();
676 context.Dispose();
677 context = new LifeSenseDBEntities();
678 }
679 }
680
681 //Add a new Episode
682 episode = new Episode();
683 episode.EndEventId = savedEvent.Id;
684 episode.EndTime = ((DateTime)savedEvent.StartTime).AddSeconds(((double)savedEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
685 episode.StudyId = (int)savedEvent.StudyId;
686 //Make the "Entry" as the start of the episode
687 episode.StartTime = ((DateTime)lastEvent.StartTime).AddSeconds(((double)lastEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
688 episode.StartEventId = lastEvent.Id;
689 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Entry Exit").Id;
690 episode.EventType = context.EventsTypes.FirstOrDefault(o => o.Description == savedEventPref.ActualEventDescription.Replace(" Exit", "")).Id;
691 context.Episodes.Add(episode);
692 context.SaveChanges();
693
694 //Check if there are episodes of the same type in between (No entry and No exit)
695 var type = "";
696 if (eventDescription.Contains("Tachy"))
697 {
698 type = "Tachycardia";
699 }
700 else if (eventDescription.Contains("Brady"))
701 {
702 type = "Bradycardia";
703 }
704 else if (eventDescription.Contains("Atrial Fibrillation"))
705 {
706 type = "Atrial Fibrillation";
707 }
708 var existingEpisodesInBetween = context.Episodes.Where(o => o.EventsType.Description.Contains(type) && o.StartTime > episode.StartTime && o.EndTime < episode.EndTime && o.CalculationInfo == 1);//1 stands for the 'Episode' episode calculation type
709 if (existingEpisodesInBetween != null)
710 {
711 var existingEpisodesInBetweenList = existingEpisodesInBetween.ToList();
712 //Delete all the episodes as they are taken in consideration of the entry exit episode
713 foreach (Episode ep in existingEpisodesInBetweenList)
714 {
715 context.Episodes.Remove(ep);
716 context.SaveChanges();
717 }
718 }
719 }
720
721 }
722
723 }
724 else
725 {
726 //No entry is detected
727
728 //Add a new Episode
729 episode = new Episode();
730 episode.EventType = context.EventsTypes.FirstOrDefault(o => o.Description == savedEventPref.ActualEventDescription.Replace(" Exit", "")).Id;
731 episode.StudyId = (int)studyId;
732 //Make the event as the start of the episode
733 episode.StartEventId = savedEvent.Id;
734 episode.StartTime = savedEvent.StartTime;
735
736 //Add the default end paramteres as the event is an episode
737 episode.EndEventId = savedEvent.Id;
738 episode.EndTime = ((DateTime)savedEvent.StartTime).AddSeconds(((double)savedEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
739 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
740
741 //Check if it's the last event in the list
742 var eventDate = (DateTime)savedEvent.StartTime;
743 var startOfDay = eventDate.AddMinutes(double.Parse(patientUTC.ToString())).Date.AddMinutes(-double.Parse(patientUTC.ToString()));
744
745 if (currentEventIndex == 0)
746 {
747 //Check if there's a 'Recording suspended' event
748 var deviceEvent = deviceEvents.FirstOrDefault(o => DateTime.Parse(o.Split(',')[0]) <= savedEvent.StartTime && DateTime.Parse(o.Split(',')[0]) >= startOfDay && o.Split(',')[0] == "Recording Suspended");
749 if (deviceEvent != null)
750 {
751 //Found a 'Recording suspended' event after that event
752
753 //Check if there's events between the event and the recording suspended event
754 var deviceEventTime = DateTime.Parse(deviceEvent.Split(',')[0]);
755 var existingEventsInBetween = context.Events.Any(o => o.StudyId == studyId && o.StartTime <= savedEvent.StartTime && o.StartTime >= deviceEventTime);
756 if (!existingEventsInBetween)
757 {
758
759 //Add the "Recording Suspended" to the Results list as the exit of the entry
760 episode.StartTime = deviceEventTime;
761 episode.StartEventId = null;
762 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Recording Suspended").Id;
763
764 }
765 //Else keep the default values saved when the episode is added
766 }
767 else
768 {
769 //No recording suspended, The start of the episode will be the start of the day
770 episode.StartTime = startOfDay;
771 episode.StartEventId = savedEvent.Id;
772 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Start of Day").Id;
773 var existingEventsInBetween = context.Events.Any(o => o.StudyId == studyId && o.StartTime < savedEvent.StartTime && o.StartTime >= startOfDay);
774 if (existingEventsInBetween)
775 {
776
777 //Add the "Recording Suspended" to the Results list as the exit of the entry
778 episode.StartTime = ((DateTime)savedEvent.StartTime).AddSeconds(((double)savedEvent.EventOccurredAtSample + (60 * samplingFrequency)) / samplingFrequency);
779 episode.StartEventId = savedEvent.Id;
780 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Episode").Id;
781
782 }
783
784 //Check the study start time
785 var studyStartTime = ((DateTime)study.StartTime).AddMinutes(-double.Parse(patientUTC.ToString()));
786 if (startOfDay < studyStartTime)
787 {
788 //Make the study start as the entry and convert it to UTC (Because it is saved on patient time)
789 episode.StartTime = (DateTime)studyStartTime;
790
791 }
792 }
793 }
794 else
795 {
796 //It's not the first one in the list
797
798
799 //check if there's recording suspended in between
800 var deviceEvent = deviceEvents.FirstOrDefault(o => DateTime.Parse(o.Split(',')[0]) <= savedEvent.StartTime && DateTime.Parse(o.Split(',')[0]) >= eventDate && o.Split(',')[0] == "Recording Suspended");
801 if (deviceEvent != null)
802 {
803 var deviceEventTime = DateTime.Parse(deviceEvent.Split(',')[0]);
804 var eventExistsInBetween = context.Events.Any(o => o.StudyId == studyId && o.StartTime >= savedEvent.StartTime && o.StartTime <= deviceEventTime);
805 if (!eventExistsInBetween)
806 {
807
808 episode.EndTime = deviceEventTime;
809 episode.EndEventId = null;
810 episode.CalculationInfo = context.EpisodeNoteTypes.FirstOrDefault(o => o.Name == "Recording Suspended").Id;
811
812
813 }
814 //Else keep the default values saved when the episode is added
815 }
816 }
817 context.Episodes.Add(episode);
818 }
819
820 }
821 }
822 }
823
824 }
825 #endregion
826 context.SaveChanges();
827 context.Dispose();
828 }
829 catch (Exception ex)
830 {
831
832 OptimisticConcurrencyException optConcEx = ex as OptimisticConcurrencyException;
833 if (optConcEx != null)
834 {
835 //Requeue the event
836 using (var storageContext = new StorageContext())
837 {
838 //Create a Queue Message
839 CloudQueueClient queueClient = storageContext.QueueClient;
840 // Retrieve a reference to a queue
841 CloudQueue queue = queueClient.GetQueueReference("savedevents");
842 // Create the queue if it doesn't already exist
843 queue.CreateIfNotExists();
844 // Create a message and add it to the queue.
845 CloudQueueMessage queueMessage = new CloudQueueMessage(eventId.ToString());
846
847 queue.AddMessage(queueMessage);
848 }
849 }
850 else
851 {
852 SendEmailToSupport(parameters, ex);
853 }
854
855 }
856 finally
857 {
858 if (context != null)
859 {
860 context.Dispose();
861 }
862 }
863
864 }
865
866 /// <summary>
867 /// This email sends an email to support team whenever an exception happens
868 /// </summary>
869 /// <returns>success status</returns>
870 public static string SendEmailToSupport(string parameters, Exception lastException)
871 {
872
873 var body = new StringBuilder();
874 MailAddress fromAddress = new MailAddress("no-reply@cardiodiagnostics.net", "No-Reply"); ;
875 MailAddress toAddress = new MailAddress("support@cardiodiagnostics.net", "Support Team"); ;
876
877 //Create the MailMessage instance
878 MailMessage myMailMessage = new MailMessage(fromAddress, toAddress);
879
880 //Assign the MailMessage's properties
881 myMailMessage.Subject = "Error On Server";
882 body.AppendLine("<b>Exception on server</b>/br> ");
883 body.AppendLine("<br/><br/><b>Date: </b>" + DateTime.UtcNow);
884 //Get the username saved in the authentication cookie user data
885 body.AppendLine("<br/><br/><b>Application: </b> CloudBeat Heavy Duty Functions");
886
887 body.AppendLine("<br/><br/><b>Parameters: </b><br/>" + parameters);
888 body.AppendLine("<br/><br/><b>Exception Message: </b><br/>" + lastException.Message);
889 body.AppendLine("<br/><br/><b>Exception StackTrace: </b><br/>" + lastException.StackTrace);
890 body.AppendLine("<br/><br/><b>Exception InnerException: </b><br/>" + lastException.InnerException);
891
892 myMailMessage.Body = body.ToString();
893 myMailMessage.IsBodyHtml = true;
894
895 //Create the SmtpClient object
896 SmtpClient smtp = new SmtpClient();
897 smtp.EnableSsl = true;
898 //Send the MailMessage (will use the Web.config settings)
899 smtp.Send(myMailMessage);
900 return "success";
901
902 }
903
904 }
905}