Projekt

Obecné

Profil

Stáhnout (27.4 KB) Statistiky
| Větev: | Tag: | Revize:
1
using Core.Contexts;
2
using Core.Entities;
3
using Models.Annotations;
4
using Models.Enums;
5
using Serilog;
6
using System;
7
using System.Collections.Generic;
8
using System.Linq;
9
using System.Text;
10
using System.Threading.Tasks;
11
using Microsoft.EntityFrameworkCore;
12
using AutoMapper;
13
using Models.Tags;
14
using Ganss.XSS;
15
using HtmlAgilityPack;
16
using System.Text.RegularExpressions;
17
using Newtonsoft.Json;
18
using Core.GraphUtils;
19

    
20
namespace Core.Services.AnnotationService
21
{
22
    public class AnnotationServiceEF : IAnnotationService
23
    {
24
        private readonly DatabaseContext context;
25
        private readonly ILogger logger;
26
        private readonly IMapper mapper;
27
        private readonly IHTMLService htmlService;
28

    
29

    
30
        public AnnotationServiceEF(DatabaseContext context, ILogger logger, IMapper mapper, IHTMLService htmlService)
31
        {
32
            this.context = context;
33
            this.logger = logger;
34
            this.mapper = mapper;
35
            this.htmlService = htmlService;
36
        }
37

    
38
        public void CreateDocumentAnnotations(AnnotationsAddRequest request, Guid clientUserId)
39
        {
40
            User addingUser = context.Users.Single(u => u.Id == clientUserId);
41

    
42
            // Check the documents exist
43
            var documents = context.Documents.Where(d => request.DocumentIdList.Contains(d.Id)).ToList();
44
            if (documents.Count() != request.DocumentIdList.Count)
45
            {
46
                logger.Information($"Received a non-existent Document ID when assigning documents to users");
47
                throw new InvalidOperationException($"{request.DocumentIdList.Count - documents.Count()} of the received documents do not exist");
48
            }
49

    
50
            var users = context.Users.Where(u => request.UserIdList.Contains(u.Id)).ToList();
51
            foreach (var user in users)
52
            {
53
                var userAnnotatedDocuments = context.Annotations.Where(a => a.User == user).Select(a => a.Document).ToList();
54
                foreach (var doc in documents)
55
                {
56
                    if (userAnnotatedDocuments.Contains(doc))
57
                    {
58
                        logger.Information($"User {user.Username} has already been assigned the document {doc.Id}, ignoring");
59
                        continue;
60
                    }
61

    
62
                    context.Annotations.Add(new Annotation()
63
                    {
64
                        User = user,
65
                        UserAssigned = addingUser,
66
                        DateAssigned = DateTime.Now,
67
                        DateLastChanged = DateTime.Now,
68
                        Document = doc,
69
                        State = EState.NEW,
70
                        Note = ""
71
                    });
72
                }
73
            }
74

    
75
            context.SaveChanges();
76
        }
77

    
78
        public AnnotationListResponse GetUserAnnotations(Guid userId)
79
        {
80
            var annotations = context.Annotations
81
                .Where(a => a.User.Id == userId)
82
                .Include(a => a.Document)
83
                .ToList();
84
            var infos = new List<AnnotationListInfo>();
85
            foreach (var annotation in annotations)
86
            {
87
                infos.Add(new AnnotationListInfo()
88
                {
89
                    AnnotationId = annotation.Id,
90
                    DocumentName = annotation.Document.Name,
91
                    State = annotation.State
92
                });
93
            }
94

    
95
            return new AnnotationListResponse()
96
            {
97
                Annotations = infos
98
            };
99
        }
100

    
101
        public void AddNoteToAnnotation(Guid annotationId, Guid userId, ERole userRole, AddNoteToAnnotationRequest request, bool isFinal)
102
        {
103
            Annotation annotation = null;
104
            try
105
            {
106
                if (!isFinal)
107
                {
108
                    annotation = context.Annotations.Include(a => a.User).First(a => a.Id == annotationId);
109
                }
110
                else
111
                {
112
                    annotation = context.FinalAnnotations.Include(a => a.User).First(a => a.Id == annotationId);
113
                }
114
            }
115
            catch (Exception)
116
            {
117
                throw new InvalidOperationException("Annotation not found");
118
            }
119

    
120
            if (userRole < ERole.ADMINISTRATOR && annotation.User.Id != userId)
121
            {
122
                throw new UnauthorizedAccessException("User does not have access to this annotation");
123
            }
124

    
125
            annotation.Note = request.Note;
126
            context.SaveChanges();
127
        }
128

    
129

    
130
        public AnnotationInfo GetAnnotation(Guid annotationId, Guid userId, ERole userRole, bool isFinal)
131
        {
132
            Annotation annotation = new();
133
            if (!isFinal)
134
            {
135
                annotation = context.Annotations
136
                .Where(a => a.Id == annotationId)
137
                .Include(a => a.User)
138
                .Include(a => a.Document).ThenInclude(d => d.Content)
139
                .First();
140
            }
141
            else
142
            {
143
                annotation = context.FinalAnnotations
144
                .Where(a => a.Id == annotationId)
145
                .Include(a => a.User)
146
                .Include(a => a.Document).ThenInclude(d => d.Content)
147
                .First();
148
            }
149

    
150

    
151
            if (userRole < ERole.ADMINISTRATOR)
152
            {
153
                if (annotation.User.Id != userId)
154
                {
155
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
156
                }
157
            }
158

    
159
            var documentContent = context.Documents.Where(d => d.Id == annotation.Document.Id).Select(d => d.Content).First();
160

    
161
            var tags = context.AnnotationTags.Where(at => at.Annotation.Id == annotationId)
162
                .Include(at => at.Tag)
163
                .ThenInclude(t => t.Category)
164
                .Include(at => at.SubTag)
165
                .OrderBy(at => at.Position)
166
                .Select(at => at as AnnotationTagGeneric)
167
                .ToList();
168

    
169
            List<TagInstanceInfo> tagInstanceInfos = new();
170
            foreach (var tag in tags)
171
            {
172
                var tagInstance = mapper.Map<TagInstanceInfo>(tag);
173
                tagInstanceInfos.Add(tagInstance);
174
            }
175

    
176
            var docToRender = "";
177
            HTMLService.CachedInfo cachedInfoToReturn = new();
178
            if (annotation.CachedDocumentHTML == "")
179
            {
180
                var result = htmlService.FullPreprocessHTML(documentContent.Content, tags);
181
                cachedInfoToReturn = result.Item2;
182
                docToRender = result.Item1;
183

    
184
                annotation.CachedStartPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartPositions);
185
                annotation.CachedLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartLengths);
186
                annotation.CachedClosingPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingPositions);
187
                annotation.CachedClosingLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingLengths);
