private static int CheckSequence(IFuzzyComparer <T> _Comparer, SequencePart _Subject, SequencePart _Target, int _LimitCheck = -1, int _SkipItems = 0)
        {
            int          SubjectStart         = _Subject.SequencePosition;
            SequencePart NextItem             = _Subject.Next;
            SequencePart NextComparisonTarget = _Target.Next;
            int          CorrectCount         = 1;

            for (int i = 0; CorrectCount < _SkipItems; ++i)
            {
                NextItem             = NextItem.Next;
                NextComparisonTarget = NextComparisonTarget.Next;
                CorrectCount++;
            }


            while (NextItem.SequencePosition != SubjectStart)
            {
                FuzzyCompareResult CompareResult = _Comparer.CompareItems(NextItem.SequenceValue, NextComparisonTarget.SequenceValue);

                if (CompareResult == FuzzyCompareResult.ExactMatch || CompareResult == FuzzyCompareResult.GreaterThanWithinMargins || CompareResult == FuzzyCompareResult.SmallerThanWithinMargins || CompareResult == FuzzyCompareResult.NotEqualUndefinedWithinMargins)
                {
                    CorrectCount++;

                    if (_LimitCheck > 0 && CorrectCount >= _LimitCheck)
                    {
                        break;
                    }
                }
                else
                {
                    break;
                }

                NextItem             = NextItem.Next;
                NextComparisonTarget = NextComparisonTarget.Next;
            }

            return(CorrectCount);
        }
        public List <SequenceMatchScore> CompareSequence(LoopingSequence <T> _OtherSeqence, IFuzzyComparer <T> _Comparer, out int _ThisBestStartIndex, out int _BestMatchScore, out int _BestOtherMatchIndex, int _CandidateConsiderationLength = 1, int _MinScore = -1)
        {
            List <SequenceMatchScore> Scores = new List <SequenceMatchScore>();

            Parallel.For(0, Parts.Length, (s) =>
            {
                SequencePart Subject     = this.Parts[s];
                int CandidateGatherPoint = -1;

                int LowerBound = 0;
                int UpperBound = _OtherSeqence.Parts.Length - 1;

                //Do binary search for start point
                while (LowerBound <= UpperBound)
                {
                    int Midpoint = (LowerBound + UpperBound) / 2;

                    FuzzyCompareResult Result = _Comparer.CompareItems(Subject.SequenceValue, _OtherSeqence.Parts[Midpoint].SequenceValue);

                    if (Result == FuzzyCompareResult.ExactMatch || Result == FuzzyCompareResult.GreaterThanWithinMargins || Result == FuzzyCompareResult.SmallerThanWithinMargins || Result == FuzzyCompareResult.NotEqualUndefinedWithinMargins)
                    {
                        CandidateGatherPoint = Midpoint;
                        break;
                    }
                    else if (Result == FuzzyCompareResult.SmallerThan)
                    {
                        UpperBound = Midpoint - 1;
                    }
                    else
                    {
                        LowerBound = Midpoint + 1;
                    }
                }

                if (CandidateGatherPoint != -1)
                {
                    List <SequencePart> Candidates = new List <SequencePart>();

                    int InitialCorrect = CheckSequence(_Comparer, Subject, _OtherSeqence.Parts[CandidateGatherPoint], _CandidateConsiderationLength);

                    if (InitialCorrect >= _CandidateConsiderationLength)
                    {
                        Candidates.Add(_OtherSeqence.Parts[CandidateGatherPoint]);
                    }

                    bool FoundEnd   = false;
                    int SearchIndex = CandidateGatherPoint + 1;

                    //Check above starting point for matches
                    while (!FoundEnd)
                    {
                        if (SearchIndex >= _OtherSeqence.Parts.Length)
                        {
                            FoundEnd = true;
                            break;
                        }

                        FuzzyCompareResult CompareResult = _Comparer.CompareItems(Subject.SequenceValue, _OtherSeqence.Parts[SearchIndex].SequenceValue);

                        if (CompareResult == FuzzyCompareResult.ExactMatch || CompareResult == FuzzyCompareResult.GreaterThanWithinMargins || CompareResult == FuzzyCompareResult.SmallerThanWithinMargins || CompareResult == FuzzyCompareResult.NotEqualUndefinedWithinMargins)
                        {
                            int CorrectCount = CheckSequence(_Comparer, Subject, _OtherSeqence.Parts[SearchIndex], _CandidateConsiderationLength);

                            if (_CandidateConsiderationLength > 0 && _CandidateConsiderationLength <= CorrectCount)
                            {
                                Candidates.Add(_OtherSeqence.Parts[SearchIndex]);
                            }
                        }
                        else
                        {
                            FoundEnd = true;
                            break;
                        }

                        SearchIndex++;
                    }

                    FoundEnd    = false;
                    SearchIndex = CandidateGatherPoint - 1;

                    //Check below starting point for matches
                    while (!FoundEnd)
                    {
                        if (SearchIndex < 0)
                        {
                            FoundEnd = true;
                            break;
                        }

                        FuzzyCompareResult CompareResult = _Comparer.CompareItems(Subject.SequenceValue, _OtherSeqence.Parts[SearchIndex].SequenceValue);

                        if (CompareResult == FuzzyCompareResult.ExactMatch || CompareResult == FuzzyCompareResult.GreaterThanWithinMargins || CompareResult == FuzzyCompareResult.SmallerThanWithinMargins || CompareResult == FuzzyCompareResult.NotEqualUndefinedWithinMargins)
                        {
                            int CorrectCount = CheckSequence(_Comparer, Subject, _OtherSeqence.Parts[SearchIndex], _CandidateConsiderationLength);

                            if (_CandidateConsiderationLength > 0 && _CandidateConsiderationLength <= CorrectCount)
                            {
                                Candidates.Add(_OtherSeqence.Parts[SearchIndex]);
                            }
                        }
                        else
                        {
                            FoundEnd = true;
                            break;
                        }

                        SearchIndex--;
                    }

                    Parallel.For(0, Candidates.Count, (i) =>
                    {
                        SequencePart Target = Candidates[i];

                        int CorrectCount = CheckSequence(_Comparer, Subject, Target, -1, _CandidateConsiderationLength);


                        if ((_MinScore == -1) || (_MinScore >= 0 && CorrectCount >= _MinScore))
                        {
                            SequenceMatchScore score   = new SequenceMatchScore();
                            score.ThisBestIndex        = Subject.SequencePosition;
                            score.BestMatchLengthOther = CorrectCount;
                            score.BestMatchIndexOther  = Candidates[i].SequencePosition;

                            lock (Scores)
                            {
                                Scores.Add(score);
                            }
                        }
                    });
                }
            });

            int Best          = -1;
            int BestIndex     = -1;
            int ThisBestIndex = -1;

            for (int i = 0; i < Scores.Count; ++i)
            {
                if (Scores[i].BestMatchLengthOther > Best)
                {
                    Best          = Scores[i].BestMatchLengthOther;
                    BestIndex     = Scores[i].BestMatchIndexOther;
                    ThisBestIndex = Scores[i].ThisBestIndex;
                }
            }

            _BestMatchScore      = Best;
            _BestOtherMatchIndex = BestIndex;
            _ThisBestStartIndex  = ThisBestIndex;

            return(Scores);
        }