context: #region License
  // Copyright (c) 2007 James Newton-King
  //
  // Permission is hereby granted, free of charge, to any person
  // obtaining a copy of this software and associated documentation
  // files (the "Software"), to deal in the Software without
  // restriction, including without limitation the rights to use,
  // copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the
  // Software is furnished to do so, subject to the following
  // conditions:
  //
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  // OTHER DEALINGS IN THE SOFTWARE.
  #endregion
  
  using System;
  using System.Collections.Generic;
  using System.Reflection;
  using System.Collections;
  using System.Linq;
  
  namespace Magentaize.Net.LMCL.JsonLite.Utilities
  {
      internal static class CollectionUtils
      {
          /// <summary>
          /// Determines whether the collection is null or empty.
          /// </summary>
          /// <param name="collection">The collection.</param>
          /// <returns>
          /// 	<c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
          /// </returns>
          public static bool IsNullOrEmpty<T>(ICollection<T> collection)
          {
              if (collection != null)
              {
                  return (collection.Count == 0);
              }
              return true;
          }
  
          /// <summary>
          /// Adds the elements of the specified collection to the specified generic IList.
          /// </summary>
          /// <param name="initial">The list to add to.</param>
          /// <param name="collection">The collection of elements to add.</param>
          public static void AddRange<T>(this IList<T> initial, IEnumerable<T> collection)
          {
              if (initial == null)
              {
                  throw new ArgumentNullException(nameof(initial));
              }
  
              if (collection == null)
              {
                  return;
              }
  
              foreach (T value in collection)
              {
                  initial.Add(value);
              }
          }
  
          public static bool IsDictionaryType(Type type)
          {
              ValidationUtils.ArgumentNotNull(type, nameof(type));
  
              if (typeof(IDictionary).IsAssignableFrom(type))
              {
                  return true;
              }
              if (ReflectionUtils.ImplementsGenericDefinition(type, typeof(IDictionary<,>)))
              {
                  return true;
              }
  
              return false;
          }
  
          public static ConstructorInfo ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType)
          {
              Type genericEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionItemType);
              ConstructorInfo match = null;
  
              foreach (ConstructorInfo constructor in collectionType.GetConstructors(BindingFlags.Public | BindingFlags.Instance))
              {
                  IList<ParameterInfo> parameters = constructor.GetParameters();
  
                  if (parameters.Count == 1)
                  {
                      if (genericEnumerable == parameters[0].ParameterType)
                      {
                          // exact match
                          match = constructor;
                          break;
                      }
  
                      // incase we can't find an exact match, use first inexact
                      if (match == null)
                      {
                          if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
                          {
                              match = constructor;
                          }
                      }
                  }
              }
  
              return match;
          }
  
          public static bool AddDistinct<T>(this IList<T> list, T value)
          {
              return list.AddDistinct(value, EqualityComparer<T>.Default);
          }
  
          public static bool AddDistinct<T>(this IList<T> list, T value, IEqualityComparer<T> comparer)
          {
              if (list.ContainsValue(value, comparer))
              {
                  return false;
              }
  
              list.Add(value);
              return true;
          }
  
          // this is here because LINQ Bridge doesn't support Contains with IEqualityComparer<T>
          public static bool ContainsValue<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
          {
              if (comparer == null)
              {
                  comparer = EqualityComparer<TSource>.Default;
              }
  
              if (source == null)
              {
                  throw new ArgumentNullException(nameof(source));
              }
  
              foreach (TSource local in source)
              {
                  if (comparer.Equals(local, value))
                  {
                      return true;
                  }
              }
  
              return false;
          }
  
          public static bool AddRangeDistinct<T>(this IList<T> list, IEnumerable<T> values, IEqualityComparer<T> comparer)
          {
              bool allAdded = true;
              foreach (T value in values)
              {
                  if (!list.AddDistinct(value, comparer))
                  {
                      allAdded = false;
                  }
              }
  
              return allAdded;
          }
  
          public static int IndexOf<T>(this IEnumerable<T> collection, Func<T, bool> predicate)
          {
              int index = 0;
              foreach (T value in collection)
              {
                  if (predicate(value))
                  {
                      return index;
                  }
  
                  index++;
              }
  
              return -1;
          }
  
          public static bool Contains<T>(this List<T> list, T value, IEqualityComparer comparer)
          {
              for (int i = 0; i < list.Count; i++)
              {
                  if (comparer.Equals(value, list[i]))
                  {
                      return true;
                  }
              }
              return false;
          }
  
          public static int IndexOfReference<T>(this List<T> list, T item)
          {
              for (int i = 0; i < list.Count; i++)
              {
                  if (ReferenceEquals(item, list[i]))
                  {
                      return i;
                  }
              }
              return -1;
          }
  
          private static IList<int> GetDimensions(IList values, int dimensionsCount)
          {
              IList<int> dimensions = new List<int>();
  
              IList currentArray = values;
              while (true)
              {
                  dimensions.Add(currentArray.Count);
  
                  // don't keep calculating dimensions for arrays inside the value array
  
gt:                 if (dimensions.Count == dimensionsCount)