/// <summary>
        /// Returns all permutations in the collections of available items.
        /// </summary>
        public static T[][] Permute <T>(IEnumerable <IEnumerable <T> > availableItems)
        {
            Debug.Assert(availableItems != null);

            var listedItems = availableItems
                              .Select((itemCollection) => itemCollection.ToLinkList( ))
                              .ToLinkList( );

            return(Permuter.Permute(listedItems, LinkList <T> .Empty).ToArray( ));
        }
        public void Permute_returns_expected_permutation(int[][] items, int[][] expectedPermutations)
        {
            var permutations = Permuter.Permute(items);

            Assert.NotNull(permutations);
            Assert.Equal(expectedPermutations.Length, permutations.Length);
            foreach (var permutation in permutations)
            {
                Assert.Contains(permutation, expectedPermutations, ArrayComparer <int> .Instance);
            }
        }
        private static IEnumerable <IInstanceCreator> GetMethodCreators(Type targetType, MethodBase method)
        {
            Debug.Assert(targetType != null);
            Debug.Assert(method != null);
            Debug.Assert(method.IsGenericMethod || !targetType.ContainsGenericParameters);

            // Ignore recursive parameters.
            var parameters = method.GetParameters( );

            if (parameters.Any(p => p.ParameterType.Is(targetType) || p.ParameterType.Is(method.DeclaringType)))
            {
                yield break;
            }

            // Retrieve creators for each parameter.
            var availableArguments = parameters.Select((p) => TypeCreator.GetInstanceCreators(p.ParameterType).AsEnumerable( ));

            // Call constructor with all argument permutations.
            foreach (var arguments in Permuter.Permute(availableArguments))
            {
                // If method is concrete, use it.
                if (!method.IsGenericMethod)
                {
                    yield return(WeakInstanceCreator.ForMethod(targetType, method, arguments));
                }
                // Otherwise, try to resolve generic arguments on method.
                else if (method is MethodInfo)
                {
                    var methodInfo = (MethodInfo)method;
                    var bindings   = new BindingCollection(Binding.EmptyBindings);
                    for (int i = 0; i < parameters.Length; ++i)
                    {
                        ParameterInfo    parameter = parameters[i];
                        IInstanceCreator argument  = arguments[i];
                        if (parameter.ParameterType.ContainsGenericParameters)
                        {
                            GenericTypeResolver.GetAssignedGenericArguments(bindings, argument.InstanceType, parameter.ParameterType);
                        }
                    }

                    foreach (LinkList <Binding> b in bindings)
                    {
                        var concreteMethod = GenericTypeResolver.MakeConcreteMethod(methodInfo, b);
                        if (concreteMethod != null)
                        {
                            targetType = concreteMethod.ReturnType;
                            yield return(WeakInstanceCreator.ForMethod(targetType, concreteMethod, arguments));
                        }
                    }
                }
            }
        }
        private static ICollection <MethodInfo> GetConcreteMethods(MethodInfo method, LinkList <Binding> bindings)
        {
            Debug.Assert(method != null);
            Debug.Assert(bindings != null);


            // Try to resolve generic arguments on method.
            var openArguments    = GenericTypeResolver.GetOpenGenericArguments(method.GetGenericArguments( ));
            var concreteBindings = new BindingCollection(bindings);

            GenericTypeResolver.BindGenericArguments(concreteBindings, openArguments);

            var concreteMethods = concreteBindings.Transform((b) => MakeConcreteMethod(method, openArguments, b));


            // If generic arguments cannot be resolved statically, try to bind method arguments by searching for creatable parameter types.
            if (concreteMethods.Count == 0)
            {
                var genericParameterTypes = method.GetParameters( )
                                            .Select(p => p.ParameterType)
                                            .Where(t => t.IsGenericType)
                                            .ToArray( );
                Debug.Assert(genericParameterTypes.All(t => !t.IsGenericParameter));

                var creatableParameterTypes = genericParameterTypes
                                              .Select(t => TypeCreator.GetCreators(t)
                                                      .Select(c => c.InstanceType)
                                                      .Distinct( )
                                                      );

                var parameterBindings = new BindingCollection(bindings);
                parameterBindings.Expand(Permuter.Permute(creatableParameterTypes), (b, permutation) => {
                    for (int i = 0; i < permutation.Length; ++i)
                    {
                        Type permutationType      = permutation[i];
                        Type genericParameterType = genericParameterTypes[i];
                        GenericTypeResolver.GetAssignedGenericArguments(b, permutationType, genericParameterType);
                    }
                });

                concreteMethods = parameterBindings.Transform((b) => MakeConcreteMethod(method, openArguments, b));
            }


            return(concreteMethods);
        }
        private static IEnumerable <T[]> Permute <T>(LinkList <LinkList <T> > availableItems, LinkList <T> currentPermutation)
        {
            // If there are no remaining available items, return current permutation.
            if (availableItems.IsEmpty)
            {
                return(currentPermutation.ToArray( ).MakeEnumerable( ));
            }

            // Otherwise, loop through all of the current available items,
            //  returning permutations of the remaining items.
            var currentAvailableItems   = availableItems.Value;
            var remainingAvailableItems = availableItems.Tail;

            Debug.Assert(currentAvailableItems != null);
            return
                (from item in currentAvailableItems
                 let nextPermutation = currentPermutation.Add(item)
                                       from permutation in Permuter.Permute(remainingAvailableItems, nextPermutation)
                                       select permutation);
        }