using Firebird2D.Datatypes; using Firebird2D.Interfaces; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Firebird2D.EventPipelines { /// /// EventBus manages event pipelines and allows registering callbacks (hooks) if a pipeline is not Build Yet, as well as creating, retrieving, and destroying pipelines. /// public class EventBus : IEventBus { // Dictionary that stores various pipelines for specific FirebirdEvents. // The key is the event, and the value is the corresponding pipeline. private Dictionary pipelines = new(); // Dictionary that stores a list of callbacks for each FirebirdEvent. // These callbacks will be invoked when the event's pipeline is build. private Dictionary>> pendingHooks = new(); /// /// Registers a callback (hook) for a specific event. The callback will be invoked when the pipeline for this event is built. /// /// The function to be called when the pipeline for the event is built. /// The event for which the callback should be registered. /// Thrown when the callback is null. public void OnPipelineIsBuild(Action callback, FirebirdEvent type) { if (callback == null) throw new ArgumentNullException(nameof(callback)); if (!pendingHooks.TryGetValue(type, out var hookList)) { hookList = new(); pendingHooks[type] = hookList; } hookList.Add(callback); } /// /// Attempts to create or retrieve a pipeline for the given event. /// If the pipeline already exists, it is returned. /// Otherwise, a new pipeline is created and stored. /// /// The event for which the pipeline should be created or retrieved. /// The type of the arguments to be passed to the pipeline. /// The master object used when creating the pipeline. /// The pipeline for the given event. public IPipeline GetOrBuildPipeline(FirebirdEvent type, Type argsType, object master) { if (pipelines.TryGetValue(type, out var pipeline)) return pipeline; var genericPipelineType = typeof(Pipeline<>).MakeGenericType(argsType); var pipelineInstance = (IPipeline)Activator.CreateInstance(genericPipelineType, master)!; pipelines[type] = pipelineInstance; return pipelineInstance; } /// /// Retrieves the pipeline for an event if it exists; otherwise, returns null. /// /// The event for which the pipeline should be retrieved. /// The type of the arguments for the pipeline. /// The pipeline for the event, or null if it does not exist. public IPipeline? GetPipeline(FirebirdEvent type, Type argsType) { if (!pipelines.TryGetValue(type, out var pipeline)) return null; return pipeline; } /// /// Destroys the pipeline for an event. Only the "master" of the pipeline is allowed to destroy it. /// /// The event for which the pipeline should be destroyed. /// The master object that has permission to destroy the pipeline. /// Thrown when a non-authorized user attempts to destroy the pipeline. public void DestroyPipeline(FirebirdEvent type, object master) { if (!pipelines.ContainsKey(type)) return; if (!pipelines[type].PipelineMaster.Equals(master)) throw new InvalidDataException("Only the pipeline master is allowed to delete this pipeline."); pipelines.Remove(type); } } }