|  | @@ -7,137 +7,25 @@ namespace MediaBrowser.Controller.Sorting
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      public static class SortExtensions
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  | +        private static readonly AlphanumComparator _comparer = new AlphanumComparator();
 | 
	
		
			
				|  |  |          public static IEnumerable<T> OrderByString<T>(this IEnumerable<T> list, Func<T, string> getName)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            return list.OrderBy(getName, new AlphanumComparator());
 | 
	
		
			
				|  |  | +            return list.OrderBy(getName, _comparer);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public static IEnumerable<T> OrderByStringDescending<T>(this IEnumerable<T> list, Func<T, string> getName)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            return list.OrderByDescending(getName, new AlphanumComparator());
 | 
	
		
			
				|  |  | +            return list.OrderByDescending(getName, _comparer);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public static IOrderedEnumerable<T> ThenByString<T>(this IOrderedEnumerable<T> list, Func<T, string> getName)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            return list.ThenBy(getName, new AlphanumComparator());
 | 
	
		
			
				|  |  | +            return list.ThenBy(getName, _comparer);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public static IOrderedEnumerable<T> ThenByStringDescending<T>(this IOrderedEnumerable<T> list, Func<T, string> getName)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            return list.ThenByDescending(getName, new AlphanumComparator());
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        private class AlphanumComparator : IComparer<string>
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            private enum ChunkType { Alphanumeric, Numeric };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            private static bool InChunk(char ch, char otherCh)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                var type = ChunkType.Alphanumeric;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                if (char.IsDigit(otherCh))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    type = ChunkType.Numeric;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                if ((type == ChunkType.Alphanumeric && char.IsDigit(ch))
 | 
	
		
			
				|  |  | -                    || (type == ChunkType.Numeric && !char.IsDigit(ch)))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    return false;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                return true;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            public static int CompareValues(string s1, string s2)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                if (s1 == null || s2 == null)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    return 0;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                int thisMarker = 0, thisNumericChunk = 0;
 | 
	
		
			
				|  |  | -                int thatMarker = 0, thatNumericChunk = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                while ((thisMarker < s1.Length) || (thatMarker < s2.Length))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    if (thisMarker >= s1.Length)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        return -1;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    else if (thatMarker >= s2.Length)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        return 1;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    char thisCh = s1[thisMarker];
 | 
	
		
			
				|  |  | -                    char thatCh = s2[thatMarker];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    var thisChunk = new StringBuilder();
 | 
	
		
			
				|  |  | -                    var thatChunk = new StringBuilder();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || InChunk(thisCh, thisChunk[0])))
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        thisChunk.Append(thisCh);
 | 
	
		
			
				|  |  | -                        thisMarker++;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                        if (thisMarker < s1.Length)
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            thisCh = s1[thisMarker];
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    while ((thatMarker < s2.Length) && (thatChunk.Length == 0 || InChunk(thatCh, thatChunk[0])))
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        thatChunk.Append(thatCh);
 | 
	
		
			
				|  |  | -                        thatMarker++;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                        if (thatMarker < s2.Length)
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            thatCh = s2[thatMarker];
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    int result = 0;
 | 
	
		
			
				|  |  | -                    // If both chunks contain numeric characters, sort them numerically
 | 
	
		
			
				|  |  | -                    if (char.IsDigit(thisChunk[0]) && char.IsDigit(thatChunk[0]))
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        if (!int.TryParse(thisChunk.ToString(), out thisNumericChunk))
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            return 0;
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        if (!int.TryParse(thatChunk.ToString(), out thatNumericChunk))
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            return 0;
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                        if (thisNumericChunk < thatNumericChunk)
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            result = -1;
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                        if (thisNumericChunk > thatNumericChunk)
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            result = 1;
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    else
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        result = thisChunk.ToString().CompareTo(thatChunk.ToString());
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    if (result != 0)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        return result;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                return 0;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            public int Compare(string x, string y)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                return CompareValues(x, y);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | +            return list.ThenByDescending(getName, _comparer);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |