using DataLayer; using Dinah.Core.DataBinding; using Dinah.Core.Drawing; using LibationFileManager; using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Linq; namespace LibationWinForms.GridView { public abstract class GridEntry : AsyncNotifyPropertyChanged, IMemberComparable { protected abstract Book Book { get; } private Image _cover; #region Model properties exposed to the view public Image Cover { get => _cover; protected set { _cover = value; NotifyPropertyChanged(); } } public new bool InvokeRequired => base.InvokeRequired; public abstract DateTime DateAdded { get; } public abstract float SeriesIndex { get; } public abstract string ProductRating { get; protected set; } public abstract string PurchaseDate { get; protected set; } public abstract string MyRating { get; protected set; } public abstract string Series { get; protected set; } public abstract string Title { get; protected set; } public abstract string Length { get; protected set; } public abstract string Authors { get; protected set; } public abstract string Narrators { get; protected set; } public abstract string Category { get; protected set; } public abstract string Misc { get; protected set; } public abstract string Description { get; protected set; } public abstract string DisplayTags { get; } public abstract LiberateButtonStatus Liberate { get; } #endregion #region Sorting public GridEntry() => _memberValues = CreateMemberValueDictionary(); private Dictionary> _memberValues { get; set; } protected abstract Dictionary> CreateMemberValueDictionary(); // These methods are implementation of Dinah.Core.DataBinding.IMemberComparable // Used by GridEntryBindingList for all sorting public virtual object GetMemberValue(string memberName) => _memberValues[memberName](); public IComparer GetMemberComparer(Type memberType) => _memberTypeComparers[memberType]; #endregion protected void LoadCover() { // Get cover art. If it's default, subscribe to PictureCached { (bool isDefault, byte[] picture) = PictureStorage.GetPicture(new PictureDefinition(Book.PictureId, PictureSize._80x80)); if (isDefault) PictureStorage.PictureCached += PictureStorage_PictureCached; // Mutable property. Set the field so PropertyChanged isn't fired. _cover = ImageReader.ToImage(picture); } } private void PictureStorage_PictureCached(object sender, PictureCachedEventArgs e) { if (e.Definition.PictureId == Book.PictureId) { Cover = ImageReader.ToImage(e.Picture); PictureStorage.PictureCached -= PictureStorage_PictureCached; } } // Instantiate comparers for every exposed member object type. private static readonly Dictionary _memberTypeComparers = new() { { typeof(string), new ObjectComparer() }, { typeof(int), new ObjectComparer() }, { typeof(float), new ObjectComparer() }, { typeof(bool), new ObjectComparer() }, { typeof(DateTime), new ObjectComparer() }, { typeof(LiberateButtonStatus), new ObjectComparer() }, }; ~GridEntry() { PictureStorage.PictureCached -= PictureStorage_PictureCached; } } internal static class GridEntryExtensions { #nullable enable public static IEnumerable Series(this IEnumerable gridEntries) => gridEntries.Where(i => i is SeriesEntry).Cast(); public static IEnumerable LibraryBooks(this IEnumerable gridEntries) => gridEntries.Where(i => i is LibraryBookEntry).Cast(); public static LibraryBookEntry? FindBookByAsin(this IEnumerable gridEntries, string audibleProductID) => gridEntries.FirstOrDefault(i => i.AudibleProductId == audibleProductID); public static SeriesEntry? FindBookSeriesEntry(this IEnumerable gridEntries, IEnumerable matchSeries) => gridEntries.Series().FirstOrDefault(i => matchSeries.Any(s => s.Series.Name == i.Series)); public static IEnumerable EmptySeries(this IEnumerable gridEntries) => gridEntries.Series().Where(i => i.Children.Count == 0); } }