188
                annotation.CachedCSS = JsonConvert.SerializeObject(cachedInfoToReturn.TagInstanceCSS);
189
                annotation.ModifiedType = EModified.NONE;
190
                annotation.CachedDocumentHTML = docToRender;
191
                context.SaveChanges();
192
            }
193
            else
194
            {
195
                docToRender = annotation.CachedDocumentHTML;
196
                cachedInfoToReturn = new()
197
                {
198
                    TagStartPositions = JsonConvert.DeserializeObject<List<int>>(annotation.CachedStartPositions),
199
                    TagStartLengths = JsonConvert.DeserializeObject<List<int>>(annotation.CachedLengths),
200
                    TagClosingPositions = JsonConvert.DeserializeObject<List<int>>(annotation.CachedClosingPositions),
201
                    TagClosingLengths = JsonConvert.DeserializeObject<List<int>>(annotation.CachedClosingLengths),
202
                    TagInstanceCSS = JsonConvert.DeserializeObject<List<TagInstanceCSSInfo>>(annotation.CachedCSS)
203
                };
204

    
205
                // The annotation has been modified and we need to either add the new tag or remove the tag
206
                if (annotation.ModifiedType != EModified.NONE)
207
                {
208
                    if (annotation.ModifiedType == EModified.ADDED)
209
                    {
210
                        var lastModifiedTag = context.AnnotationTags.Where(at => at.Id == annotation.LastModifiedTagId).First();
211
                        var result = htmlService.PartialPreprocessHTMLAddTag(docToRender, documentContent.Content, lastModifiedTag, tags, cachedInfoToReturn);
212
                        docToRender = result.Item1;
213
                        cachedInfoToReturn = result.Item2;
214
                    }
215
                    else if (annotation.ModifiedType == EModified.REMOVED)
216
                    {
217
                        var result = htmlService.PartialPreprocessHTMLRemoveTag(docToRender, documentContent.Content, new AnnotationTag() { Id = annotation.LastModifiedTagId.Value }, tags, cachedInfoToReturn);
218
                        docToRender = result.Item1;
219
                        cachedInfoToReturn = result.Item2;
220
                    }
221

    
222
                    annotation.ModifiedType = EModified.NONE;
223
                    annotation.CachedStartPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartPositions);
224
                    annotation.CachedLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartLengths);
225
                    annotation.CachedClosingPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingPositions);
226
                    annotation.CachedClosingLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingLengths);
227
                    annotation.CachedDocumentHTML = docToRender;
228
                    annotation.CachedCSS = JsonConvert.SerializeObject(cachedInfoToReturn.TagInstanceCSS);
229
                    context.SaveChanges();
230
                }
231
            }
232

    
233
            // We probably cannot use AutoMapper since we are dealing with too many different entities
234
            AnnotationInfo annotationInfo = new()
235
            {
236
                SourceDocumentContent = documentContent.Content,
237
                DocumentToRender = docToRender,
238
                TagStartPositions = cachedInfoToReturn.TagStartPositions.ToArray(),
239
                TagLengths = cachedInfoToReturn.TagStartLengths.ToArray(),
240
                Note = annotation.Note,
241
                State = annotation.State,
242
                Type = IsHtml(documentContent.Content) ? EDocumentType.HTML : EDocumentType.TEXT,
243
                TagInstances = tagInstanceInfos,
244
                CSSInfo = cachedInfoToReturn.TagInstanceCSS
245
            };
246

    
247
            return annotationInfo;
248
        }
249

    
250
        // TODO temporary
251
        private bool IsHtml(string text)
252
        {
253
            return text.Contains("<html>");
254
        }
255

    
256
        public void AddAnnotationInstance(Guid annotationId, Guid userId, ERole userRole, AnnotationInstanceAddRequest request, bool isFinal)
257
        {
258
            Annotation annotation = new();
259
            if (!isFinal)
260
            {
261
                annotation = context.Annotations
262
                    .Where(a => a.Id == annotationId)
263
                    .Include(a => a.User)
264
                    .Include(a => a.Document).ThenInclude(d => d.Content)
265
                    .First();
266
            }
267
            else
268
            {
269
                annotation = context.FinalAnnotations
270
                    .Where(a => a.Id == annotationId)
271
                    .Include(a => a.User)
272
                    .Include(a => a.Document).ThenInclude(d => d.Content)
273
                    .First();
274
            }
275

    
276
            if (userRole < ERole.ADMINISTRATOR)
277
            {
278
                if (annotation.User.Id != userId)
279
                {
280
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
281
                }
282
            }
283

    
284
            if (annotation.State == EState.NEW)
285
            {
286
                annotation.State = EState.IN_PROGRESS;
287
            }
288

    
289
            AnnotationTagGeneric annotationTag = new();
290
            if (isFinal)
291
            {
292
                annotationTag = new FinalAnnotationTag()
293
                {
294
                    Id = Guid.NewGuid(),
295
                    Annotation = annotation as FinalAnnotation,
296
                    Instance = request.InstanceId == null ? Guid.NewGuid() : request.InstanceId.Value,
297
                    Length = request.Length,
298
                    Position = request.Position,
299
                    SelectedText = request.SelectedText,
300
                    Note = ""
301
                };
302
            }
303
            else
304
            {
305
                annotationTag = new AnnotationTag()
306
                {
307
                    Id = Guid.NewGuid(),
308
                    Annotation = annotation as Annotation,
309
                    Instance = request.InstanceId == null ? Guid.NewGuid() : request.InstanceId.Value,
310
                    Length = request.Length,
311
                    Position = request.Position,
312
                    SelectedText = request.SelectedText,
313
                    Note = ""
314
                };
315
            }
316

    
317
            if (request.Type == ETagType.TAG)
318
            {
319
                annotationTag.Tag = context.Tags.Where(t => t.Id == request.Id).Single();
320
                annotationTag.SubTag = null;
321

    
322
                if (annotationTag.Tag.SentimentEnabled)
323
                {
324
                    annotationTag.Sentiment = ETagSentiment.NEUTRAL;
325
                }
326

    
327
                // If for the same annotation exists a tag with same position and length and of the same type, ignore
328
                if (context.AnnotationTags.Any(at =>
329
                at.Position == annotationTag.Position &&
330
                at.Length == annotationTag.Length &&
331
                at.Annotation == annotation &&
332
                at.Tag == annotationTag.Tag))
333
                {
334
                    throw new InvalidOperationException("Duplicate tag");
335
                }
336

    
337
            }
338
            else if (request.Type == ETagType.SUBTAG)
339
            {
340
                var subTag = context.SubTags.Where(st => st.Id == request.Id).Include(st => st.Tag).Single();
341
                annotationTag.SubTag = subTag;
342
                annotationTag.Tag = subTag.Tag;
343

    
344
                if (annotationTag.SubTag.SentimentEnabled)
345
                {
346
                    annotationTag.Sentiment = ETagSentiment.NEUTRAL;
347
                }
348

    
349
                if (context.AnnotationTags.Any(at =>
350
                at.Position == annotationTag.Position &&
351
                at.Length == annotationTag.Length &&
352
                at.Annotation == annotation &&
353
                at.Tag == annotationTag.Tag &&
354
                at.SubTag == annotationTag.SubTag))
355
                {
356
                    throw new InvalidOperationException("Duplicate tag");
357
                }
358
            }
359
            else
360
            {
361
                throw new ArgumentException($"Unknown tag type {request.Type}");
362
            }
363

    
364
            if (annotation.State == EState.NEW)
365
            {
366
                annotation.State = EState.IN_PROGRESS;
367
            }
368

    
369
            annotation.LastModifiedTagId = annotationTag.Id;
370
            annotation.ModifiedType = EModified.ADDED;
371

    
372
            if (isFinal)
373
            {
374
                context.FinalAnnotationTags.Add(annotationTag as FinalAnnotationTag);
375
            }
376
            else
377
            {
378
                context.AnnotationTags.Add(annotationTag as AnnotationTag);
379
            }
380

    
381
            context.SaveChanges();
382
        }
