using System;
using System.Collections.Generic;
using System.Linq;
using global::System.Reflection;
using global::Pilz.Reflection.PluginSystem.Attributes;
namespace Pilz.Reflection.PluginSystem
{
public class Plugin
{
///
/// A collection of Methods that contains PluginFunctions that will be called automatically when loading the Plugin, as long as the property AutoCallMainFunctions is set to True.
///
///
public IReadOnlyList MainFunctions { get; private set; }
///
/// A collection of Methods with a FunctionCode (excluding all PluginFunctions from MainFunctions).
///
///
public IReadOnlyList PluginFunctions { get; private set; }
///
/// Gets the assembly that contains the PluginFunctions of this Plugin
///
///
public Assembly Assembly { get; private set; }
///
/// Gets the main module that contains the PluginFunctions of this Plugin
///
///
public Type MainModule { get; private set; }
///
/// Load a new Plugin and its PluginFunctions.
///
///
/// If true, all MainMethods of a Plugin will be called as soon as a Plugin is loaded.
/// The name of the type where to search for Methods when loading a new Plugin.
public Plugin(string filePath, bool autoCallMainFunction, string entryTypeName)
{
Assembly = Assembly.LoadFile(filePath);
MainModule = Assembly.GetType(entryTypeName);
if (MainModule is null)
{
throw new PluginLoadException("Plugin Modul not found!");
}
// Define the attribute types to observe
var entryMethodType = typeof(LoadMethodAttribute);
var implementMethodType = typeof(PluginFunctionAttribute);
// Create the lists
var mainMethods = new List();
var implementMethods = new List();
// Search for PluginFunctions
foreach (MethodInfo mi in MainModule.GetMethods())
{
bool found = false;
// Check if the method has one of the defined attributes
foreach (Attribute attr in Attribute.GetCustomAttributes(mi))
{
if (!found)
{
var t = attr.GetType();
switch (t)
{
case var @case when @case == entryMethodType:
{
mainMethods.Add(new PluginFunction(mi, this));
break;
}
case var case1 when case1 == implementMethodType:
{
{
var withBlock = (PluginFunctionAttribute)attr;
implementMethods.Add(new PluginFunction(mi, this, withBlock.Params, withBlock.FunctionCode));
}
break;
}
}
found = true;
}
}
}
// Set the collections
MainFunctions = mainMethods;
PluginFunctions = implementMethods;
// Call all PluginFunctions in MainFunctions
if (autoCallMainFunction)
{
foreach (PluginFunction func in mainMethods)
{
var @params = func.Method.GetParameters();
if (@params.Length == 1)
{
string startupExe = Assembly.GetEntryAssembly().Location;
var args = new[] { startupExe, filePath };
func.Invoke(new[] { args });
}
else if (!@params.Any())
{
func.Invoke();
}
}
}
}
///
/// Get all PluginFunctions that have one of the given function codes.
///
///
///
public IEnumerable GetFunctions(params string[] funcCodes)
{
var funcs = new List();
foreach (PluginFunction func in PluginFunctions)
{
if (funcCodes.Contains(func.FunctionCode))
{
funcs.Add(func);
}
}
return funcs;
}
///
/// Get the first PluginFunction that have the one of the given function codes.
///
///
public PluginFunction GetFunction(params string[] funcCodes)
{
PluginFunction f = null;
foreach (PluginFunction func in PluginFunctions)
{
if (f is null && funcCodes.Contains(func.FunctionCode))
{
f = func;
}
}
return f;
}
}
}