using System.Collections.Generic;
using System.Linq;
using OmiLAXR.Composers;
using OmiLAXR.Composers.HigherComposers;
using OmiLAXR.Endpoints;
using OmiLAXR.Hooks;
using UnityEngine;
namespace OmiLAXR
{
///
/// Core component that manages data flow through the OmiLAXR pipeline system.
/// Serves as a central hub for composers, hooks, and endpoints.
/// Executes early in Unity's order to ensure data is available for other components.
///
[AddComponentMenu("OmiLAXR / Core / Data Provider")]
[DefaultExecutionOrder(-1)]
public class DataProvider : PipelineComponent
{
///
/// Collection of composers that generate statements/data for the pipeline.
///
public readonly List Composers = new List();
///
/// Collection of higher-level composers that process and aggregate statements
/// from regular composers to create more complex data structures.
///
public readonly List> HigherComposers =
new List>();
///
/// Collection of hooks that can intercept and modify statements as they flow through the pipeline.
///
public readonly List Hooks = new List();
///
/// Collection of endpoints that receive and process the final statements,
/// often responsible for data persistence, transmission, or visualization.
///
public readonly List Endpoints = new List();
///
/// Extensions that can add functionality to the DataProvider without modifying its core implementation.
///
public List Extensions = new List();
///
/// Retrieves the first composer of the specified type.
///
/// Type of composer to retrieve
/// The first composer of the specified type, or null if none exists
public T GetComposer() where T : IComposer
=> Composers.OfType().FirstOrDefault();
private bool _isInit = false;
///
/// Initializes the DataProvider by discovering and registering all available
/// composers, higher composers, hooks, and endpoints in its children.
/// Sets up event subscriptions for processing statements.
///
private void OnEnable()
{
if (_isInit)
return;
// Find available composers
var composers = GetComponentsInChildren(true);
Composers.AddRange(composers);
// Find available higher composers
HigherComposers.AddRange(Composers.Where(c => c.IsHigherComposer)
.Select(c => c as HigherComposer));
// Find available hooks
Hooks.AddRange(GetComponentsInChildren(true));
// Find available data endpoints
Endpoints.AddRange(GetComponentsInChildren(true));
// Subscribe to each composer's AfterComposed event to process statements
foreach (var composer in Composers)
{
composer.AfterComposed += HandleStatement;
}
_isInit = true;
}
private void OnDisable()
{
Cleanup();
}
private void Cleanup()
{
if (!_isInit)
return;
foreach (var composer in Composers)
{
composer.AfterComposed -= HandleStatement;
}
Composers.Clear();
Endpoints.Clear();
HigherComposers.Clear();
Hooks.Clear();
_isInit = false;
}
///
/// Processes statements from composers through the pipeline flow:
/// 1. Provides statements to higher composers for potential aggregation
/// 2. Passes statements through all active hooks for modification/filtering
/// 3. Distributes statements to all registered endpoints
///
/// The composer that generated the statement
/// The data/statement to be processed
/// Whether to send the statement immediately or queue it
private void HandleStatement(IComposer sender, IStatement statement)
{
// First, allow higher composers to examine and potentially aggregate the statement
foreach (var composer in HigherComposers)
{
if (!composer.enabled)
continue;
composer.LookFor(statement);
}
// Then, pass through hooks for potential modification or filtering
foreach (var hook in Hooks)
{
if (!hook.enabled)
continue;
statement = hook.AfterCompose(statement);
if (statement.IsDiscarded())
return; // Statement was marked to be discarded by a hook
}
// Finally, distribute to all endpoints
foreach (var dp in Endpoints)
{
if (!dp.enabled)
continue;
dp.SendStatement(statement);
}
}
///
/// Static helper to find the DataProvider instance in the scene.
///
/// The first available DataProvider
public static DataProvider GetAll() => FindObject();
}
}