Imports System.IO

Public Class PluginManager

    ''' <summary>
    ''' Gets or sets an indicator if an exception should throw on error while loading a plugin.
    ''' </summary>
    ''' <returns></returns>
    Public Property ThrowOnError As Boolean = False

    ''' <summary>
    ''' The name of the type where to search for Methods when loading a new Plugin.
    ''' </summary>
    ''' <returns></returns>
    Public Property EntryTypeName As String = "Plugin"

    ''' <summary>
    ''' If true, all MainMethods of a Plugin will be called as soon as a Plugin is loaded.
    ''' </summary>
    ''' <returns></returns>
    Public Property AutoCallMainFunctions As Boolean = True

    ''' <summary>
    ''' A collection of all loaded Plugins.
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property Plugins As New Dictionary(Of String, Plugin)

    ''' <summary>
    ''' Loads Plugins that can be found at the given path and adds them to the Plugins-List.
    ''' </summary>
    ''' <param name="pluginPath">The path where to search for Plugins to load.</param>
    Public Function LoadPlugins(pluginPath As String) As IEnumerable(Of Plugin)
        Return LoadPlugins(pluginPath, True)
    End Function

    ''' <summary>
    ''' Loads Plugins that can be found at the given path and adds them to the Plugins-List.
    ''' </summary>
    ''' <param name="pluginPath">The path where to search for Plugins to load.</param>
    ''' <param name="addToList">If true, the Plugins will be added to Plugins-List after loading.</param>
    Public Function LoadPlugins(pluginPath As String, addToList As Boolean) As IEnumerable(Of Plugin)
        Return LoadPlugins(pluginPath, addToList, AutoCallMainFunctions, EntryTypeName)
    End Function

    ''' <summary>
    ''' Loads Plugins that can be found at the given path and adds them to the Plugins-List.
    ''' </summary>
    ''' <param name="pluginPath">The path where to search for Plugins to load.</param>
    ''' <param name="addToList">If true, the Plugins will be added to Plugins-List after loading.</param>
    ''' <param name="autoCallMainFunction">If true, all MainMethods of a Plugin will be called as soon as a Plugin is loaded.</param>
    ''' <param name="entryTypeName">The name of the type where to search for Methods when loading a new Plugin.</param>
    Public Function LoadPlugins(pluginPath As String, addToList As Boolean, autoCallMainFunction As Boolean, entryTypeName As String) As IEnumerable(Of Plugin)
        Dim loaded As New List(Of Plugin)

        For Each f As String In Directory.GetFiles(pluginPath, "*.dll", SearchOption.AllDirectories)
            Dim p As Plugin = LoadPlugin(f, addToList)
            If p IsNot Nothing Then
                loaded.Add(p)
            End If
        Next

        Return loaded
    End Function

    ''' <summary>
    ''' Loads a Plugin and adds it to the Plugins-List.
    ''' </summary>
    ''' <param name="filePath">The path to the plugin to load.</param>
    ''' <param name="addToList">If true, the Plugin will be added to Plugins-List after loading.</param>
    Public Function LoadPlugin(filePath As String, addToList As Boolean) As Plugin
        Return LoadPlugin(filePath, addToList, AutoCallMainFunctions, EntryTypeName)
    End Function

    ''' <summary>
    ''' Loads a Plugin and adds it to the Plugins-List.
    ''' </summary>
    ''' <param name="filePath">The path to the plugin to load.</param>
    ''' <param name="addToList">If true, the Plugin will be added to Plugins-List after loading.</param>
    ''' <param name="autoCallMainFunction">If true, all MainMethods of a Plugin will be called as soon as a Plugin is loaded.</param>
    ''' <param name="entryTypeName">The name of the type where to search for Methods when loading a new Plugin.</param>
    Public Function LoadPlugin(filePath As String, addToList As Boolean, autoCallMainFunction As Boolean, entryTypeName As String) As Plugin
        Try
            Dim plugin As New Plugin(filePath, autoCallMainFunction, entryTypeName)
            If addToList Then Plugins.Add(filePath, plugin)
            Return plugin
        Catch ex As Exception
            If ThrowOnError Then
                Throw
            Else
                Return Nothing
            End If
        End Try
    End Function

    ''' <summary>
    ''' Loads a Plugin and adds it to the Plugins-List.
    ''' </summary>
    ''' <param name="filePath">The path to the plugin to load.</param>
    Public Function LoadPlugin(filePath As String) As Plugin
        Return LoadPlugin(filePath, True)
    End Function

    ''' <summary>
    ''' Get all PluginFunctions that have one of the given function codes.
    ''' </summary>
    ''' <param name="funcCodes"></param>
    ''' <returns></returns>
    Public Function GetFunctions(ParamArray funcCodes As String()) As IEnumerable(Of PluginFunction)
        Dim list As New List(Of PluginFunction)

        For Each kvp In Plugins
            list.AddRange(kvp.Value.GetFunctions(funcCodes))
        Next

        Return list
    End Function

    ''' <summary>
    ''' Get the first PluginFunction that have the one of the given function codes.
    ''' </summary>
    ''' <returns></returns>
    Public Function GetFunction(ParamArray funcCodes As String()) As PluginFunction
        Dim f As PluginFunction = Nothing

        For Each kvp In Plugins
            If f Is Nothing Then
                For Each func As PluginFunction In kvp.Value.GetFunctions(funcCodes)
                    If f Is Nothing Then
                        f = func
                    End If
                Next
            End If
        Next

        Return f
    End Function

End Class
