Inheritance: Acrolinx.Sdk.Sidebar.Documents.IRange
        private IEnumerable<MatchWithReplacement> ConvertMatches(string jsonString)
        {
            Contract.Requires(!string.IsNullOrWhiteSpace(jsonString));

            JArray matches = JArray.Parse(jsonString);

            Range lastRange = new Range(0,0);
            foreach (dynamic match in matches)
            {
                string content = "" + match.content;
                string replacement = "" + match.replacement;
                Range range = CreateRangeSafe(lastRange, (int)match.range[0], (int)match.range[1]);
                lastRange = range;
                yield return new MatchWithReplacement(new Match(content, range), replacement);
            }
        }
 private static Range CreateRangeSafe(Range lastRange, int start, int end)
 {
     Contract.Requires(lastRange.End <= start);
     Contract.Requires(start <= end);
     return new Range(start, end);
 }
        public void ReplaceRanges(IReadOnlyList<MatchWithReplacement> matches, DocumentModel model, Format format)
        {
            var modifiedRanges = new List<IRange>(matches.Select<Match, IRange>(x => model.OriginalToModifiedRange(x.Range)));

            var currentExtraction = Extract(format);

            var lookup = new Lookup(model.Content);
            var searchResult = lookup.Search(currentExtraction, modifiedRanges);

            var lengthDiff = 0;

            if (searchResult.Count == 0)
            {
                throw new MatchesNotFoundException("Lookup returned an empty list. Maybe source document was change by user?", matches, null);
            }

            for (var i = searchResult.Count - 1; i >= 0; i--)
            {
                var match = searchResult[i];
                var replacement = matches[i].Replacement;

                IRange rawRange= ToRawRange(format, currentExtraction, match,false);

                var rawOriginalTextLength = (!EncodeContent && format != Format.Text) ? DecodedLength(currentExtraction.Substring(match.Start, match.Length)) : match.Length;
                var rawReplacement =  (!EncodeContent && format != Format.Text) ? XmlEncode(replacement) : replacement;

                if (rawRange.Length == 0)
                {
                    throw new MatchesNotFoundException("", new Match[]{matches[i]}, null);
                }

                lengthDiff += rawReplacement.Length - rawOriginalTextLength;

                ReplaceRawRange(rawRange, rawReplacement, format);
                model.Update(matches[i].Range, ((format != Format.Text) ? XmlEncode(replacement) : replacement));
            }

            var rangeWithTag = new Range(searchResult[0].Start, searchResult[searchResult.Count - 1].End);
            IRange range = ToRawRange(format, currentExtraction, rangeWithTag, false);
            SelectRawRange(new Range(range.Start, range.End + lengthDiff), format);
        }
        private IRange ToRawRange(Format format, string currentExtraction, IRange rangeWithTag, bool silent)
        {
            IRange range;
            if (EncodeContent && format != Format.Text)
            {
                var xmlContentStart = currentExtraction.IndexOf(">") + 1;
                var xmlContentEnd = currentExtraction.LastIndexOf("<");

                System.Diagnostics.Trace.Assert(xmlContentStart > 0);
                System.Diagnostics.Trace.Assert(xmlContentEnd > 0);

                if (!silent && !(xmlContentStart <= rangeWithTag.Start && rangeWithTag.End <= xmlContentEnd))
                {
                    throw new RangesNotFoundException(rangeWithTag + " in content: '" + currentExtraction.Substring(rangeWithTag.Start,rangeWithTag.Length) + "' is trying to mark inside tags.", new IRange[]{rangeWithTag}, null);
                }

                var xmlContent = currentExtraction.Substring(xmlContentStart, xmlContentEnd - xmlContentStart);

                var rangeInContentStart = Math.Min(Math.Max(0, rangeWithTag.Start - xmlContentStart), xmlContent.Length);
                var rangeInContentLength = Math.Min(rangeWithTag.Length, xmlContent.Length - rangeInContentStart);

                var decodedStart = DecodedLength(xmlContent.Substring(0, rangeInContentStart));
                var decodedLength = DecodedLength(xmlContent.Substring(rangeInContentStart, rangeInContentLength));
                range = new Range(decodedStart, decodedStart + decodedLength);
            }
            else
            {
                range = new Range(rangeWithTag.Start, rangeWithTag.End);
            }
            return range;
        }
        public void SelectRanges(IReadOnlyList<Match> matches, DocumentModel model, Format format)
        {
            var modifiedRanges = new List<IRange>(matches.Select<Match, IRange>(x => model.OriginalToModifiedRange(x.Range)));

            var currentExtraction = Extract(format);

            var lookup = new Lookup(model.Content);
            var searchResult = lookup.Search(currentExtraction, modifiedRanges);

            if(searchResult.Count == 0)
            {
                throw new MatchesNotFoundException("Lookup returned an empty list. Maybe source document was change by user?", matches, null);
            }

            var rangeWithTag = new Range(searchResult[0].Start, searchResult[searchResult.Count - 1].End);

            IRange range = ToRawRange(format, currentExtraction, rangeWithTag, false);
            SelectRawRange(range, format);
        }
 internal CheckedEventArgs(string checkId, Range range) : base(checkId)
 {
     Range = range;
 }