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

171 lines
6.3 KiB
C#

using Modules.Library.Domain.EntitiesV0.MediaContent.Items.Anime.ShadowEntities;
namespace Modules.Library.Domain.EntitiesV0.MediaContent.Items.Anime;
public class AnimeTitle : Entity
{
internal readonly AnimeTitleShadow _shadow;
public override string Id => _shadow.id;
public CommonProperties.CommonProperties CommonProperties => new(_shadow.commonProperties, CheckIsCompleted, CheckIsCompleted, CheckIsCompleted);
public IReadOnlyCollection<AnimeItem> Items => _shadow.items.Select(ConvertToAnimeItem).ToList().AsReadOnly();
public bool Completed => _shadow.completed;
public override bool Deleted => _shadow.deleted;
public TimeSpan ExpirationTime => _shadow.expirationTime;
internal AnimeTitle(AnimeTitleShadow shadow) => _shadow = shadow;
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(AnimeEpisode episode)
{
episode.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();
}
}