diff --git a/OpenNest.Engine/NestEngineInfo.cs b/OpenNest.Engine/NestEngineInfo.cs new file mode 100644 index 0000000..a18a93d --- /dev/null +++ b/OpenNest.Engine/NestEngineInfo.cs @@ -0,0 +1,18 @@ +using System; + +namespace OpenNest +{ + public class NestEngineInfo + { + public NestEngineInfo(string name, string description, Func factory) + { + Name = name; + Description = description; + Factory = factory; + } + + public string Name { get; } + public string Description { get; } + public Func Factory { get; } + } +} diff --git a/OpenNest.Engine/NestEngineRegistry.cs b/OpenNest.Engine/NestEngineRegistry.cs new file mode 100644 index 0000000..a189de9 --- /dev/null +++ b/OpenNest.Engine/NestEngineRegistry.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace OpenNest +{ + public static class NestEngineRegistry + { + private static readonly List engines = new(); + + static NestEngineRegistry() + { + Register("Default", + "Multi-phase nesting (Linear, Pairs, RectBestFit, Remainder)", + plate => new DefaultNestEngine(plate)); + } + + public static IReadOnlyList AvailableEngines => engines; + + public static string ActiveEngineName { get; set; } = "Default"; + + public static NestEngineBase Create(Plate plate) + { + var info = engines.FirstOrDefault(e => + e.Name.Equals(ActiveEngineName, StringComparison.OrdinalIgnoreCase)); + + if (info == null) + { + Debug.WriteLine($"[NestEngineRegistry] Engine '{ActiveEngineName}' not found, falling back to Default"); + info = engines[0]; + } + + return info.Factory(plate); + } + + public static void Register(string name, string description, Func factory) + { + if (engines.Any(e => e.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) + { + Debug.WriteLine($"[NestEngineRegistry] Duplicate engine '{name}' skipped"); + return; + } + + engines.Add(new NestEngineInfo(name, description, factory)); + } + + public static void LoadPlugins(string directory) + { + if (!Directory.Exists(directory)) + return; + + foreach (var dll in Directory.GetFiles(directory, "*.dll")) + { + try + { + var assembly = Assembly.LoadFrom(dll); + + foreach (var type in assembly.GetTypes()) + { + if (type.IsAbstract || !typeof(NestEngineBase).IsAssignableFrom(type)) + continue; + + var ctor = type.GetConstructor(new[] { typeof(Plate) }); + + if (ctor == null) + { + Debug.WriteLine($"[NestEngineRegistry] Skipping {type.Name}: no Plate constructor"); + continue; + } + + // Create a temporary instance to read Name and Description. + try + { + var tempPlate = new Plate(); + var instance = (NestEngineBase)ctor.Invoke(new object[] { tempPlate }); + Register(instance.Name, instance.Description, + plate => (NestEngineBase)ctor.Invoke(new object[] { plate })); + Debug.WriteLine($"[NestEngineRegistry] Loaded plugin engine: {instance.Name}"); + } + catch (Exception ex) + { + Debug.WriteLine($"[NestEngineRegistry] Failed to instantiate {type.Name}: {ex.Message}"); + } + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NestEngineRegistry] Failed to load assembly {Path.GetFileName(dll)}: {ex.Message}"); + } + } + } + } +}