/************************************************************************************************************************/

        private static List <MemberInfo> GetSortedMembers(Type type, BindingFlags bindings)
        {
            // Get the cache for the specified bindings.
            Dictionary <Type, List <MemberInfo> > memberCache;

            if (!MemberCache.TryGetValue(bindings, out memberCache))
            {
                memberCache = new Dictionary <Type, List <MemberInfo> >();
                MemberCache.Add(bindings, memberCache);
            }

            // If the members for the specified type aren't cached for those bindings, gather and sort them.
            List <MemberInfo> members;

            if (!memberCache.TryGetValue(type, out members))
            {
                var properties = type.GetProperties(bindings);
                var methods    = type.GetMethods(bindings);

                // When gathering static members, also include instance constructors.
                var constructors = ((bindings & BindingFlags.Static) == BindingFlags.Static) ?
                                   type.GetConstructors((bindings & ~BindingFlags.Static) | BindingFlags.Instance) :
                                   null;

                var capacity = properties.Length + methods.Length;
                if (constructors != null)
                {
                    capacity += constructors.Length;
                }

                members = new List <MemberInfo>(capacity);
                members.AddRange(properties);
                if (constructors != null)
                {
                    members.AddRange(constructors);
                }
                members.AddRange(methods);

                // If the bindings include static, add static members from each base type.
                if ((bindings & BindingFlags.Static) == BindingFlags.Static && type.BaseType != null)
                {
                    members.AddRange(GetSortedMembers(type.BaseType, bindings & ~BindingFlags.Instance));
                }

                UltEventUtils.StableInsertionSort(members, CompareMembers);

                memberCache.Add(type, members);
            }

            return(members);
        }
        /************************************************************************************************************************/

        private static void PopulateMenuForComponents(string prefix, GameObject[] gameObjects)
        {
            var firstGameObject = gameObjects[0];
            var components      = firstGameObject.GetComponents <Component>();

            for (int i = 0; i < components.Length; i++)
            {
                var component = components[i];

                var targets = new Object[gameObjects.Length];
                targets[0] = component;

                Type type;
                var  typeIndex = GetComponentTypeIndex(component, components, out type);

                int       minTypeCount;
                Component unused;
                GetComponent(firstGameObject, type, typeIndex, out minTypeCount, out unused);

                var j = 1;
                for (; j < gameObjects.Length; j++)
                {
                    int       typeCount;
                    Component targetComponent;
                    GetComponent(gameObjects[j], type, typeIndex, out typeCount, out targetComponent);
                    if (typeCount <= typeIndex)
                    {
                        goto NextComponent;
                    }

                    targets[j] = targetComponent;

                    if (minTypeCount > typeCount)
                    {
                        minTypeCount = typeCount;
                    }
                }

                var name = type.GetNameCS(BoolPref.ShowFullTypeNames) + " ->/";

                if (minTypeCount > 1)
                {
                    name = UltEventUtils.GetPlacementName(typeIndex) + " " + name;
                }

                PopulateMenuForObject(prefix + name, targets);
            }

            NextComponent :;
        }
        /************************************************************************************************************************/

        private static void DoMethodNameSuggestionGUI(ref Rect area, Type declaringType, string methodName)
        {
            if (declaringType == null ||
                string.IsNullOrEmpty(methodName))
            {
                return;
            }

            var lastDot = methodName.LastIndexOf('.');

            if (lastDot >= 0)
            {
                lastDot++;
                if (lastDot >= methodName.Length)
                {
                    return;
                }

                methodName = methodName.Substring(lastDot);
            }

            var methods = declaringType.GetMethods(UltEventUtils.AnyAccessBindings);

            if (methods.Length == 0)
            {
                return;
            }

            area.width -= SuggestionButtonWidth + Padding;

            var buttonArea = new Rect(
                area.x + area.width + Padding,
                area.y,
                SuggestionButtonWidth,
                area.height);

            if (GUI.Button(buttonArea, MethodNameSuggestionLabel))
            {
                var cachedState = new DrawerState();
                cachedState.CopyFrom(DrawerState.Current);

                EditorApplication.delayCall += () =>
                {
                    DrawerState.Current.CopyFrom(cachedState);

                    var bestMethod   = methods[0];
                    var bestDistance = UltEventUtils.CalculateLevenshteinDistance(methodName, bestMethod.Name);

                    var i = 1;
                    for (; i < methods.Length; i++)
                    {
                        var method   = methods[i];
                        var distance = UltEventUtils.CalculateLevenshteinDistance(methodName, method.Name);

                        if (bestDistance > distance)
                        {
                            bestDistance = distance;
                            bestMethod   = method;
                        }
                    }

                    SetMethod(bestMethod);

                    DrawerState.Current.Clear();

                    InternalEditorUtility.RepaintAllViews();
                };
            }
        }