using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using Artemis.Storage.Entities.Plugins;
using McMaster.NETCore.Plugins;
using Ninject;
namespace Artemis.Core
{
///
/// Represents a plugin
///
public class Plugin : CorePropertyChanged, IDisposable
{
private readonly List _features;
private bool _isEnabled;
internal Plugin(PluginInfo info, DirectoryInfo directory)
{
Info = info;
Directory = directory;
_features = new List();
}
///
/// Gets the plugin GUID
///
public Guid Guid => Info.Guid;
///
/// Gets the plugin info related to this plugin
///
public PluginInfo Info { get; }
///
/// The plugins root directory
///
public DirectoryInfo Directory { get; }
///
/// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins
///
public IPluginConfigurationDialog? ConfigurationDialog { get; set; }
///
/// Indicates whether the user enabled the plugin or not
///
public bool IsEnabled
{
get => _isEnabled;
private set => SetAndNotify(ref _isEnabled, value);
}
///
/// Gets a read-only collection of all features this plugin provides
///
public ReadOnlyCollection Features => _features.AsReadOnly();
///
/// The assembly the plugin code lives in
///
public Assembly? Assembly { get; internal set; }
///
/// Gets the plugin bootstrapper
///
public IPluginBootstrapper? Bootstrapper { get; internal set; }
///
/// The Ninject kernel of the plugin
///
public IKernel? Kernel { get; internal set; }
///
/// The PluginLoader backing this plugin
///
internal PluginLoader? PluginLoader { get; set; }
///
/// The entity representing the plugin
///
internal PluginEntity Entity { get; set; }
///
/// Resolves the relative path provided in the parameter to an absolute path
///
/// The path to resolve
/// An absolute path pointing to the provided relative path
public string? ResolveRelativePath(string path)
{
return path == null ? null : Path.Combine(Directory.FullName, path);
}
///
/// Looks up the instance of the feature of type
/// Note: This method only returns instances of enabled features
///
/// The type of feature to find
/// If found, the instance of the feature
public T? GetFeature() where T : PluginFeature
{
return _features.FirstOrDefault(i => i is T) as T;
}
///
public override string ToString()
{
return Info.ToString();
}
internal void ApplyToEntity()
{
Entity.Id = Guid;
Entity.IsEnabled = IsEnabled;
}
internal void AddFeature(PluginFeature feature)
{
feature.Plugin = this;
_features.Add(feature);
OnFeatureAdded(new PluginFeatureEventArgs(feature));
}
internal void RemoveFeature(PluginFeature feature)
{
if (feature.IsEnabled)
throw new ArtemisCoreException("Cannot remove an enabled feature from a plugin");
_features.Remove(feature);
feature.Dispose();
OnFeatureRemoved(new PluginFeatureEventArgs(feature));
}
internal void SetEnabled(bool enable)
{
if (IsEnabled == enable)
return;
if (!enable && Features.Any(e => e.IsEnabled))
throw new ArtemisCoreException("Cannot disable this plugin because it still has enabled features");
IsEnabled = enable;
if (enable)
{
Bootstrapper?.Enable(this);
OnEnabled();
}
else
{
Bootstrapper?.Disable(this);
OnDisabled();
}
}
public void Dispose()
{
foreach (PluginFeature feature in Features)
feature.Dispose();
Kernel?.Dispose();
PluginLoader?.Dispose();
_features.Clear();
SetEnabled(false);
}
#region Events
///
/// Occurs when the plugin is enabled
///
public event EventHandler? Enabled;
///
/// Occurs when the plugin is disabled
///
public event EventHandler? Disabled;
///
/// Occurs when an feature is loaded and added to the plugin
///
public event EventHandler? FeatureAdded;
///
/// Occurs when an feature is disabled and removed from the plugin
///
public event EventHandler? FeatureRemoved;
///
/// Invokes the Enabled event
///
protected virtual void OnEnabled()
{
Enabled?.Invoke(this, EventArgs.Empty);
}
///
/// Invokes the Disabled event
///
protected virtual void OnDisabled()
{
Disabled?.Invoke(this, EventArgs.Empty);
}
///
/// Invokes the FeatureAdded event
///
protected virtual void OnFeatureAdded(PluginFeatureEventArgs e)
{
FeatureAdded?.Invoke(this, e);
}
///
/// Invokes the FeatureRemoved event
///
protected virtual void OnFeatureRemoved(PluginFeatureEventArgs e)
{
FeatureRemoved?.Invoke(this, e);
}
#endregion
}
}