// 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.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using OwlCore;
using OwlCore.Events;
using OwlCore.Remoting;
using StrixMusic.Sdk.CoreModels;
using StrixMusic.Sdk.MediaPlayback;
namespace StrixMusic.Sdk.Plugins.CoreRemote
{
///
/// Wraps around an instance of an to enable controlling it remotely, or takes a remotingId to control another instance remotely.
///
public sealed class RemoteCoreAlbum : ICoreAlbum
{
private readonly MemberRemote _memberRemote;
private readonly ICoreAlbum? _album;
private int _totalArtistItemsCount;
private int _totalTrackCount;
private int _totalImageCount;
private int _totalUrlCount;
private int _totalGenreCount;
private string _name;
private string? _description;
private PlaybackState _playbackState;
private TimeSpan _duration;
private DateTime? _lastPlayed;
private DateTime? _datePublished;
private bool _isChangeDurationAsyncAvailable;
private bool _isChangeDescriptionAsyncAvailable;
private bool _isChangeNameAsyncAvailable;
private bool _isPauseTrackCollectionAsyncAvailable;
private bool _isPlayTrackCollectionAsyncAvailable;
private bool _isPauseArtistCollectionAsyncAvailable;
private bool _isPlayArtistCollectionAsyncAvailable;
private bool _isChangeDatePublishedAsyncAvailable;
private SemaphoreSlim _getTracksMutex = new SemaphoreSlim(1, 1);
private SemaphoreSlim _getArtistsMutex = new SemaphoreSlim(1, 1);
private SemaphoreSlim _getImagesMutex = new SemaphoreSlim(1, 1);
private SemaphoreSlim _getUrlsMutex = new SemaphoreSlim(1, 1);
private SemaphoreSlim _getGenresMutex = new SemaphoreSlim(1, 1);
///
/// Creates a new instance of .
///
/// The instance ID of the core that created this object.
/// A unique identifier for this instance.
/// The name of the data.
[JsonConstructor]
internal RemoteCoreAlbum(string sourceCoreInstanceId, string name, string id)
{
_name = name;
Id = id;
SourceCoreInstanceId = sourceCoreInstanceId;
// Properties assigned before MemberRemote is created won't be set remotely.
SourceCore = RemoteCore.GetInstance(sourceCoreInstanceId, RemotingMode.Client); // should be set remotely by the ctor.
_memberRemote = new MemberRemote(this, $"{sourceCoreInstanceId}.{nameof(RemoteCoreAlbum)}.{id}", RemoteCoreMessageHandler.SingletonClient);
}
///
/// Wraps around and remotely relays events, property changes and method calls (with return data) from an album instance.
///
///
internal RemoteCoreAlbum(ICoreAlbum coreAlbum)
{
_album = coreAlbum;
_name = coreAlbum.Name;
Id = coreAlbum.Id;
SourceCoreInstanceId = coreAlbum.SourceCore.InstanceId;
SourceCore = RemoteCore.GetInstance(SourceCoreInstanceId, RemotingMode.Host);
_memberRemote = new MemberRemote(this, $"{coreAlbum.SourceCore.InstanceId}.{nameof(RemoteCoreAlbum)}.{coreAlbum.Id}", RemoteCoreMessageHandler.SingletonHost);
}
[RemoteMethod]
private void OnTracksChanged(IReadOnlyList> addedItems, IReadOnlyList> removedItems)
{
TracksChanged?.Invoke(this, addedItems, removedItems);
}
[RemoteMethod]
private void OnArtistItemsChanged(IReadOnlyList> addedItems, IReadOnlyList> removedItems)
{
ArtistItemsChanged?.Invoke(this, addedItems, removedItems);
}
[RemoteMethod]
private void OnImagesChanged(IReadOnlyList> addedItems, IReadOnlyList> removedItems)
{
ImagesChanged?.Invoke(this, addedItems, removedItems);
}
[RemoteMethod]
private void OnUrlsChanged(IReadOnlyList> addedItems, IReadOnlyList> removedItems)
{
UrlsChanged?.Invoke(this, addedItems, removedItems);
}
[RemoteMethod]
private void OnGenresChanged(IReadOnlyList> addedItems, IReadOnlyList> removedItems)
{
GenresChanged?.Invoke(this, addedItems, removedItems);
}
///
public event EventHandler? PlaybackStateChanged;
///
public event EventHandler? NameChanged;
///
public event EventHandler? DescriptionChanged;
///
public event EventHandler? DurationChanged;
///
public event EventHandler? LastPlayedChanged;
///
public event EventHandler? IsPlayArtistCollectionAsyncAvailableChanged;
///
public event EventHandler? IsPauseArtistCollectionAsyncAvailableChanged;
///
public event EventHandler? IsPlayTrackCollectionAsyncAvailableChanged;
///
public event EventHandler? IsPauseTrackCollectionAsyncAvailableChanged;
///
public event EventHandler? IsChangeNameAsyncAvailableChanged;
///
public event EventHandler? IsChangeDescriptionAsyncAvailableChanged;
///
public event EventHandler? IsChangeDurationAsyncAvailableChanged;
///
public event EventHandler? IsChangeDatePublishedAsyncAvailableChanged;
///
public event EventHandler? ArtistItemsCountChanged;
///
public event EventHandler? TracksCountChanged;
///
public event EventHandler? GenresCountChanged;
///
public event EventHandler? ImagesCountChanged;
///
public event EventHandler? UrlsCountChanged;
///
public event CollectionChangedEventHandler? TracksChanged;
///
public event CollectionChangedEventHandler? ArtistItemsChanged;
///
public event CollectionChangedEventHandler? GenresChanged;
///
public event CollectionChangedEventHandler? ImagesChanged;
///
public event CollectionChangedEventHandler? UrlsChanged;
///
public event EventHandler? DatePublishedChanged;
///
public ICore SourceCore { get; set; }
///
/// The instance ID of the
///
public string SourceCoreInstanceId { get; set; }
///
public string Id { get; set; }
///
[RemoteProperty]
public string Name
{
get => _name;
set
{
_name = value;
NameChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public string? Description
{
get => _description;
set
{
_description = value;
DescriptionChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public PlaybackState PlaybackState
{
get => _playbackState;
set
{
_playbackState = value;
PlaybackStateChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public TimeSpan Duration
{
get => _duration;
set
{
_duration = value;
DurationChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public DateTime? LastPlayed
{
get => _lastPlayed;
set
{
_lastPlayed = value;
LastPlayedChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public DateTime? AddedAt { get; set; }
///
[RemoteProperty]
public ICorePlayableCollectionGroup? RelatedItems { get; set; }
///
[RemoteProperty]
public DateTime? DatePublished
{
get => _datePublished;
set
{
_datePublished = value;
DatePublishedChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public int TotalArtistItemsCount
{
get => _totalArtistItemsCount;
set
{
_totalArtistItemsCount = value;
ArtistItemsCountChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public int TotalTrackCount
{
get => _totalTrackCount;
set
{
_totalTrackCount = value;
TracksCountChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public int TotalImageCount
{
get => _totalImageCount;
internal set
{
_totalImageCount = value;
ImagesCountChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public int TotalUrlCount
{
get => _totalUrlCount;
internal set
{
_totalUrlCount = value;
UrlsCountChanged?.Invoke(this, value);
}
}
///
public int TotalGenreCount
{
get => _totalGenreCount;
internal set
{
_totalGenreCount = value;
GenresCountChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public bool IsPlayArtistCollectionAsyncAvailable
{
get => _isPlayArtistCollectionAsyncAvailable;
set
{
_isPlayArtistCollectionAsyncAvailable = value;
IsPlayArtistCollectionAsyncAvailableChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public bool IsPauseArtistCollectionAsyncAvailable
{
get => _isPauseArtistCollectionAsyncAvailable;
set
{
_isPauseArtistCollectionAsyncAvailable = value;
IsPauseArtistCollectionAsyncAvailableChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public bool IsPlayTrackCollectionAsyncAvailable
{
get => _isPlayTrackCollectionAsyncAvailable;
set
{
_isPlayTrackCollectionAsyncAvailable = value;
IsPlayTrackCollectionAsyncAvailableChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public bool IsPauseTrackCollectionAsyncAvailable
{
get => _isPauseTrackCollectionAsyncAvailable;
set
{
_isPauseTrackCollectionAsyncAvailable = value;
IsPauseTrackCollectionAsyncAvailableChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public bool IsChangeNameAsyncAvailable
{
get => _isChangeNameAsyncAvailable;
set
{
_isChangeNameAsyncAvailable = value;
IsChangeNameAsyncAvailableChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public bool IsChangeDescriptionAsyncAvailable
{
get => _isChangeDescriptionAsyncAvailable;
set
{
_isChangeDescriptionAsyncAvailable = value;
IsChangeDescriptionAsyncAvailableChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public bool IsChangeDurationAsyncAvailable
{
get => _isChangeDurationAsyncAvailable;
set
{
_isChangeDurationAsyncAvailable = value;
IsChangeDurationAsyncAvailableChanged?.Invoke(this, value);
}
}
///
[RemoteProperty]
public bool IsChangeDatePublishedAsyncAvailable
{
get => _isChangeDatePublishedAsyncAvailable;
set
{
_isChangeDatePublishedAsyncAvailable = value;
IsChangeDatePublishedAsyncAvailableChanged?.Invoke(this, value);
}
}
///
[RemoteMethod]
public Task IsAddTrackAvailableAsync(int index, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync(nameof(IsAddTrackAvailableAsync));
///
[RemoteMethod]
public Task IsAddArtistItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync(nameof(IsAddArtistItemAvailableAsync));
///
[RemoteMethod]
public Task IsAddImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync(nameof(IsAddImageAvailableAsync));
///
[RemoteMethod]
public Task IsAddUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync(nameof(IsAddUrlAvailableAsync));
///
[RemoteMethod]
public Task IsRemoveTrackAvailableAsync(int index, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync(nameof(IsRemoveTrackAvailableAsync));
///
[RemoteMethod]
public Task IsRemoveImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync(nameof(IsRemoveImageAvailableAsync));
///
[RemoteMethod]
public Task IsRemoveUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync(nameof(IsRemoveUrlAvailableAsync));
///
[RemoteMethod]
public Task IsRemoveArtistItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync(nameof(IsRemoveArtistItemAvailableAsync));
///
[RemoteMethod]
public Task IsAddGenreAvailableAsync(int index, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync(nameof(IsAddGenreAvailableAsync));
///
[RemoteMethod]
public Task IsRemoveGenreAvailableAsync(int index, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync(nameof(IsRemoveGenreAvailableAsync));
///
[RemoteMethod]
public Task ChangeDescriptionAsync(string? description, CancellationToken cancellationToken = default) => _memberRemote.ReceiveDataAsync