using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
namespace Discord.Interactions
{
///
/// Represents a cached object initialization delegate.
///
/// Property arguments array.
///
/// Returns the constructed object.
///
public delegate IModal ModalInitializer(object[] args);
///
/// Represents the info class of an form.
///
public class ModalInfo
{
internal readonly InteractionService _interactionService;
internal readonly ModalInitializer _initializer;
///
/// Gets the title of this modal.
///
public string Title { get; }
///
/// Gets the implementation used to initialize this object.
///
public Type Type { get; }
///
/// Gets a collection of the components of this modal.
///
public IReadOnlyCollection Components { get; }
///
/// Gets a collection of the text components of this modal.
///
public IReadOnlyCollection TextComponents { get; }
internal ModalInfo(Builders.ModalBuilder builder)
{
Title = builder.Title;
Type = builder.Type;
Components = builder.Components.Select(x => x switch
{
Builders.TextInputComponentBuilder textComponent => textComponent.Build(this),
_ => throw new InvalidOperationException($"{x.GetType().FullName} isn't a supported modal input component builder type.")
}).ToImmutableArray();
TextComponents = Components.OfType().ToImmutableArray();
_interactionService = builder._interactionService;
_initializer = builder.ModalInitializer;
}
///
/// Creates an and fills it with provided message components.
///
/// that will be injected into the modal.
///
/// A filled with the provided components.
///
[Obsolete("This method is no longer supported with the introduction of Component TypeConverters, please use the CreateModalAsync method.")]
public IModal CreateModal(IModalInteraction modalInteraction, bool throwOnMissingField = false)
{
var args = new object[Components.Count];
var components = modalInteraction.Data.Components.ToList();
for (var i = 0; i < Components.Count; i++)
{
var input = Components.ElementAt(i);
var component = components.Find(x => x.CustomId == input.CustomId);
if (component is null)
{
if (!throwOnMissingField)
args[i] = input.DefaultValue;
else
throw new InvalidOperationException($"Modal interaction is missing the required field: {input.CustomId}");
}
else
args[i] = component.Value;
}
return _initializer(args);
}
///
/// Creates an and fills it with provided message components.
///
/// Context of the that will be injected into the modal.
/// Services to be passed onto the s of the modal fiels.
/// Wheter or not this method should exit on encountering a missing modal field.
///
/// A if a type conversion has failed, else a .
///
public async Task CreateModalAsync(IInteractionContext context, IServiceProvider services = null, bool throwOnMissingField = false)
{
if (context.Interaction is not IModalInteraction modalInteraction)
return TypeConverterResult.FromError(InteractionCommandError.Unsuccessful, "Provided context doesn't belong to a Modal Interaction.");
services ??= EmptyServiceProvider.Instance;
var args = new object[Components.Count];
var components = modalInteraction.Data.Components.ToList();
for (var i = 0; i < Components.Count; i++)
{
var input = Components.ElementAt(i);
var component = components.Find(x => x.CustomId == input.CustomId);
if (component is null)
{
if (!throwOnMissingField)
args[i] = input.DefaultValue;
else
return TypeConverterResult.FromError(InteractionCommandError.BadArgs, $"Modal interaction is missing the required field: {input.CustomId}");
}
else
{
var readResult = await input.TypeConverter.ReadAsync(context, component, services).ConfigureAwait(false);
if (!readResult.IsSuccess)
return readResult;
args[i] = readResult.Value;
}
}
return TypeConverterResult.FromSuccess(_initializer(args));
}
}
}