383

    
384
        public void DeleteAnnotationInstance(Guid annotationId, Guid tagInstanceId, Guid loggedUserId, ERole userRole, bool isFinal)
385
        {
386
            Annotation annotation = null;
387
            try
388
            {
389
                if (!isFinal)
390
                {
391
                    annotation = context.Annotations
392
                    .Where(a => a.Id == annotationId)
393
                    .Include(a => a.User)
394
                    .Include(a => a.Document).ThenInclude(d => d.Content)
395
                    .First();
396
                }
397
                else
398
                {
399
                    annotation = context.FinalAnnotations
400
                    .Where(a => a.Id == annotationId)
401
                    .Include(a => a.User)
402
                    .Include(a => a.Document).ThenInclude(d => d.Content)
403
                    .First();
404
                }
405

    
406

    
407
            }
408
            catch (Exception ex)
409
            {
410
                throw new InvalidOperationException("Could not find annotation");
411
            }
412

    
413

    
414
            if (userRole < ERole.ADMINISTRATOR)
415
            {
416
                if (annotation.User.Id != loggedUserId)
417
                {
418
                    throw new UnauthorizedAccessException($"User {loggedUserId} does not have assigned annotation {annotationId}");
419
                }
420
            }
421

    
422
            AnnotationTagGeneric annotationTag = new();
423

    
424
            if (isFinal)
425
            {
426
                if (!context.FinalAnnotationTags.Any(at => at.Id == tagInstanceId))
427
                {
428
                    throw new InvalidOperationException("Could not find tag instance");
429
                }
430
                annotationTag = context.FinalAnnotationTags.First(at => at.Id == tagInstanceId);
431

    
432
            }
433
            else
434
            {
435
                if (!context.AnnotationTags.Any(at => at.Id == tagInstanceId))
436
                {
437
                    throw new InvalidOperationException("Could not find tag instance");
438
                }
439
                annotationTag = context.AnnotationTags.First(at => at.Id == tagInstanceId);
440
            }
441

    
442
            annotation.LastModifiedTagId = annotationTag.Id;
443
            annotation.ModifiedType = EModified.REMOVED;
444

    
445
            if (isFinal)
446
            {
447
                context.FinalAnnotationTags.Remove(annotationTag as FinalAnnotationTag);
448
            }
449
            else
450
            {
451
                context.AnnotationTags.Remove(annotationTag as AnnotationTag);
452
            }
453

    
454
            context.SaveChanges();
455
        }
456

    
457
        public void SetTagInstanceSentiment(Guid annotationId, Guid instanceId, Guid userId, ERole userRole, ETagSentiment sentiment, bool isFinal)
