// Copyright (c) Arlo Godfrey. All Rights Reserved.
// Licensed under the GNU Lesser General Public License, Version 3.0 with additional terms.
// See the LICENSE, LICENSE.LESSER and LICENSE.ADDITIONAL files in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Diagnostics;
using OwlCore.Events;
using StrixMusic.Sdk.AdapterModels;
using StrixMusic.Sdk.AppModels;
using StrixMusic.Sdk.CoreModels;
using StrixMusic.Sdk.MediaPlayback;
using StrixMusic.Sdk.Plugins.Model;
namespace StrixMusic.Sdk.PluginModels;
///
/// Wraps an instance of with the provided plugins.
///
public class PlaylistCollectionPluginWrapper : IPlaylistCollection, IPluginWrapper
{
private readonly IPlaylistCollection _playlistCollection;
private readonly SdkModelPlugin[] _plugins;
///
/// Initializes a new instance of the class.
///
/// The instance to wrap around and apply plugins to.
/// The plugins that are applied to items returned from or emitted by this collection.
internal PlaylistCollectionPluginWrapper(IPlaylistCollection playlistCollection, params SdkModelPlugin[] plugins)
{
foreach (var item in plugins)
ActivePlugins.Import(item);
ActivePlugins = GlobalModelPluginConnector.Create(ActivePlugins);
_playlistCollection = ActivePlugins.PlaylistCollection.Execute(playlistCollection);
_plugins = plugins;
AttachEvents(_playlistCollection);
}
///
public SdkModelPlugin ActivePlugins { get; } = new(PluginModelWrapperInfo.Metadata);
private void AttachEvents(IPlaylistCollection playlistCollection)
{
playlistCollection.SourcesChanged += OnSourcesChanged;
playlistCollection.ImagesCountChanged += OnImagesCountChanged;
playlistCollection.UrlsCountChanged += OnUrlsCountChanged;
playlistCollection.PlaybackStateChanged += OnPlaybackStateChanged;
playlistCollection.NameChanged += OnNameChanged;
playlistCollection.DescriptionChanged += OnDescriptionChanged;
playlistCollection.DurationChanged += OnDurationChanged;
playlistCollection.LastPlayedChanged += OnLastPlayedChanged;
playlistCollection.IsChangeNameAsyncAvailableChanged += OnIsChangeNameAsyncAvailableChanged;
playlistCollection.IsChangeDescriptionAsyncAvailableChanged += OnIsChangeDescriptionAsyncAvailableChanged;
playlistCollection.IsChangeDurationAsyncAvailableChanged += OnIsChangeDurationAsyncAvailableChanged;
playlistCollection.IsPlayPlaylistCollectionAsyncAvailableChanged += OnIsPlayPlaylistCollectionAsyncAvailableChanged;
playlistCollection.IsPausePlaylistCollectionAsyncAvailableChanged += OnIsPausePlaylistCollectionAsyncAvailableChanged;
playlistCollection.PlaylistItemsCountChanged += OnPlaylistItemsCountChanged;
playlistCollection.ImagesChanged += OnImagesChanged;
playlistCollection.UrlsChanged += OnUrlsChanged;
playlistCollection.DownloadInfoChanged += OnDownloadInfoChanged;
playlistCollection.PlaylistItemsChanged += OnPlaylistItemsChanged;
}
private void DetachEvents(IPlaylistCollection playlistCollection)
{
playlistCollection.SourcesChanged -= OnSourcesChanged;
playlistCollection.ImagesCountChanged -= OnImagesCountChanged;
playlistCollection.UrlsCountChanged -= OnUrlsCountChanged;
playlistCollection.PlaybackStateChanged -= OnPlaybackStateChanged;
playlistCollection.NameChanged -= OnNameChanged;
playlistCollection.DescriptionChanged -= OnDescriptionChanged;
playlistCollection.DurationChanged -= OnDurationChanged;
playlistCollection.LastPlayedChanged -= OnLastPlayedChanged;
playlistCollection.IsChangeNameAsyncAvailableChanged -= OnIsChangeNameAsyncAvailableChanged;
playlistCollection.IsChangeDescriptionAsyncAvailableChanged -= OnIsChangeDescriptionAsyncAvailableChanged;
playlistCollection.IsChangeDurationAsyncAvailableChanged -= OnIsChangeDurationAsyncAvailableChanged;
playlistCollection.IsPlayPlaylistCollectionAsyncAvailableChanged -= OnIsPlayPlaylistCollectionAsyncAvailableChanged;
playlistCollection.IsPausePlaylistCollectionAsyncAvailableChanged -= OnIsPausePlaylistCollectionAsyncAvailableChanged;
playlistCollection.PlaylistItemsCountChanged -= OnPlaylistItemsCountChanged;
playlistCollection.ImagesChanged -= OnImagesChanged;
playlistCollection.UrlsChanged -= OnUrlsChanged;
playlistCollection.DownloadInfoChanged -= OnDownloadInfoChanged;
playlistCollection.PlaylistItemsChanged -= OnPlaylistItemsChanged;
}
private void OnSourcesChanged(object sender, EventArgs e) => SourcesChanged?.Invoke(sender, e);
private void OnPlaylistItemsChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems)
{
var wrappedAdded = addedItems.Select(x => new CollectionChangedItem(Transform(x.Data), x.Index)).ToList();
var wrappedRemoved = removedItems.Select(x => new CollectionChangedItem(Transform(x.Data), x.Index)).ToList();
PlaylistItemsChanged?.Invoke(sender, wrappedAdded, wrappedRemoved);
}
private void OnUrlsChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems)
{
var wrappedAdded = addedItems.Select(x => new CollectionChangedItem(new UrlPluginWrapper(x.Data, _plugins), x.Index)).ToList();
var wrappedRemoved = removedItems.Select(x => new CollectionChangedItem(new UrlPluginWrapper(x.Data, _plugins), x.Index)).ToList();
UrlsChanged?.Invoke(sender, wrappedAdded, wrappedRemoved);
}
private void OnImagesChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems)
{
var wrappedAdded = addedItems.Select(x => new CollectionChangedItem(new ImagePluginWrapper(x.Data, _plugins), x.Index)).ToList();
var wrappedRemoved = removedItems.Select(x => new CollectionChangedItem(new ImagePluginWrapper(x.Data, _plugins), x.Index)).ToList();
ImagesChanged?.Invoke(sender, wrappedAdded, wrappedRemoved);
}
private void OnDownloadInfoChanged(object sender, DownloadInfo e) => DownloadInfoChanged?.Invoke(sender, e);
private void OnPlaylistItemsCountChanged(object sender, int e) => PlaylistItemsCountChanged?.Invoke(sender, e);
private void OnIsPausePlaylistCollectionAsyncAvailableChanged(object sender, bool e) => IsPausePlaylistCollectionAsyncAvailableChanged?.Invoke(sender, e);
private void OnIsPlayPlaylistCollectionAsyncAvailableChanged(object sender, bool e) => IsPlayPlaylistCollectionAsyncAvailableChanged?.Invoke(sender, e);
private void OnIsChangeDurationAsyncAvailableChanged(object sender, bool e) => IsChangeDurationAsyncAvailableChanged?.Invoke(sender, e);
private void OnIsChangeDescriptionAsyncAvailableChanged(object sender, bool e) => IsChangeDescriptionAsyncAvailableChanged?.Invoke(sender, e);
private void OnIsChangeNameAsyncAvailableChanged(object sender, bool e) => IsChangeNameAsyncAvailableChanged?.Invoke(sender, e);
private void OnLastPlayedChanged(object sender, DateTime? e) => LastPlayedChanged?.Invoke(sender, e);
private void OnDurationChanged(object sender, TimeSpan e) => DurationChanged?.Invoke(sender, e);
private void OnDescriptionChanged(object sender, string? e) => DescriptionChanged?.Invoke(sender, e);
private void OnNameChanged(object sender, string e) => NameChanged?.Invoke(sender, e);
private void OnPlaybackStateChanged(object sender, PlaybackState e) => PlaybackStateChanged?.Invoke(sender, e);
private void OnUrlsCountChanged(object sender, int e) => UrlsCountChanged?.Invoke(sender, e);
private void OnImagesCountChanged(object sender, int e) => ImagesCountChanged?.Invoke(sender, e);
///
public event EventHandler? SourcesChanged;
///
public event EventHandler? ImagesCountChanged;
///
public event EventHandler? UrlsCountChanged;
///
public event EventHandler? PlaybackStateChanged;
///
public event EventHandler? NameChanged;
///
public event EventHandler? DescriptionChanged;
///
public event EventHandler? DurationChanged;
///
public event EventHandler? LastPlayedChanged;
///
public event EventHandler? IsChangeNameAsyncAvailableChanged;
///
public event EventHandler? IsChangeDescriptionAsyncAvailableChanged;
///
public event EventHandler? IsChangeDurationAsyncAvailableChanged;
///
public event EventHandler? IsPlayPlaylistCollectionAsyncAvailableChanged;
///
public event EventHandler? IsPausePlaylistCollectionAsyncAvailableChanged;
///
public event EventHandler? PlaylistItemsCountChanged;
///
public event CollectionChangedEventHandler? ImagesChanged;
///
public event CollectionChangedEventHandler? UrlsChanged;
///
public event EventHandler? DownloadInfoChanged;
///
public event CollectionChangedEventHandler? PlaylistItemsChanged;
///
public int TotalImageCount => _playlistCollection.TotalImageCount;
///
public Task IsAddImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsAddImageAvailableAsync(index, cancellationToken);
///
public Task IsRemoveImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsRemoveImageAvailableAsync(index, cancellationToken);
///
public Task RemoveImageAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.RemoveImageAsync(index, cancellationToken);
///
public int TotalUrlCount => _playlistCollection.TotalUrlCount;
///
public Task RemoveUrlAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.RemoveUrlAsync(index, cancellationToken);
///
public Task IsAddUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsAddUrlAvailableAsync(index, cancellationToken);
///
public Task IsRemoveUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsRemoveUrlAvailableAsync(index, cancellationToken);
///
public string Id => _playlistCollection.Id;
///
public string Name => _playlistCollection.Name;
///
public string? Description => _playlistCollection.Description;
///
public DateTime? LastPlayed => _playlistCollection.LastPlayed;
///
public PlaybackState PlaybackState => _playlistCollection.PlaybackState;
///
public TimeSpan Duration => _playlistCollection.Duration;
///
public bool IsChangeNameAsyncAvailable => _playlistCollection.IsChangeNameAsyncAvailable;
///
public bool IsChangeDescriptionAsyncAvailable => _playlistCollection.IsChangeDescriptionAsyncAvailable;
///
public bool IsChangeDurationAsyncAvailable => _playlistCollection.IsChangeDurationAsyncAvailable;
///
public Task ChangeNameAsync(string name, CancellationToken cancellationToken = default) => _playlistCollection.ChangeNameAsync(name, cancellationToken);
///
public Task ChangeDescriptionAsync(string? description, CancellationToken cancellationToken = default) => _playlistCollection.ChangeDescriptionAsync(description, cancellationToken);
///
public Task ChangeDurationAsync(TimeSpan duration, CancellationToken cancellationToken = default) => _playlistCollection.ChangeDurationAsync(duration, cancellationToken);
///
public DateTime? AddedAt => _playlistCollection.AddedAt;
///
public int TotalPlaylistItemsCount => _playlistCollection.TotalPlaylistItemsCount;
///
public bool IsPlayPlaylistCollectionAsyncAvailable => _playlistCollection.IsPlayPlaylistCollectionAsyncAvailable;
///
public bool IsPausePlaylistCollectionAsyncAvailable => _playlistCollection.IsPausePlaylistCollectionAsyncAvailable;
///
public Task RemovePlaylistItemAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.RemovePlaylistItemAsync(index, cancellationToken);
///
public Task IsAddPlaylistItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsAddPlaylistItemAvailableAsync(index, cancellationToken);
///
public Task IsRemovePlaylistItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsRemovePlaylistItemAvailableAsync(index, cancellationToken);
///
public Task PlayPlaylistCollectionAsync(CancellationToken cancellationToken = default) => _playlistCollection.PlayPlaylistCollectionAsync(cancellationToken);
///
public Task PausePlaylistCollectionAsync(CancellationToken cancellationToken = default) => _playlistCollection.PausePlaylistCollectionAsync(cancellationToken);
///
public bool Equals(ICoreImageCollection other) => _playlistCollection.Equals(other);
///
IReadOnlyList IMerged.Sources => ((IMerged)_playlistCollection).Sources;
///
IReadOnlyList IMerged.Sources => ((IMerged)_playlistCollection).Sources;
///
IReadOnlyList IMerged.Sources => ((IMerged)_playlistCollection).Sources;
///
IReadOnlyList IMerged.Sources => ((IMerged)_playlistCollection).Sources;
///
public IAsyncEnumerable GetImagesAsync(int limit, int offset, CancellationToken cancellationToken = default) => _playlistCollection.GetImagesAsync(limit, offset, cancellationToken).Select(x => new ImagePluginWrapper(x, _plugins));
///
public Task AddImageAsync(IImage image, int index, CancellationToken cancellationToken = default) => _playlistCollection.AddImageAsync(image, index, cancellationToken);
///
public bool Equals(ICoreUrlCollection other) => _playlistCollection.Equals(other);
///
public IAsyncEnumerable GetUrlsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _playlistCollection.GetUrlsAsync(limit, offset, cancellationToken).Select(x => new UrlPluginWrapper(x, _plugins));
///
public Task AddUrlAsync(IUrl url, int index, CancellationToken cancellationToken = default) => _playlistCollection.AddUrlAsync(url, index, cancellationToken);
///
public DownloadInfo DownloadInfo => _playlistCollection.DownloadInfo;
///
public Task StartDownloadOperationAsync(DownloadOperation operation, CancellationToken cancellationToken = default) => _playlistCollection.StartDownloadOperationAsync(operation, cancellationToken);
///
public bool Equals(ICorePlaylistCollectionItem other) => _playlistCollection.Equals(other);
///
public Task PlayPlaylistCollectionAsync(IPlaylistCollectionItem playlistItem, CancellationToken cancellationToken = default) => _playlistCollection.PlayPlaylistCollectionAsync(playlistItem, cancellationToken);
///
public IAsyncEnumerable GetPlaylistItemsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _playlistCollection.GetPlaylistItemsAsync(limit, offset, cancellationToken).Select(Transform);
///
public Task AddPlaylistItemAsync(IPlaylistCollectionItem playlistItem, int index, CancellationToken cancellationToken = default) => _playlistCollection.AddPlaylistItemAsync(playlistItem, index, cancellationToken);
///
public bool Equals(ICorePlaylistCollection other) => _playlistCollection.Equals(other);
///
public ValueTask DisposeAsync()
{
DetachEvents(_playlistCollection);
return _playlistCollection.DisposeAsync();
}
private IPlaylistCollectionItem Transform(IPlaylistCollectionItem item) => item switch
{
IPlaylist playlist => new PlaylistPluginWrapper(playlist, _plugins),
IPlaylistCollection playlistCollection => new PlaylistCollectionPluginWrapper(playlistCollection, _plugins),
_ => ThrowHelper.ThrowArgumentOutOfRangeException()
};
}