using System ;
using System.Collections.Generic ;
using System.Linq ;
using TNode.Attribute ;
using TNode.BaseViews ;
using TNode.Editor ;
using TNode.Editor.BaseViews ;
using TNode.Models ;
using UnityEditor.Experimental.GraphView ;
using UnityEngine ;
namespace TNode.Cache {
/// <summary>
/// Internal singleton class for caching TNode reflection Data.
/// </summary>
internal class NodeEditorSingleton {
private static NodeEditorSingleton _ instance ;
public readonly Dictionary < Type , Type > FromGenericToSpecific = new Dictionary < Type , Type > ( ) ;
public readonly Dictionary < Type , List < Type > > GraphDataUsage = new Dictionary < Type , List < Type > > ( ) ;
public static NodeEditorSingleton Instance {
get { return _ instance ? ? = new NodeEditorSingleton ( ) ; }
}
private static readonly string [ ] ExcludedAssemblies = new string [ ] { "Microsoft" , "UnityEngine" , "UnityEditor" , "mscorlib" , "System" } ;
private NodeEditorSingleton ( ) {
//exclude unity ,system ,and microsoft types
var assemblies = AppDomain .
CurrentDomain . GetAssemblies ( )
. Where ( x = > ExcludedAssemblies . All ( y = > ! x . GetName ( ) . Name . Split ( "." ) [ 0 ] . Equals ( y ) ) ) ;
foreach ( var assembly in assemblies ) {
foreach ( var type in assembly . GetTypes ( ) ) {
if ( type . IsClass & & ! type . IsAbstract ) {
//Register Node View And Graph View via its parent class
SetNodeComponentAttribute ( type ) ;
//Register Node Data by GraphUsageAttribute.
SetGraphUsageAttribute ( type ) ;
}
}
}
}
private void SetGraphUsageAttribute ( Type type ) {
foreach ( var attribute in type . GetCustomAttributes ( typeof ( GraphUsageAttribute ) , true ) ) {
var parent = type . BaseType ;
if ( typeof ( NodeData ) . IsAssignableFrom ( type . BaseType ) ) {
//Check if GraphDataUsage dictionary has GraphDataType of attribute
if ( attribute is GraphUsageAttribute attributeCasted ) {
if ( GraphDataUsage . ContainsKey ( attributeCasted . GraphDataType ) ) {
GraphDataUsage [ attributeCasted . GraphDataType ] . Add ( type ) ;
}
else {
GraphDataUsage . Add ( attributeCasted . GraphDataType , new List < Type > { type } ) ;
}
}
}
}
}
private void SetNodeComponentAttribute ( Type type ) {
foreach ( var attribute in type . GetCustomAttributes ( typeof ( NodeComponentAttribute ) , false ) ) {
//fetch this type 's parent class
var parent = type . BaseType ;
//Check if this type is a generic type and is a generic type of NodeView or DataGraphView
if ( parent is { IsGenericType : true } & & ( parent . GetGenericTypeDefinition ( ) = = typeof ( NodeView < > ) | |
parent . GetGenericTypeDefinition ( ) = = typeof ( DataGraphView < > ) ) ) {
//Get the generic type of this type
//Add this type to the dictionary
FromGenericToSpecific . Add ( parent , type ) ;
}
//TODO Note that a node component only applied to a specific type of editor,so ,same GraphView could behave differently in different editor.it's a todo feature.
}
}
}
//Outer wrapper for the singleton class
public static class NodeEditorExtensions {
public static T CreateInstance < T > ( ) {
Debug . Log ( $"Create A instance of {typeof(T)}" ) ;
var implementedType = NodeEditorSingleton . Instance . FromGenericToSpecific [ typeof ( T ) ] ;
var instance = ( T ) Activator . CreateInstance ( implementedType ) ;
return instance ;
}
public static object CreateInstance ( Type t ) {
Debug . Log ( $"Create A instance of {t}" ) ;
var implementedType = NodeEditorSingleton . Instance . FromGenericToSpecific [ t ] ;
var instance = Activator . CreateInstance ( implementedType ) ;
return instance ;
}
public static bool HasSpecificType < T > ( ) where T : class {
return NodeEditorSingleton . Instance . FromGenericToSpecific . ContainsKey ( typeof ( T ) ) ;
}
public static List < Type > GetGraphDataUsage ( Type t ) {
if ( NodeEditorSingleton . Instance . GraphDataUsage . ContainsKey ( t ) ) {
return NodeEditorSingleton . Instance . GraphDataUsage [ t ] ;
}
return new List < Type > ( ) ;
}
public static object CreateNodeViewFromNodeType < T > ( ) where T : NodeData , new ( ) {
//Check specific derived type exists or not.
var type = typeof ( NodeView < T > ) ;
if ( NodeEditorSingleton . Instance . FromGenericToSpecific . ContainsKey ( type ) ) {
var implementedType = NodeEditorSingleton . Instance . FromGenericToSpecific [ type ] ;
var instance = ( NodeView < T > ) Activator . CreateInstance ( implementedType ) ;
return instance ;
}
else {
return new DefaultNodeView ( ) ;
}
}
public static object CreateNodeViewFromNodeType ( Type t ) {
//Check the generic type of NodeView by t
var type = typeof ( NodeView < > ) . MakeGenericType ( t ) ;
if ( NodeEditorSingleton . Instance . FromGenericToSpecific . ContainsKey ( type ) ) {
var implementedType = NodeEditorSingleton . Instance . FromGenericToSpecific [ type ] ;
var instance = Activator . CreateInstance ( implementedType ) ;
return instance ;
}
else {
return new DefaultNodeView ( ) ;
}
}
}
}