458
        {
459
            Annotation annotation = null;
460
            try
461
            {
462
                if (!isFinal)
463
                {
464
                    annotation = context.Annotations
465
                    .Where(a => a.Id == annotationId)
466
                    .Include(a => a.User)
467
                    .Include(a => a.Document).ThenInclude(d => d.Content)
468
                    .First();
469
                }
470
                else
471
                {
472
                    annotation = context.FinalAnnotations
473
                    .Where(a => a.Id == annotationId)
474
                    .Include(a => a.User)
475
                    .Include(a => a.Document).ThenInclude(d => d.Content)
476
                    .First();
477
                }
478
            }
479
            catch (Exception ex)
480
            {
481
                throw new InvalidOperationException("Could not find annotation");
482
            }
483

    
484

    
485
            if (userRole < ERole.ADMINISTRATOR)
486
            {
487
                if (annotation.User.Id != userId)
488
                {
489
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
490
                }
491
            }
492

    
493

    
494
            IEnumerable<AnnotationTagGeneric> tagInstances = null;
495

    
496
            if (isFinal)
497
            {
498
                tagInstances = context.FinalAnnotationTags.Where(at => at.Instance == instanceId).ToList();
499
            }
500
            else
501
            {
502
                tagInstances = context.AnnotationTags.Where(at => at.Instance == instanceId).ToList();
503
            }
504

    
505
            if (tagInstances.Count() == 0)
506
            {
507
                throw new InvalidOperationException("No such instance found");
508
            }
509

    
510
            foreach (var tagInstance in tagInstances)
511
            {
512
                tagInstance.Sentiment = sentiment;
513
            }
514

    
515
            context.SaveChanges();
516
        }
517

    
518
        public void MarkAnnotationAsDone(Guid annotationId, Guid userId, ERole userRole, bool done, bool isFinal)
519
        {
520

    
521
            Annotation annotation = null;
522
            try
523
            {
524
                if (!isFinal)
525
                {
526
                    annotation = context.Annotations
527
                   .Where(a => a.Id == annotationId)
528
                   .Include(a => a.User)
529
                   .Include(a => a.Document).ThenInclude(d => d.Content)
530
                   .First();
531
                }
532
                else
533
                {
534
                    annotation = context.FinalAnnotations
535
                   .Where(a => a.Id == annotationId)
536
                   .Include(a => a.User)
537
                   .Include(a => a.Document).ThenInclude(d => d.Content)
538
                   .First();
539
                }
540
            }
541
            catch (Exception ex)
542
            {
543
                throw new InvalidOperationException("Could not find annotation");
544
            }
545

    
546
            if (userRole < ERole.ADMINISTRATOR)
547
            {
548
                if (annotation.User.Id != userId)
549
                {
550
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
551
                }
552
            }
553

    
554
            annotation.State = done ? EState.DONE : EState.IN_PROGRESS;
555
            context.SaveChanges();
556
        }
557

    
558
        public Guid CreateFinalAnnotation(Guid documentId, Guid userId)
