MatchingCopyPattern internalFindMatchingCopyPattern(
            FindMatchingPatternConfig findConfig,
            CopyPatternPreset replaceConfig)
        {
            var ret = new MatchingCopyPattern();

            bool matchG5Lengths = replaceConfig.MatchLengths5;
            bool matchG6Lengths = replaceConfig.MatchLengths6;
            bool matchSpacing = replaceConfig.MatchSpacing;
            bool matchBeat = replaceConfig.MatchBeat;

            TickPair ticks;
            if (!getPatternMatchTicks(out ticks))
                return ret;

            var track5 = EditorG5.GuitarTrack;
            var track6 = EditorPro.GuitarTrack;

            var chords5 = track5.Messages.Chords.ToArray();
            var nchords6 = track6.Messages.Chords.ToArray();

            var matchChords5 = track5.Messages.Chords.GetBetweenTick(ticks).ToArray();
            if (matchChords5.Length == 0)
                return ret;

            var oChords6 = track6.Messages.Chords.GetBetweenTick(ticks).ToArray();

            if (oChords6.Length == 0)
                return ret;

            if (replaceConfig.ForwardOnly && !findConfig.FindPrevious)
            {
                chords5 = chords5.Where(x => x.DownTick >= ticks.Up).ToArray();
                nchords6 = nchords6.Where(x => x.DownTick >= ticks.Up).ToArray();
            }

            int minMatchTick5 = matchChords5.GetMinTick();

            int minMatchTick6 = oChords6.GetMinTick();
            int maxMatchTick6 = oChords6.GetMaxTick();

            ret.DeltaTimeStart = track6.TickToTime(minMatchTick6) -
                track5.TickToTime(minMatchTick5);

            if (matchChords5.Any() == false)
                return ret;

            int numMatchChords5 = matchChords5.Count();
            int numMatchChords6 = oChords6.Count();

            ret.OriginalChords6 = oChords6.ToArray();
            ret.StartTick = ticks.Down;
            ret.EndTick = ticks.Up;

            var checkStrings = new cmpNoteFunc(
                (n1, n2) =>
                {
                    return n1.NoteString != n2.NoteString;
                });
            var checkData1 = new cmpNoteFunc(
                (n1, n2) =>
                {
                    return n1.NoteFretDown != n2.NoteFretDown;
                });
            var checkLength = new cmpNoteFunc(
                (n1, n2) =>
                {
                    return Utility.IsCloseTick(n1.TickLength, n2.TickLength) == false;
                });

            var checkNull = new cmpNoteFunc((a, b) =>
            {
                return ((a == null) || (b == null));
            });

            var testBeat = new cmpChordFunc((co, cn) =>
            {
                var ob32 = ProGuitarTrack.GetTempo(co.DownTick).SecondsPerThirtySecondNote;
                var ob = ProGuitarTrack.GetTempo(co.DownTick).SecondsPerQuarterNote;
                var nb = ProGuitarTrack.GetTempo(cn.DownTick).SecondsPerQuarterNote;

                var diff = Math.Abs(ob - nb);
                if (diff > ob32)
                {
                    return false;
                }

                return true;
            });
            var chordsEqual = new cmpChordFunc(
                (a, b) =>
                {
                    if (matchBeat && testBeat(a, b) == false)
                        return false;

                    for (int x = 0; x < 6; x++)
                    {
                        var an = a.Notes[x];
                        var bn = b.Notes[x];

                        if (an == null && bn == null)
                            continue;

                        if (checkNull(an, bn) ||
                            checkData1(an, bn) ||
                            checkStrings(an, bn) ||
                            (matchG5Lengths && checkLength(an, bn)))
                        {
                            return false;
                        }
                    }
                    return true;
                });

            var testSpacing = new matchFunc((mfmatch, mfmca) =>
            {
                for (int y = 0; y < mfmca.Length - 1; y++)
                {
                    var nc = mfmatch[y];
                    var oc = mfmca[y];

                    var timeTillNext5 =
                        track5.TickToTime(mfmca[y + 1].DownTick) -
                        track5.TickToTime(oc.UpTick);

                    var timeTillNext52 =
                        track5.TickToTime(mfmatch[y + 1].DownTick) -
                        track5.TickToTime(nc.UpTick);

                    var diff = Math.Abs(timeTillNext52 - timeTillNext5);
                    double spb = ProGuitarTrack.GetTempo(oc.DownTick).SecondsPerThirtySecondNote;
                    if (diff > spb)
                    {
                        return false;
                    }
                }
                return true;
            });

            var mca = matchChords5.ToArray();
            var match = new GuitarChord[mca.Length];
            var matches = new List<GuitarChord[]>();
            for (int ci = 0; ci < chords5.Length - mca.Length; ci++)
            {
                for (int mc = 0; mc < mca.Length; mc++)
                {
                    var cc = chords5[ci + mc];

                    if (cc.DownTick < mca[mca.Length - 1].UpTick &&
                        cc.UpTick > mca[0].DownTick)
                    {
                        break;
                    }

                    if (chordsEqual(cc, mca[mc]))
                    {
                        match[mc] = cc;
                        if (mc == mca.Length - 1)
                        {
                            if (matchSpacing)
                            {
                                if (testSpacing(match, mca) == true)
                                {
                                    matches.Add(match.ToArray());
                                    ci += mca.Length - 1;
                                }
                            }
                            else
                            {
                                matches.Add(match.ToArray());
                                ci += mca.Length - 1;
                            }
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }

            var goodMatches = new List<GuitarChord[]>();
            foreach (var m in matches)
            {
                var c6 = track6.Messages.Chords.GetBetweenTick(m.GetTickPair()).ToArray();
                bool matching = true;
                if (replaceConfig.MatchLengths6)
                {

                    if (c6.Length == oChords6.Length)
                    {
                        for (int x = 0; x < c6.Length; x++)
                        {
                            if (!Utility.IsCloseTick(c6[x].TickPair.TickLength, oChords6[x].TickPair.TickLength))
                            {
                                matching = false;
                                break;
                            }
                        }
                    }
                    else
                    {
                        matching = false;
                    }
                }

                if (matching)
                {
                    goodMatches.Add(c6);
                }
            }
            foreach (var m in goodMatches)
            {
                ret.Matches.Add(m);
            }
            return ret;
        }
        MatchingCopyPattern FindMatchingCopyPattern(FindMatchingPatternConfig config, CopyPatternPreset replaceConfig = null)
        {
            MatchingCopyPattern ret = null;

            try
            {
                if (replaceConfig == null)
                {
                    replaceConfig = GetNewCopyPatternPresetFromScreen();
                }

                ret = internalFindMatchingCopyPattern(config, replaceConfig);
                if (ret == null)
                    return ret;

                var matches = ret.Matches.ToArray();

                ret.Matches.Clear();

                matches.ToList().For((x, i) => matches[i] = x.SortTicks().ToArray());

                if (config.FindNext && config.FindPrevious)
                {
                    if (config.FirstMatchOnly)
                    {
                        ret.Matches.Add(matches.FirstOrDefault());
                    }
                    else
                    {
                        foreach (var itm in matches)
                        {
                            ret.Matches.Add(itm);
                        }
                    }
                }
                else if (config.FindNext)
                {
                    var next = matches.Where(n => n.GetMinTick() > SelectedChord.DownTick);
                    if (next != null && next.Any())
                    {
                        if (config.FirstMatchOnly)
                        {
                            ret.Matches.Add(next.FirstOrDefault());
                        }
                        else
                        {
                            foreach (var itm in next)
                            {
                                ret.Matches.Add(itm);
                            }
                        }
                    }
                }
                else if (config.FindPrevious)
                {
                    var next = matches.Where(n => n.GetMinTick() < SelectedChord.DownTick);
                    if (next != null && next.Any())
                    {
                        if (config.FirstMatchOnly)
                        {
                            ret.Matches.Add(next.LastOrDefault());
                        }
                        else
                        {
                            ret.Matches.AddRange(next);
                        }
                    }
                }
            }
            catch { }

            return ret;
        }