using System.Collections.ObjectModel;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegrator.Handlers.Components;
using Telegrator.Logging;
using Telegrator.MadiatorCore;
using Telegrator.MadiatorCore.Descriptors;
namespace Telegrator.Providers
{
///
/// Provides handler resolution and instantiation logic for Telegram bot updates.
/// Responsible for mapping update types to handler descriptors, filtering handlers based on update context,
/// and creating handler instances with appropriate lifecycle management.
///
public class HandlersProvider : IHandlersProvider
{
///
public IEnumerable AllowedTypes { get; }
///
/// Read-only dictionary mapping to lists of handler descriptors.
/// Each descriptor list is frozen to prevent modification after initialization.
///
public readonly ReadOnlyDictionary HandlersDictionary;
///
/// Configuration options for the bot and handler execution behavior.
///
protected readonly TelegratorOptions Options;
///
/// Initializes a new instance of with the specified handler collections and configuration.
///
/// Collection of handler descriptor lists organized by update type
/// Configuration options for the bot and handler execution
/// Thrown when options or botInfo is null
public HandlersProvider(IHandlersCollection handlers, TelegratorOptions options)
{
AllowedTypes = handlers.AllowedTypes;
HandlersDictionary = handlers.Values.ForEach(list => list.Freeze()).ToReadOnlyDictionary(list => list.HandlingType);
Options = options ?? throw new ArgumentNullException(nameof(options));
Alligator.LogTrace("{0} created!", GetType().Name);
}
///
/// Initializes a new instance of with the specified handler collections and configuration.
///
/// Collection of handler descriptor lists organized by update type
/// Configuration options for the bot and handler execution
/// Thrown when options or botInfo is null
public HandlersProvider(IEnumerable handlers, TelegratorOptions options)
{
AllowedTypes = Update.AllTypes;
HandlersDictionary = handlers.ForEach(list => list.Freeze()).ToReadOnlyDictionary(list => list.HandlingType);
Options = options ?? throw new ArgumentNullException(nameof(options));
Alligator.LogTrace("{0} created!", GetType().Name);
}
///
/// Thrown when the descriptor type is not recognized
public virtual UpdateHandlerBase GetHandlerInstance(HandlerDescriptor descriptor, CancellationToken cancellationToken = default)
{
try
{
// Checking handler instance status
cancellationToken.ThrowIfCancellationRequested();
bool useSingleton = UseSingleton(descriptor);
// Returning singleton instance
if (useSingleton && descriptor.SingletonInstance != null)
return descriptor.SingletonInstance;
// Creating instance
UpdateHandlerBase instance = GetHandlerInstanceInternal(descriptor);
if (useSingleton)
descriptor.TrySetInstance(instance);
// Lazy initialization execution
descriptor.LazyInitialization?.Invoke(instance);
return instance;
}
catch (Exception ex)
{
Alligator.LogError("Failed to create instance of '{0}'", exception: ex, descriptor.ToString());
throw;
}
}
private static UpdateHandlerBase GetHandlerInstanceInternal(HandlerDescriptor descriptor)
{
if (descriptor.InstanceFactory != null)
return descriptor.InstanceFactory.Invoke();
return (UpdateHandlerBase)Activator.CreateInstance(descriptor.HandlerType);
}
private static bool UseSingleton(HandlerDescriptor descriptor) => descriptor.Type switch
{
DescriptorType.General or DescriptorType.Keyed => false,
DescriptorType.Implicit or DescriptorType.Singleton => true,
_ => throw new Exception("Unknown decriptor type")
};
///
public virtual bool TryGetDescriptorList(UpdateType updateType, out HandlerDescriptorList? list)
{
if (UpdateTypeExtensions.SuppressTypes.TryGetValue(updateType, out UpdateType suppressType))
updateType = suppressType;
return HandlersDictionary.TryGetValue(updateType, out list);
}
///
public virtual bool IsEmpty()
{
return HandlersDictionary.Count == 0;
}
}
}