559
        {
560
            var document = context.Documents.Single(d => d.Id == documentId);
561
            var user = context.Users.Single(u => u.Id == userId);
562

    
563
            // Remove existing 
564
            if (context.FinalAnnotations.Any(fa => fa.Document == document))
565
            {
566
                var finalAnnotationOld = context.FinalAnnotations.Single(fa => fa.Document == document);
567
                context.FinalAnnotations.Remove(finalAnnotationOld);
568
            }
569

    
570
            var annotations = context.Annotations
571
                .Include(a => a.Document)
572
                .Where(a => a.Document == document && a.State == EState.DONE)
573
                .ToList();
574

    
575
            var finalAnnotation = new FinalAnnotation()
576
            {
577
                Id = Guid.NewGuid(),
578
                DateAssigned = DateTime.Now,
579
                DateLastChanged = DateTime.Now,
580
                Document = document,
581
                User = user,
582
                UserAssigned = user,
583
                Annotations = annotations,
584
                State = EState.NEW
585
            };
586

    
587
            List<AnnotationTag> annotationTagsAll = new();
588
            foreach (var annotation in annotations)
589
            {
590
                annotationTagsAll.AddRange(context.AnnotationTags
591
                    .Where(at => at.Annotation == annotation)
592
                    .Include(at => at.Tag)
593
                    .Include(at => at.SubTag)
594
                    .Include(at => at.Annotation)
595
                    .ThenInclude(a => a.User)
596
                    .ToList());
597
            }
598
            annotationTagsAll = annotationTagsAll.OrderBy(at => at.Position).ToList();
599

    
600
            Dictionary<Guid, List<AnnotationTag>> occurenceDict = new();
601
            foreach (var annotationTag in annotationTagsAll)
602
            {
603
                if (occurenceDict.ContainsKey(annotationTag.Instance))
604
                {
605
                    occurenceDict[annotationTag.Instance].Add(annotationTag);
606
                }
607
                else
608
                {
609
                    occurenceDict[annotationTag.Instance] = new();
610
                    occurenceDict[annotationTag.Instance].Add(annotationTag);
611
                }
612
            }
613

    
614
            List<List<AnnotationTag>> occurenceLists = new();
615
            foreach (var key in occurenceDict.Keys)
616
            {
617
                occurenceLists.Add(occurenceDict[key]);
618
            }
619

    
620
            List<List<AnnotationTag>> annotationTagsProcessed = new();
621
            List<FinalAnnotationTag> finalAnnotationTags = new();
622
            for (int i = 0; i < occurenceLists.Count; i++)
623
            {
624
                var occurrenceList1 = occurenceLists[i];
625
                List<List<AnnotationTag>> sameLists = new();
626

    
627
                for (int j = 0; j < occurenceLists.Count; j++)
628
                {
629
                    var occurrenceList2 = occurenceLists[j];
630

    
631
                    if (annotationTagsProcessed.Contains(occurrenceList2))
632
                    {
633
                        continue;
634
                    }
635

    
636
                    if (SelectionsAreSame(occurrenceList1, occurrenceList2))
637
                    {
638
                        sameLists.Add(occurrenceList2);
639
                    }
640
                }
641

    
642
                // This means that this occurrence ahs already been processed as matching a previous tag
643
                if (sameLists.Count() == 0)
644
                {
645
                    continue;
646
                }
647

    
648
                List<User> relatedUsers = new();
649
                foreach (var list in sameLists)
650
                {
651
                    relatedUsers.Add(list[0].Annotation.User);
652
                }
653

    
654
                foreach (var tag in sameLists[0])
655
                {
656
                    finalAnnotationTags.Add(new()
657
                    {
658
                        Id = Guid.NewGuid(),
659
                        Tag = tag.Tag,
660
                        SubTag = tag.SubTag,
661
                        Annotation = finalAnnotation,
662
                        SelectedText = tag.SelectedText,
663
                        Sentiment = tag.Sentiment,
664
                        Instance = tag.Instance,
665
                        IsFinal = sameLists.Count == annotations.Count,
666
                        Length = tag.Length,
667
                        Position = tag.Position,
668
                        Note = "",
669
                        Users = relatedUsers
670
                    });
671
                }
672

    
673
                annotationTagsProcessed.AddRange(sameLists);
674
            }
675

    
676
            context.FinalAnnotations.Add(finalAnnotation);
677
            context.SaveChanges();
678
            context.FinalAnnotationTags.AddRange(finalAnnotationTags);
679

    
680
            context.SaveChanges();
681
            return finalAnnotation.Id;
682
        }
683

    
684
        private bool SelectionsAreSame(List<AnnotationTag> list1, List<AnnotationTag> list2)
685
        {
686
            if (list1.Count != list2.Count)
687
            {
688
                return false;
689
            }
690

    
691
            bool sentimentEnabled = list1[0].Tag.SentimentEnabled;
692

    
693
            if (sentimentEnabled)
694
            {
695
                for (int i = 0; i < list1.Count; i++)
696
                {
697
                    var tag1 = list1[i];
698
                    var tag2 = list2[i];
699
                    if (tag1.Position == tag2.Position &&
700
                        tag1.Length == tag2.Length &&
701
                        tag1.Sentiment == tag2.Sentiment &&
702
                        tag1.Tag == tag2.Tag &&
703
                        tag1.SubTag == tag2.SubTag)
704
                    {
705
                        continue;
706
                    }
707
                    else
708
                    {
709
                        return false;
710
                    }
711
                }
712
            }
713
            else
714
            {
715
                for (int i = 0; i < list1.Count; i++)
716
                {
717
                    var tag1 = list1[i];
718
                    var tag2 = list2[i];
719
                    if (tag1.Position == tag2.Position &&
720
                        tag1.Length == tag2.Length &&
721
                        tag1.Tag == tag2.Tag &&
722
                        tag1.SubTag == tag2.SubTag)
723
                    {
724
                        continue;
725
                    }
726
                    else
727
                    {
728
                        return false;
729
                    }
730
                }
731
            }
732

    
733
            return true;
734
        }
735
    }
736
}
(1-1/2)