using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using DataLayer; namespace LibationWinForms { internal class GridEntry { private LibraryBook libraryBook; private Book book => libraryBook.Book; public Book GetBook() => book; // this special case is obvious and ugly public void REPLACE_Library_Book(LibraryBook libraryBook) => this.libraryBook = libraryBook; public GridEntry(LibraryBook libraryBook) => this.libraryBook = libraryBook; // hide from public fields from Data Source GUI with [Browsable(false)] [Browsable(false)] public string Tags => book.UserDefinedItem.Tags; [Browsable(false)] public IEnumerable TagsEnumerated => book.UserDefinedItem.TagsEnumerated; public enum LiberatedState { NotDownloaded, DRM, Liberated } [Browsable(false)] public LiberatedState Liberated_Status => FileManager.AudibleFileStorage.Audio.Exists(book.AudibleProductId) ? LiberatedState.Liberated : FileManager.AudibleFileStorage.AAX.Exists(book.AudibleProductId) ? LiberatedState.DRM : LiberatedState.NotDownloaded; public enum PdfState { NoPdf, Downloaded, NotDownloaded } [Browsable(false)] public PdfState Pdf_Status => !book.Supplements.Any() ? PdfState.NoPdf : FileManager.AudibleFileStorage.PDF.Exists(book.AudibleProductId) ? PdfState.Downloaded : PdfState.NotDownloaded; // displayValues is what gets displayed // the value that gets returned from the property is the cell's value // this allows for the value to be sorted one way and displayed another // eg: // orig title: The Computer // formatReplacement: The Computer // value for sorting: Computer private Dictionary displayValues { get; } = new Dictionary(); public bool TryDisplayValue(string key, out string value) => displayValues.TryGetValue(key, out value); public Image Cover => WindowsDesktopUtilities.WinAudibleImageServer.GetImage(book.PictureId, FileManager.PictureSize._80x80); public string Title { get { displayValues[nameof(Title)] = book.Title; return getSortName(book.Title); } } public string Authors => book.AuthorNames; public string Narrators => book.NarratorNames; public int Length { get { displayValues[nameof(Length)] = book.LengthInMinutes == 0 ? "" : $"{book.LengthInMinutes / 60} hr {book.LengthInMinutes % 60} min"; return book.LengthInMinutes; } } public string Series { get { displayValues[nameof(Series)] = book.SeriesNames; return getSortName(book.SeriesNames); } } private static string[] sortPrefixIgnores { get; } = new[] { "the", "a", "an" }; private static string getSortName(string unformattedName) { var sortName = unformattedName .Replace("|", "") .Replace(":", "") .ToLowerInvariant() .Trim(); if (sortPrefixIgnores.Any(prefix => sortName.StartsWith(prefix + " "))) sortName = sortName.Substring(sortName.IndexOf(" ") + 1).TrimStart(); return sortName; } private string descriptionCache = null; public string Description { get { // HtmlAgilityPack is expensive. cache results if (descriptionCache is null) { if (book.Description is null) descriptionCache = ""; else { var doc = new HtmlAgilityPack.HtmlDocument(); doc.LoadHtml(book.Description); var noHtml = doc.DocumentNode.InnerText; descriptionCache = noHtml.Length < 63 ? noHtml : noHtml.Substring(0, 60) + "..."; } } return descriptionCache; } } public string Category => string.Join(" > ", book.CategoriesNames); // star ratings retain numeric value but display star text. this is needed because just using star text doesn't sort correctly: // - star // - star star // - star 1/2 public string Product_Rating { get { displayValues[nameof(Product_Rating)] = starString(book.Rating); return firstScore(book.Rating); } } public string Purchase_Date { get { displayValues[nameof(Purchase_Date)] = libraryBook.DateAdded.ToString("d"); return libraryBook.DateAdded.ToString("yyyy-MM-dd HH:mm:ss"); } } public string My_Rating { get { displayValues[nameof(My_Rating)] = starString(book.UserDefinedItem.Rating); return firstScore(book.UserDefinedItem.Rating); } } private string starString(Rating rating) => (rating?.FirstScore != null && rating?.FirstScore > 0f) ? rating?.ToStarString() : ""; private string firstScore(Rating rating) => rating?.FirstScore.ToString("0.0"); // max 5 text rows public string Misc { get { var details = new List(); if (book.HasPdf) details.Add("Has PDF"); if (book.IsAbridged) details.Add("Abridged"); if (book.DatePublished.HasValue) details.Add($"Date pub'd: {book.DatePublished.Value.ToString("MM/dd/yyyy")}"); // this goes last since it's most likely to have a line-break if (!string.IsNullOrWhiteSpace(book.Publisher)) details.Add($"Pub: {book.Publisher}"); if (!details.Any()) return "[details not imported]"; return string.Join("\r\n", details); } } } }