/// <summary>
        ///     Formats <see cref="TimeSpan" /> as string with specified suffixes
        ///     for each measure (days, hours, minutes, seconds and milliseconds).
        /// </summary>
        /// <param name="time">Value to be formatted.</param>
        /// <param name="formatStrings">String suffixes for formatting each measure.</param>
        /// <param name="measures">Return only specified top significant measures.</param>
        public static string ToFormattedString (this TimeSpan time,
                                                int? measures = null,
                                                TimeSpanFormatStrings formatStrings = null)
        {
            measures.RequiredGreaterThan (0, "measures");
            measures.RequiredNotGreaterThan (5, "measures");

            var result = new StringBuilder ();
            var format_strings = formatStrings ?? TimeSpanFormatStrings.Default;


            if (time == TimeSpan.Zero)
                return "0" + format_strings.Milliseconds;

            if (time.Ticks < 0)
            {
                result.Append ('-');
                time = time.Negate ();
            }

            
            int? first_measure = null;
            var max_measure = measures ?? 5;
            var add_separator = false;

            if (time.Days > 0)
            {
                const int current_measure = 4;

                first_measure = current_measure;

                if (first_measure - current_measure < max_measure)
                {
                    result.Append (time.Days);
                    result.Append (format_strings.Days);
                    add_separator = true;
                }
            }

            if (time.Hours > 0)
            {
                const int current_measure = 3;

                if (first_measure == null)
                    first_measure = current_measure;

                if (first_measure - current_measure < max_measure)
                {
                    if (add_separator)
                        result.Append (' ');

                    result.Append (time.Hours);
                    result.Append (format_strings.Hours);
                    add_separator = true;
                }
            }

            if (time.Minutes > 0)
            {
                const int current_measure = 2;

                if (first_measure == null)
                    first_measure = current_measure;

                if (first_measure - current_measure < max_measure)
                {
                    if (add_separator)
                        result.Append (' ');

                    result.Append (time.Minutes);
                    result.Append (format_strings.Minutes);
                    add_separator = true;
                }
            }

            if (time.Seconds > 0)
            {
                const int current_measure = 1;

                if (first_measure == null)
                    first_measure = current_measure;

                if (first_measure - current_measure < max_measure)
                {
                    if (add_separator)
                        result.Append (' ');

                    result.Append (time.Seconds);
                    result.Append (format_strings.Seconds);
                    add_separator = true;
                }
            }

            if (time.Milliseconds > 0)
            {
                const int current_measure = 0;

                if (first_measure == null)
                    first_measure = current_measure;

                if (first_measure - current_measure < max_measure)
                {
                    if (add_separator)
                        result.Append (' ');

                    result.Append (time.Milliseconds);
                    result.Append (format_strings.Milliseconds);
                    add_separator = true;
                }
            }

            return result.ToString ();
        }
        /// <summary>
        ///     Formats <see cref="TimeSpan" /> as string with specified suffixes
        ///     for each measure (days, hours, minutes, seconds and milliseconds).
        /// </summary>
        /// <param name="time">Value to be formatted.</param>
        /// <param name="formatStrings">String suffixes for formatting each measure.</param>
        /// <param name="measures">Return only specified top significant measures.</param>
        public static string ToFormattedString(this TimeSpan time,
                                               int?measures = null,
                                               TimeSpanFormatStrings formatStrings = null)
        {
            measures.RequiredGreaterThan(0, "measures");
            measures.RequiredNotGreaterThan(5, "measures");

            var result         = new StringBuilder();
            var format_strings = formatStrings ?? TimeSpanFormatStrings.Default;


            if (time == TimeSpan.Zero)
            {
                return("0" + format_strings.Milliseconds);
            }

            if (time.Ticks < 0)
            {
                result.Append('-');
                time = time.Negate();
            }


            int?first_measure = null;
            var max_measure   = measures ?? 5;
            var add_separator = false;

            if (time.Days > 0)
            {
                const int current_measure = 4;

                first_measure = current_measure;

                if (first_measure - current_measure < max_measure)
                {
                    result.Append(time.Days);
                    result.Append(format_strings.Days);
                    add_separator = true;
                }
            }

            if (time.Hours > 0)
            {
                const int current_measure = 3;

                if (first_measure == null)
                {
                    first_measure = current_measure;
                }

                if (first_measure - current_measure < max_measure)
                {
                    if (add_separator)
                    {
                        result.Append(' ');
                    }

                    result.Append(time.Hours);
                    result.Append(format_strings.Hours);
                    add_separator = true;
                }
            }

            if (time.Minutes > 0)
            {
                const int current_measure = 2;

                if (first_measure == null)
                {
                    first_measure = current_measure;
                }

                if (first_measure - current_measure < max_measure)
                {
                    if (add_separator)
                    {
                        result.Append(' ');
                    }

                    result.Append(time.Minutes);
                    result.Append(format_strings.Minutes);
                    add_separator = true;
                }
            }

            if (time.Seconds > 0)
            {
                const int current_measure = 1;

                if (first_measure == null)
                {
                    first_measure = current_measure;
                }

                if (first_measure - current_measure < max_measure)
                {
                    if (add_separator)
                    {
                        result.Append(' ');
                    }

                    result.Append(time.Seconds);
                    result.Append(format_strings.Seconds);
                    add_separator = true;
                }
            }

            if (time.Milliseconds > 0)
            {
                const int current_measure = 0;

                if (first_measure == null)
                {
                    first_measure = current_measure;
                }

                if (first_measure - current_measure < max_measure)
                {
                    if (add_separator)
                    {
                        result.Append(' ');
                    }

                    result.Append(time.Milliseconds);
                    result.Append(format_strings.Milliseconds);
                    add_separator = true;
                }
            }

            return(result.ToString());
        }