using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using EcsRx.Extensions;
using EcsRx.Infrastructure.Dependencies;
using EcsRx.Systems;
namespace EcsRx.Infrastructure.Extensions
{
public static class IEcsRxApplicationExtensions
{
///
/// This will bind any ISystem implementations that are found within the assembly provided
///
///
/// This can save you time but is not advised in most cases
///
/// The application to act on
/// The assemblies to scan for systems
public static void BindAllSystemsInAssemblies(this IEcsRxApplication application, params Assembly[] assemblies)
{
var systemType = typeof(ISystem);
var applicableSystems = assemblies.SelectMany(x => x.GetTypes())
.Where(x =>
{
if(x.IsInterface || x.IsAbstract)
{ return false; }
return systemType.IsAssignableFrom(x);
})
.ToList();
if(!applicableSystems.Any())
{ return; }
foreach (var applicableSystemType in applicableSystems)
{
var bindingConfiguration = new BindingConfiguration
{
AsSingleton = true,
WithName = applicableSystemType.Name
};
application.Container.Bind(systemType, applicableSystemType, bindingConfiguration);
}
}
///
/// This will bind any ISystem implementations that are found within the namespaces provided
///
///
/// It is also advised you wrap this method with your own conventions like BindAllSystemsWithinApplicationScope does.
///
/// The application to act on
/// The namespaces to be scanned for implementations
public static void BindAllSystemsInNamespaces(this IEcsRxApplication application, params string[] namespaces)
{
var applicationAssemblies = AppDomain.CurrentDomain.GetAssemblies();
var systemType = typeof(ISystem);
var applicableSystems = applicationAssemblies.SelectMany(x => x.GetTypes())
.Where(x =>
{
if(x.IsInterface || x.IsAbstract)
{ return false; }
if(string.IsNullOrEmpty(x.Namespace))
{ return false; }
if(!systemType.IsAssignableFrom(x))
{ return false; }
return namespaces.Any(namespaceToVerify => x.Namespace.Contains(namespaceToVerify));
})
.ToList();
if(!applicableSystems.Any())
{ return; }
foreach (var applicableSystemType in applicableSystems)
{
var bindingConfiguration = new BindingConfiguration
{
AsSingleton = true,
WithName = applicableSystemType.Name
};
application.Container.Bind(systemType, applicableSystemType, bindingConfiguration);
}
}
///
/// This will bind any ISystem implementations found within Systems, ViewResolvers folders which are located
/// in a child namespace of the application.
///
///
/// This is a conventional based binding that expects the application file to sit in the root of a directory,
/// and then have systems in folders within same directory,if you need other conventions then look at wrapping
/// BindAnySystemsInNamespace
///
/// The application to act on
public static void BindAllSystemsWithinApplicationScope(this IEcsRxApplication application)
{
var applicationNamespace = application.GetType().Namespace;
var namespaces = new[]
{
$"{applicationNamespace}.Systems",
$"{applicationNamespace}.ViewResolvers"
};
application.BindAllSystemsInNamespaces(namespaces);
}
///
/// This will bind the given system type (T) to the DI container against `ISystem`
/// and will then immediately register the system with the SystemExecutor.
///
/// The application to act on
/// The implementation of ISystem to bind/register
/// This is really for runtime usage, in mose cases you will want to bind in starting and register in started
public static void BindAndStartSystem(this IEcsRxApplication application) where T : ISystem
{
application.Container.Bind(x => x.WithName(typeof(T).Name));
StartSystem(application);
}
///
/// This will resolve the given type (T) from the DI container then register it
/// with the SystemExecutor.
///
/// The application to act on
/// The implementation of ISystem to register
public static void StartSystem(this IEcsRxApplication application) where T : ISystem
{
ISystem system;
if(application.Container.HasBinding(typeof(T).Name))
{ system = application.Container.Resolve(typeof(T).Name); }
else
{ system = application.Container.Resolve(); }
application.SystemExecutor.AddSystem(system);
}
///
/// Resolve all systems which have been bound in the order they should be registered
///
/// The application to act on
/// This ordering will be purely by priority
public static IEnumerable GetAllBoundSystems(this IEcsRxApplication application)
{
var allSystems = application.Container.ResolveAll();
return allSystems.OrderByPriority();
}
///
/// Resolve all systems which have been bound and register them in order with the systems executor
///
/// The application to act on
/// Will be purely
public static void StartAllBoundSystems(this IEcsRxApplication application)
{
var allSystems = GetAllBoundSystems(application);
allSystems.ForEachRun(application.SystemExecutor.AddSystem);
}
}
}