MyBookmark/Modules.Library.Domain/Entities/MediaContent/Items/Anime/AnimeTitle.cs
2024-09-04 23:08:56 +03:00

177 lines
6.3 KiB
C#

using Modules.Library.Domain.Entities.MediaContent.CommonProperties;
using Modules.Library.Domain.Entities.MediaContent.Items.Anime.ShadowEntities;
namespace Modules.Library.Domain.Entities.MediaContent.Items.Anime;
public class AnimeTitle : Entity
{
public CommonProperties.CommonProperties CommonProperties { get; private set; } = new();
/*
private List<AnimeItem> _items = [];
public IReadOnlyList<AnimeItem> Items => _items.AsReadOnly();
*/
public List<AnimeItem> Items { get; set; } = [];
public bool Completed { get; internal set; }
public TimeSpan ExpirationTime { get; set; }
private AnimeTitle() { }
internal AnimeTitle(string nameOriginal, Guid nameOriginalLanguageId)
{
CommonProperties.Names.Add(new NameItem(nameOriginalLanguageId, NameType.Original, nameOriginal));
}
private AnimeItem ConvertToAnimeItem(AnimeItemShadow shadow)
{
if (shadow is AnimeEpisodeShadow episode) return new AnimeEpisode(this, null, episode);
else if (shadow is AnimeSeasonShadow season) return new AnimeSeason(this, season);
else throw new NotImplementedException();
}
public void AddEpisode(AnimeEpisodeType episodeType)
{
var episode = new AnimeEpisodeShadow
{
type = episodeType,
order = AnimeItem.GetNewOrder(_shadow.items),
number = _shadow.items.OfType<AnimeEpisodeShadow>().Select(q => q.number).DefaultIfEmpty(-1).Max() + 1,
};
_shadow.items.Add(episode);
CheckIsCompleted();
}
public void AddEpisodeAsVariant(AnimeEpisodeType episodeType, ushort order)
{
if (order < 0 || order > _shadow.items.Select(q => q.order).DefaultIfEmpty<ushort>(0).Max())
throw new ArgumentOutOfRangeException(nameof(order));
var episode = new AnimeEpisodeShadow
{
type = episodeType,
order = order,
variant = AnimeItem.GetNewVariant(_shadow.items, order),
number = _shadow.items.OfType<AnimeEpisodeShadow>().FirstOrDefault(q => q.order == order)?.number,
};
_shadow.items.Add(episode);
CheckIsCompleted();
}
public void RemoveEpisode(AnimeEpisode episode)
{
episode.SetDeleted();
AnimeItem.Sort(_shadow.items.Where(q => !q.deleted));
CheckIsCompleted();
}
internal void SetEpisodeOrder(ushort currentOrder, ushort newOrder) =>
AnimeItem.SetItemOrder(_shadow.items, currentOrder, newOrder);
internal void SetEpisodeVariant(ushort order, ushort currentVariant, ushort newVariant) =>
AnimeItem.SetItemVariant(_shadow.items.OfType<AnimeEpisodeShadow>()
.Where(q => q.order == order), currentVariant, newVariant);
internal void SetEpisodeCompleted(ushort order, ushort variant, bool value = true) =>
SetCompleted<AnimeEpisodeShadow>(order, variant, value);
internal void SetEpisodeExpirationTime(ushort order, ushort variant, TimeSpan value) =>
SetExpirationTime<AnimeEpisodeShadow>(order, variant, value);
public void AddSeason()
{
var episode = new AnimeSeasonShadow
{
order = AnimeItem.GetNewOrder(_shadow.items),
number = _shadow.items.OfType<AnimeSeasonShadow>().Select(q => q.number).DefaultIfEmpty(-1).Max() + 1,
};
_shadow.items.Add(episode);
CheckIsCompleted();
}
/*
public void AddSeasonAsVariant(AnimeEpisodeType episodeType, ushort order)
{
if (order < 0 || order > _shadow.items.Select(q => q.order).DefaultIfEmpty<ushort>(0).Max())
throw new ArgumentOutOfRangeException(nameof(order));
var episode = new AnimeEpisodeShadow
{
type = episodeType,
order = order,
variant = AnimeItem.GetNewVariant(_shadow.items, order),
number = _shadow.items.OfType<AnimeEpisodeShadow>().FirstOrDefault(q => q.order == order)?.number,
};
_shadow.items.Add(episode);
CheckIsCompleted();
}
*/
public void RemoveSeason(AnimeSeason season)
{
season.SetDeleted();
AnimeItem.Sort(_shadow.items.Where(q => !q.deleted));
CheckIsCompleted();
}
internal void SetSeasonCompleted(ushort order, ushort variant, bool value = true) =>
SetCompleted<AnimeSeasonShadow>(order, variant, value);
internal void SetSeasonExpirationTime(ushort order, ushort variant, TimeSpan value) =>
SetExpirationTime<AnimeSeasonShadow>(order, variant, value);
private void SetCompleted<T>(ushort order, ushort variant, bool value = true) where T : AnimeItemShadow
{
var item = GetItem<T>(order, variant);
item.completed = value;
CheckIsCompleted();
}
private void SetExpirationTime<T>(ushort order, ushort variant, TimeSpan value) where T : AnimeItemShadow
{
var item = GetItem<T>(order, variant);
item.expirationTime = value;
CheckIsCompleted();
}
private T GetItem<T>(ushort order, ushort variant) where T : AnimeItemShadow
{
var type = typeof(T);
var itemName = string.Empty;
if (type == typeof(AnimeEpisodeShadow)) itemName = "Episode";
else if (type == typeof(AnimeSeason)) itemName = "Season";
else throw new NotImplementedException();
return _shadow.items.OfType<T>()
.FirstOrDefault(q => q.order == order && q.variant == variant) ??
throw new Exception(string.Concat(itemName, " not found"));
}
public void SetCompleted() => _shadow.completed = true;
public void SetNotCompleted() => _shadow.completed = false;
public void SetExpirationTime(TimeSpan value)
{
_shadow.expirationTime = value;
CheckIsCompleted();
}
public void Delete() => SetDeleted();
internal override void SetDeleted() => _shadow.deleted = true;
internal void CheckIsCompleted()
{
var itemsQuery = Items.AsQueryable();
var ucompletedSeasons = itemsQuery
.Any(q => !q.CommonProperties.ReleaseDate.HasValue);
var lastEpisodeReleaseDate = itemsQuery
.OrderByDescending(q => q.CommonProperties.ReleaseDate)
.FirstOrDefault()?.CommonProperties.ReleaseDate;
if (ucompletedSeasons || lastEpisodeReleaseDate >= DateTime.UtcNow - ExpirationTime) SetNotCompleted();
else SetCompleted();
}
}