namespace Modules.Library.Domain.Entities.MediaContent.CommonProperties; public class CommonProperties : ValueObject { private readonly List _names = []; public IReadOnlyCollection Names => _names.AsReadOnly(); public MediaInfo? Preview { get; private set; } private readonly List _descriptions = []; public IReadOnlyCollection Descriptions => _descriptions.AsReadOnly(); private readonly List _genres = []; public IReadOnlyCollection Genres => _genres.AsReadOnly(); private readonly List _relatedContent = []; public IReadOnlyCollection RelatedContent => _relatedContent.AsReadOnly(); public DateTimeOffset? AnnouncementDate { get; private set; } public DateTimeOffset? EstimatedReleaseDate { get; private set; } public DateTimeOffset? ReleaseDate { get; private set; } internal CommonProperties() { } private CommonProperties(Models.CommonProperties commonProperties) { Preview = commonProperties.Preview != null ? new MediaInfo(commonProperties.Preview.Url, commonProperties.Preview.Type) : null; AnnouncementDate = commonProperties.AnnouncementDate; EstimatedReleaseDate = commonProperties.EstimatedReleaseDate; ReleaseDate = commonProperties.ReleaseDate; _names.AddRange(commonProperties.Names.Select(NameItem.New)); _descriptions.AddRange(commonProperties.Descriptions.Select(Description.New)); _genres.AddRange(commonProperties.Genres.Select(GenreProportion.New)); _relatedContent.AddRange(commonProperties.RelatedContent.Select(q => new MediaInfo(q.Url, q.Type))); } internal CommonProperties(Guid nameOriginalLnaguageId, string nameOriginal) { _names.Add(new NameItem(nameOriginalLnaguageId, NameType.Original, nameOriginal)); } internal static CommonProperties New(Models.CommonProperties commonProperties) => new(commonProperties); #region Name public void AddName(NameType nameType, Guid languageId, string value) { switch (nameType) { case NameType.Original: AddNameOriginal(languageId, value); break; case NameType.OriginalInAnotherLanguage: AddNameOriginalInAnotherLanguage(languageId, value); break; case NameType.Translation: AddNameTranslation(languageId, value); break; case NameType.Abbreviation: AddNameAbbreviation(languageId, value); break; default: throw new NotImplementedException(); } } private void AddNameOriginal(Guid languageId, string value) { if (_names.Any(q => q.Type == NameType.Original)) throw new Exception("Original name is already exist."); var name = new NameItem(languageId, NameType.Original, value); _names.Add(name); } private void AddNameOriginalInAnotherLanguage(Guid languageId, string value) { if (_names.FirstOrDefault(q => q.Type == NameType.Original)?.LanguageId == languageId) throw new Exception("Language must not match original name language"); if (_names.Any(q => q.Type == NameType.OriginalInAnotherLanguage && q.LanguageId == languageId)) throw new Exception("Name in following language is already exist."); var name = new NameItem(languageId, NameType.OriginalInAnotherLanguage, value); _names.Add(name); } private void AddNameTranslation(Guid languageId, string value) { var name = new NameItem(languageId, NameType.Translation, value); _names.Add(name); } private void AddNameAbbreviation(Guid languageId, string value) { var name = new NameItem(languageId, NameType.Abbreviation, value); _names.Add(name); } public void RemoveName(NameItem nameItem) { var name = GetName(nameItem); if (name.Type == NameType.Original) throw new Exception($"Unable to remove original name"); _names.Remove(name); } public void SetNameValue(NameItem nameItem, string value) { var name = GetName(nameItem); if (string.IsNullOrWhiteSpace(value)) throw new ArgumentNullException(nameof(value)); if (nameItem.Type != NameType.Original && _names.Any(q => q.LanguageId == nameItem.LanguageId && q.Value == value)) throw new Exception("Name item with in same language with same value is already exists"); nameItem.SetValue(value); } private NameItem GetName(NameItem name) => _names.FirstOrDefault(q => q == name) ?? throw new Exception($"Name with is not found"); #endregion public void SetPreview(string url, MediaInfoType type) { if (string.IsNullOrWhiteSpace(url)) throw new ArgumentNullException(nameof(url)); Preview ??= new MediaInfo(url, type); Preview.SetUrl(url); Preview.SetType(type); } public void DeletePreview() => Preview = null; #region Description public void AddOriginalDescription(Guid languageId, string value) { if (_descriptions.Any(q => q.IsOriginal)) throw new Exception("Original description is already exist."); var description = new Description(languageId, true, value); _descriptions.Add(description); } public void AddNotOriginalDescription(Guid languageId, string value) { var description = new Description(languageId, false, value); _descriptions.Add(description); } public void RemoveDescription(Description descriptionItem) { var description = GetDescription(descriptionItem); if (description.IsOriginal) throw new Exception($"Unable to remove original description"); _descriptions.Remove(description); //TODO: valueobject convert //description.SetDeleted(); } public void SetDescriptionValue(Description descriptionItem, string value) { var description = GetDescription(descriptionItem); if (string.IsNullOrWhiteSpace(value)) throw new ArgumentNullException(nameof(value)); if (!descriptionItem.IsOriginal && _descriptions.Any(q => q.LanguageId == descriptionItem.LanguageId && q.Value == value)) throw new Exception("Descriptoin item with with same value is already exists"); descriptionItem.SetValue(value); } private Description GetDescription(Description description) { return _descriptions.FirstOrDefault(q => q == description) ?? throw new Exception($"Description is not found"); } #endregion #region Genre public void AddGenre(Guid genreId, decimal? proportion = null) { if (_genres.Any(q => q.GenreId == genreId)) throw new Exception("Genre is already in the list"); var genreProportionItem = new GenreProportion(genreId, proportion); _genres.Add(genreProportionItem); if (proportion.HasValue) genreProportionItem.SetProportion(proportion); } public void SetGenreProportion(Guid genreId, decimal? value = null) { var genreProportion = GetGenreProportionItem(genreId); genreProportion.SetProportion(value); } public void RemoveGenre(Guid genreId) { var genreProportion = GetGenreProportionItem(genreId); _genres.Remove(genreProportion); } private GenreProportion GetGenreProportionItem(Guid genreId) { return _genres.FirstOrDefault(q => q.GenreId == genreId) ?? throw new Exception($"Genre proportion is not found"); } /* private GenreProportion GetGenreProportionItem(GenreProportion genreProportionItem) { return _genres.FirstOrDefault(q => q == genreProportionItem) ?? throw new Exception($"Genre proportion is not found"); } */ #endregion #region RelatedContent public void AddRelatedContent(string url, MediaInfoType type) { if (string.IsNullOrWhiteSpace(url)) throw new ArgumentNullException(nameof(url)); CheckIfCanAddOrEdit(url, type); _relatedContent.Add(new MediaInfo(url, type)); } public void EditRelatedContent(MediaInfo relatedContentItem, string url, MediaInfoType type) { var relatedContent = GetRelatedContent(relatedContentItem); CheckIfCanAddOrEdit(url, type); relatedContent.SetUrl(url); relatedContent.SetType(type); } public void RemoveRelatedContent(MediaInfo relatedContentItem) { var relatedContent = GetRelatedContent(relatedContentItem); _relatedContent.Remove(relatedContent); //TODO: valueobject convert } private void CheckIfCanAddOrEdit(string url, MediaInfoType type) { if (_relatedContent.Any(q => q.Url == url && q.Type == type)) throw new Exception("Related content with same url and same type is already exists"); } private MediaInfo GetRelatedContent(MediaInfo relatedContentItem) { return _relatedContent.FirstOrDefault(q => q == relatedContentItem) ?? throw new Exception($"Related content is not found"); } #endregion public void SetAnnouncementDate(DateTimeOffset? value) { AnnouncementDate = value; } public void SetEstimatedReleaseDate(DateTimeOffset? value) { if (value == default) throw new ArgumentNullException(nameof(value)); if (AnnouncementDate.HasValue && value <= AnnouncementDate.Value) throw new Exception("Estimated release date can not be less or equal to announcement date"); EstimatedReleaseDate = value; } public void SetReleaseDate(DateTimeOffset? value) { if (value == default) throw new ArgumentNullException(nameof(value)); if (AnnouncementDate.HasValue && value <= AnnouncementDate.Value) throw new Exception("Release date can not be less or equal to announcement date"); ReleaseDate = value; } protected override IEnumerable GetEqualityComponents() { foreach (var name in _names) { yield return name; } yield return Preview; foreach (var descriptions in _descriptions) { yield return descriptions; } foreach (var genre in _genres) { yield return genre; } foreach (var relatedContent in _relatedContent) { yield return relatedContent; } yield return AnnouncementDate; yield return EstimatedReleaseDate; yield return ReleaseDate; } }