/// <summary>
        /// Convert the specified list of delegate entries into a string array.
        /// </summary>

        public static string[] GetNames(List <Entry> list, string choice, out int index)
        {
            index = 0;
            string[] names = new string[list.Count + 1];
            names[0] = "<GameObject>";

            for (int i = 0; i < list.Count;)
            {
                Entry  ent = list[i];
                string del = TweenKitTools.GetFuncName(ent.target, ent.name);
                names[++i] = del;
                if (index == 0 && string.Equals(del, choice))
                {
                    index = i;
                }
            }
            return(names);
        }
        /// <summary>
        /// Draw an editor field for the Unity Delegate.
        /// </summary>

        public static bool Field(Object undoObject, EventDelegate del, bool removeButton, bool minimalistic)
        {
            if (del == null)
            {
                return(false);
            }
            bool prev = GUI.changed;

            GUI.changed = false;
            bool          retVal = false;
            MonoBehaviour target = del.target;
            bool          remove = false;

            if (removeButton && (del.target != null || del.isValid))
            {
                if (!minimalistic)
                {
                    TweenKitEditorTools.SetLabelWidth(82f);
                }

                if (del.target == null && del.isValid)
                {
                    EditorGUILayout.LabelField("Notify", del.ToString());
                }
                else
                {
                    target = EditorGUILayout.ObjectField("Notify", del.target, typeof(MonoBehaviour), true) as MonoBehaviour;
                }

                GUILayout.Space(-18f);
                GUILayout.BeginHorizontal();
                GUILayout.Space(70f);

                if (GUILayout.Button("", "ToggleMixed", GUILayout.Width(20f), GUILayout.Height(16f)))
                {
                    target = null;
                    remove = true;
                }
                GUILayout.EndHorizontal();
            }
            else
            {
                target = EditorGUILayout.ObjectField("Notify", del.target, typeof(MonoBehaviour), true) as MonoBehaviour;
            }

            if (remove)
            {
                TweenKitEditorTools.RegisterUndo("Delegate Selection", undoObject);
                del.Clear();
                TweenKitTools.SetDirty(undoObject);
            }
            else if (del.target != target)
            {
                TweenKitEditorTools.RegisterUndo("Delegate Selection", undoObject);
                del.target = target;
                TweenKitTools.SetDirty(undoObject);
            }

            if (del.target != null && del.target.gameObject != null)
            {
                GameObject   go   = del.target.gameObject;
                List <Entry> list = GetMethods(go);

                int      index  = 0;
                string[] names  = PropertyReferenceDrawer.GetNames(list, del.ToString(), out index);
                int      choice = 0;

                GUILayout.BeginHorizontal();
                choice = EditorGUILayout.Popup("Method", index, names);
                TweenKitEditorTools.DrawPadding();
                GUILayout.EndHorizontal();

                if (choice > 0 && choice != index)
                {
                    Entry entry = list[choice - 1];
                    TweenKitEditorTools.RegisterUndo("Delegate Selection", undoObject);
                    del.target     = entry.target as MonoBehaviour;
                    del.methodName = entry.name;
                    TweenKitTools.SetDirty(undoObject);
                    retVal = true;
                }

                GUI.changed = false;
                EventDelegate.Parameter[] ps = del.parameters;

                if (ps != null)
                {
                    for (int i = 0; i < ps.Length; ++i)
                    {
                        EventDelegate.Parameter param = ps[i];
                        Object obj = EditorGUILayout.ObjectField("   Arg " + i, param.obj, typeof(Object), true);

                        if (GUI.changed)
                        {
                            GUI.changed = false;
                            param.obj   = obj;
                            TweenKitTools.SetDirty(undoObject);
                        }

                        if (obj == null)
                        {
                            continue;
                        }

                        GameObject  selGO = null;
                        System.Type type  = obj.GetType();
                        if (type == typeof(GameObject))
                        {
                            selGO = obj as GameObject;
                        }
                        else if (type.IsSubclassOf(typeof(Component)))
                        {
                            selGO = (obj as Component).gameObject;
                        }

                        if (selGO != null)
                        {
                            // Parameters must be exact -- they can't be converted like property bindings
                            PropertyReferenceDrawer.filter     = param.expectedType;
                            PropertyReferenceDrawer.canConvert = false;
                            List <PropertyReferenceDrawer.Entry> ents = PropertyReferenceDrawer.GetProperties(selGO, true, false);

                            int      selection;
                            string[] props = GetNames(ents, TweenKitTools.GetFuncName(param.obj, param.field), out selection);

                            GUILayout.BeginHorizontal();
                            int newSel = EditorGUILayout.Popup(" ", selection, props);
                            TweenKitEditorTools.DrawPadding();
                            GUILayout.EndHorizontal();

                            if (GUI.changed)
                            {
                                GUI.changed = false;

                                if (newSel == 0)
                                {
                                    param.obj   = selGO;
                                    param.field = null;
                                }
                                else
                                {
                                    param.obj   = ents[newSel - 1].target;
                                    param.field = ents[newSel - 1].name;
                                }
                                TweenKitTools.SetDirty(undoObject);
                            }
                        }
                        else if (!string.IsNullOrEmpty(param.field))
                        {
                            param.field = null;
                            TweenKitTools.SetDirty(undoObject);
                        }

                        PropertyReferenceDrawer.filter     = typeof(void);
                        PropertyReferenceDrawer.canConvert = true;
                    }
                }
            }
            else
            {
                retVal = GUI.changed;
            }
            GUI.changed = prev;
            return(retVal);
        }
        /// <summary>
        /// Collect a list of usable delegates from the specified target game object.
        /// </summary>

        public static List <Entry> GetMethods(GameObject target)
        {
            var comps = target.GetComponents <MonoBehaviour>();
            var list  = new List <Entry>();

            for (int i = 0, imax = comps.Length; i < imax; ++i)
            {
                MonoBehaviour mb = comps[i];
                if (mb == null)
                {
                    continue;
                }

                MethodInfo[] methods = mb.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);

                for (int b = 0; b < methods.Length; ++b)
                {
                    MethodInfo mi = methods[b];

                    if (mi.ReturnType == typeof(void))
                    {
                        string name = mi.Name;
                        if (name == "Invoke")
                        {
                            continue;
                        }
                        if (name == "InvokeRepeating")
                        {
                            continue;
                        }
                        if (name == "CancelInvoke")
                        {
                            continue;
                        }
                        if (name == "StopCoroutine")
                        {
                            continue;
                        }
                        if (name == "StopAllCoroutines")
                        {
                            continue;
                        }
                        if (name == "BroadcastMessage")
                        {
                            continue;
                        }
                        if (name.StartsWith("SendMessage"))
                        {
                            continue;
                        }
                        if (name.StartsWith("set_"))
                        {
                            continue;
                        }

                        Entry ent = new Entry();
                        ent.target = mb;
                        ent.name   = mi.Name;
                        list.Add(ent);
                    }
                }
            }
            return(list);
        }