/// <summary>
        /// Shift all lines in "list to change" by "offset", create a matching, rate the matching and shift lines back.
        /// </summary>
        public double GetRatingOfOffset(double offset, SubtitleMatcher.SubtitleMatcherCache subtitleMatcherParams)
        {
            /*
             * Other ideas for rating:
             *      bonus value for censecutive good bi-match ratings
             */

            // move timings of every line
            subtitleMatcherParams.ShiftTime(offset, false, true);

            // match lines
            var    biMatchedLinesList = SubtitleMatcher.MatchSubtitles(subtitleMatcherParams);
            double finalRating        = 0;

            foreach (var biMatchedLines in biMatchedLinesList)
            {
                double rating = RateBiMatchedLines(biMatchedLines);

                // use rating^3 because that way small values will become smaller
                finalRating += rating * rating * rating;
            }

            // shift timings back
            subtitleMatcherParams.ShiftTime(-offset, false, true);

            return(finalRating);
        }
        /// <summary>
        /// This function test "iterations"-times different offsets and saves the best in "returnList".
        /// The offsets will be around "centerOffset" and "2 * stepSize" is the  in every direction.
        /// The returnList will be filled until "Count==Capacity". At every time, "returnList" is sorted
        /// by rating ("returnList[0]" has the best rating of all tested offsets).
        /// </summary>
        private void FindGoodOffsets(SubtitleMatcher.SubtitleMatcherCache subtitleMatcherParams, double centerOffset, double stepSize, int iterations, List <OffsetRatingTuple> returnList)
        {
            int sign = 1;             // will alternate every iteration

            for (int iteration = 0; iteration < iterations; iteration++)
            {
                double offset = sign * (stepSize * iteration) + centerOffset;
                sign *= -1;

                double averageRating = GetRatingOfOffset(offset, subtitleMatcherParams);

                if (returnList.Count < returnList.Capacity)
                {
                    returnList.Add(new OffsetRatingTuple(offset, averageRating));

                    // if all entries are filled they have to be sorted by how good they are
                    // (at index 0 the rating is best)
                    if (returnList.Count == returnList.Capacity)
                    {
                        returnList.Sort();
                    }
                }
                else
                {
                    // is value better than worst in return list?
                    if (averageRating > returnList[returnList.Count - 1].rating)
                    {
                        returnList[returnList.Count - 1].offset = offset;
                        returnList[returnList.Count - 1].rating = averageRating;

                        // bubble sort in sorted list
                        for (int i = returnList.Count - 1; i >= 1; i--)
                        {
                            // move value up (rating at lower index is higher) or end loop?
                            if (returnList[i].rating < returnList[i - 1].rating)
                            {
                                break;
                            }

                            var tmp = returnList[i];
                            returnList[i]     = returnList[i - 1];
                            returnList[i - 1] = tmp;
                        }
                    }
                }
            }
        }