using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public static class EditorExtensions
{
    /// <summary>
    /// FindDerivedTypesFromAssembly allows a user to query all of types derived from a
    /// particular Type at runtime.
    /// Example usage:
    ///     foreach (System.Type st in EditorUtility.FindDerivedTypesFromAssembly(System.Reflection.Assembly.GetAssembly(typeof(BaseTimelineEvent)), typeof(BaseTimelineEvent), true))
    /// </summary>
    /// <param name="assembly">The assembly to search in</param>
    /// <param name="baseType">The base Type from which all returned Types derive</param>
    /// <param name="classOnly">If true, only class Types will be returned</param>
    /// <returns></returns>
    public static System.Type[] FindDerivedTypesFromAssembly(this System.Reflection.Assembly assembly, System.Type baseType, bool classOnly = true)
    {
        if (assembly == null)
            Debug.LogError("Assembly must be defined");
        if (baseType == null)
            Debug.LogError("Base type must be defined");

        // Iterate through all available types in the assembly
        var types = assembly.GetTypes().Where(type =>
            {
                if (classOnly && !type.IsClass)
                    return false;
                
                if (baseType.IsInterface)
                {
                    var it = type.GetInterface(baseType.FullName);

                    if (it != null)
                        return true;
                }
                else if (type.IsSubclassOf(baseType))
                {
                    return true;
                }

                return false;
            }
        );

        return types.ToArray();
    }

    /// <summary>
    /// A convenient method for calling the above.
    /// Example usage:
    ///     List<System.Type> subTypes = EditorUtility.FindDerivedTypes(typeof(BaseTimelineEvent)).ToList();
    /// </summary>
    /// <param name="baseType"></param>
    /// <param name="classOnly"></param>
    /// <returns></returns>
    public static System.Type[] FindDerivedTypes(System.Type baseType, bool classOnly = true)
    {
        return FindDerivedTypesFromAssembly(System.Reflection.Assembly.GetAssembly(baseType), baseType, classOnly);
    }
}