namespace Journal.Core.Models; public class JournalEntry { public string Date { get; set; } public List Fragments { get; set; } public string RawContent { get; set; } public Dictionary Sections { get; set; } public JournalEntry( string date, IEnumerable? fragments = null, string rawContent = "", IDictionary? sections = null) { if (string.IsNullOrWhiteSpace(date)) throw new ArgumentException("Date is required", nameof(date)); Date = date.Trim(); Fragments = fragments is null ? [] : [.. fragments]; RawContent = rawContent ?? ""; Sections = sections is null ? [] : new Dictionary(sections); } public string GetSection(string sectionTitle) { if (string.IsNullOrWhiteSpace(sectionTitle)) return ""; if (!Sections.TryGetValue(sectionTitle, out var section)) return ""; return string.Join("\n", section.Content); } public bool? GetCheckboxState(string sectionTitle, string checkboxText) { if (string.IsNullOrWhiteSpace(sectionTitle) || string.IsNullOrWhiteSpace(checkboxText)) return null; if (!Sections.TryGetValue(sectionTitle, out var section)) return null; return section.Checkboxes.TryGetValue(checkboxText, out var checkedState) ? checkedState : null; } public void MergeWith(JournalEntry otherEntry) { ArgumentNullException.ThrowIfNull(otherEntry); foreach (var (title, newSection) in otherEntry.Sections) { if (newSection.Content.Any(line => !string.IsNullOrWhiteSpace(line))) Sections[title] = newSection; } var existingFragmentDescriptions = Fragments .Select(fragment => fragment.Description) .ToHashSet(StringComparer.Ordinal); foreach (var newFragment in otherEntry.Fragments) { if (!existingFragmentDescriptions.Contains(newFragment.Description)) Fragments.Add(newFragment); } } public string ToMarkdown() { var lines = new List { "---", "type: journal", "---", $"**Date:** {Date}\n" }; foreach (var title in SectionTitles.Canonical) { if (!Sections.TryGetValue(title, out var section)) continue; lines.Add($"## {section.Title}\n"); lines.AddRange(section.Content); lines.Add(""); } if (Fragments.Count > 0) { lines.Add("# Fragments\n"); foreach (var fragment in Fragments) { var timeStr = fragment.Time != default ? $"@{fragment.Time:O}" : ""; var tagsStr = string.Join(" ", fragment.Tags.Select(tag => $"#{tag}")); var header = $"{fragment.Type} {timeStr} {tagsStr}".Trim(); lines.Add($"{header}\n{fragment.Description}\n"); } } return string.Join("\n", lines); } }