using System.Diagnostics; using Microsoft.AspNetCore.Mvc; using HaWeb.Models; using HaWeb.FileHelpers; using HaDocument.Interfaces; using HaDocument.Models; using HaXMLReader.Interfaces; using System.Collections.Specialized; using HaWeb.XMLParser; using HaWeb.Settings.ParsingState; using System.Text; using HaWeb.Settings.ParsingRules; using System.Linq;//AsParallel, ToList using System.Collections.Generic;//Dictionary namespace HaWeb.Controllers; public class SucheController : Controller { private IHaDocumentWrappper _lib; private IReaderService _readerService; private IXMLService _xmlService; private int _lettersForPage; public SucheController(IHaDocumentWrappper lib, IReaderService readerService, IXMLService service, IConfiguration config) { _lib = lib; _readerService = readerService; _xmlService = service; _lettersForPage = config.GetValue("LettersOnPage"); } // Letter Search [Route("/HKB/Suche/Briefe/")] public IActionResult Briefe(string search, int page = 0, bool? comments = false) { var lib = _lib.GetLibrary(); // Error checking if (search == null) return _error404(); if (String.IsNullOrWhiteSpace(search)) return View("~/Views/HKB/Dynamic/Suche.cshtml", new SucheViewModel(SearchType.Letters, SearchResultType.InvalidSearchTerm, comments, page, null, search, null, null, null, null)); search = search.Trim(); // Letter & comment search and search result creation var resletter = _xmlService.SearchCollection("letters", search, _readerService, null); List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? rescomments = null; if (comments == true) rescomments = _xmlService.SearchCollection("marginals", search, _readerService, lib); // Error checking if ((resletter == null || !resletter.Any()) && (rescomments == null || !rescomments.Any())) return View("~/Views/HKB/Dynamic/Suche.cshtml", new SucheViewModel(SearchType.Letters, SearchResultType.NotFound, comments, page, null, search, null, null, null, null)); // Metadata aquisition & sorting List? metas = new List(); if (resletter != null) metas.AddRange( resletter .Select(x => x.Index) .Where(x => lib.Metas.ContainsKey(x)) .Select(x => lib.Metas[x]) ); if (rescomments != null) metas.AddRange( rescomments .Where(x => lib.Marginals.ContainsKey(x.Index)) .Select(x => lib.Marginals[x.Index]) .Where(x => lib.Metas.ContainsKey(x.Letter)) .Select(x => lib.Metas[x.Letter]) ); // Return return _paginateSendLettersComments(lib, page, search, comments, SearchResultType.Success, metas.Distinct().ToList(), resletter, rescomments); } // Register & Bibliography Search [Route("/HKB/Suche/Register/")] public IActionResult Register(string search) { var lib = _lib.GetLibrary(); // Error checking if (search == null) return _error404(); if (String.IsNullOrWhiteSpace(search)) return _paginateSendRegister(lib, search, SearchType.Register, SearchResultType.InvalidSearchTerm, null); search = search.Trim(); // Search List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? res = null; res = _xmlService.SearchCollection("register-comments", search, _readerService, lib); if (res == null || !res.Any()) return _paginateSendRegister(lib, search, SearchType.Register, SearchResultType.NotFound, null); // Return return _paginateSendRegister(lib, search, SearchType.Register, SearchResultType.Success, _createComments("neuzeit", res.Select((x) => (x.Index, x.Results.Select((y) => y.Identifier).ToList())).OrderBy(x => x.Index).ToList())); } [Route("/HKB/Suche/Forschung/")] public IActionResult Science(string search) { var lib = _lib.GetLibrary(); // Error checking if (search == null) return _error404(); if (String.IsNullOrWhiteSpace(search)) return _paginateSendRegister(lib, search, SearchType.Science, SearchResultType.InvalidSearchTerm, null); search = search.Trim(); // Search List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? res = null; res = _xmlService.SearchCollection("forschung-comments", search, _readerService, lib); if (res == null || !res.Any()) return _paginateSendRegister(lib, search, SearchType.Science, SearchResultType.NotFound, null); // Return return _paginateSendRegister(lib, search, SearchType.Science, SearchResultType.Success, _createComments("neuzeit", res.Select((x) => (x.Index, x.Results.Select((y) => y.Identifier).ToList())).OrderBy(x => x.Index).ToList())); } private IActionResult _paginateSendLettersComments( ILibrary lib, int page, string search, bool? comments, SearchResultType SRT, List? metas, List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? resletters, List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? rescomments ) { // Sorting, get Pages & Error Checking var metasbyyear = metas!.Distinct().ToLookup(x => x.Sort.Year).OrderBy(x => x.Key).ToList(); var pages = IndexController.Paginate(metasbyyear, _lettersForPage); if (pages != null && page >= pages.Count) return _error404(); if (pages == null && page > 0) return _error404(); List<(int Year, List LetterList)>? letters = null; // Select & Parse Metadata for Letters to be shown on the selected Page if (pages != null && metasbyyear != null) letters = metasbyyear .Where(x => x.Key >= pages[page].StartYear && x.Key <= pages[page].EndYear) .Select(x => (x.Key, x .Select(y => IndexController.GenerateMetaViewModel(lib, y)) .OrderBy(x => x.Meta.Sort) .ThenBy(x => x.Meta.Order) .ToList())) .ToList(); // Generate Search results & previews Dictionary>? searchResults = new Dictionary>(); Dictionary>? parsedMarginals = null; if (resletters != null) foreach (var res in resletters) { if (!searchResults.ContainsKey(res.Index)) searchResults.Add(res.Index, new List()); foreach (var r in res.Results) { if(!searchResults[res.Index].Where(x => x.Page == r.Page && x.Line == r.Line).Any()) searchResults[res.Index].Add(new SearchResult(search, res.Index) { Page = r.Page, Line = r.Line, Preview = r.Preview }); } if (searchResults[res.Index].Any()) { searchResults[res.Index] = searchResults[res.Index].OrderBy(x => HaWeb.HTMLHelpers.ConversionHelpers.RomanOrNumberToInt(x.Page)).ThenBy(x => HaWeb.HTMLHelpers.ConversionHelpers.RomanOrNumberToInt(x.Line)).ToList(); } } if (rescomments != null) { var marginals = rescomments.Where(x => lib.Marginals.ContainsKey(x.Index)).Select(x => lib.Marginals[x.Index]).ToLookup(x => x.Letter); var shownletters = letters!.SelectMany(x => x.LetterList.Select(y => y.Meta.Index)).ToHashSet(); var shownmarginals = marginals!.Where(x => shownletters.Contains(x.Key)).Select(x => (x.Key, x.ToList())).ToList(); var previews = _xmlService != null ? _xmlService.GetPreviews(shownmarginals, _readerService ,lib) : null; if (previews != null) foreach (var p in previews) { if (!searchResults.ContainsKey(p.Index)) searchResults.Add(p.Index, new List()); foreach (var res in p.Results) { if (!searchResults[p.Index].Where(x => x.Page == res.Page && x.Line == res.Line).Any()) searchResults[p.Index].Add(new SearchResult(search, p.Index) { Page = res.Page, Line = res.Line, Preview = res.Preview }); } if (searchResults[p.Index].Any()) { searchResults[p.Index] = searchResults[p.Index].OrderBy(x => HaWeb.HTMLHelpers.ConversionHelpers.RomanOrNumberToInt(x.Page)).ThenBy(x => HaWeb.HTMLHelpers.ConversionHelpers.RomanOrNumberToInt(x.Line)).ToList(); } } // Parse Marginals foreach (var l in marginals) { if (parsedMarginals == null && l.Any()) parsedMarginals = new Dictionary>(); if (l.Any()) { var list = new List<(Marginal, string)>(); foreach (var c in l) { var sb = new StringBuilder(); var rd = _readerService.RequestStringReader(c.Element); var st = new LetterState(lib, _readerService, lib.Metas[c.Letter], null, null, null); new HaWeb.HTMLParser.XMLHelper(st, rd, sb, LetterRules.OTagRules, null, LetterRules.CTagRules, LetterRules.TextRules, LetterRules.WhitespaceRules); new HaWeb.HTMLHelpers.LinkHelper(st.Lib, rd, sb, false); rd.Read(); list.Add((c, sb.ToString())); } parsedMarginals!.Add(l.Key, list); } } } // Model Init & Return var model = new SucheViewModel(SearchType.Letters, SearchResultType.Success, comments, page, _paginate(pages), search, searchResults, letters, null, parsedMarginals); return View("~/Views/HKB/Dynamic/Suche.cshtml", model); } private IActionResult _paginateSendRegister( ILibrary lib, string activeSearch, SearchType ST, SearchResultType SRT, List comments) { // Model init & return var model = new SucheViewModel(ST, SRT, null, 0, null, activeSearch, null, null, comments, null); return View("~/Views/HKB/Dynamic/Suche.cshtml", model); } private List? _paginate(List<(int StartYear, int EndYear)>? pages) { return pages != null ? pages.Select(x => { if (x.StartYear != x.EndYear) return x.StartYear + "–" + x.EndYear; else return x.StartYear.ToString(); }).ToList() : null; } // Select and parse comments to be shown on a page private List _createComments(string category, List<(string, List)>? comments) { var lib = _lib.GetLibrary(); var res = new List(); if (comments == null) return res; foreach (var comm in comments) { var commobj = lib.Comments[comm.Item1]; var parsedComment = HTMLHelpers.CommentHelpers.CreateHTML(lib, _readerService, commobj, category, Settings.ParsingState.CommentType.Comment); List? parsedSubComments = new List(); var distinctList = comm.Item2.Distinct().ToList(); foreach (var subcomm in distinctList) { if (subcomm != comm.Item1) { var subcommobj = lib.SubCommentsByID[subcomm]; parsedSubComments.Add(HTMLHelpers.CommentHelpers.CreateHTML(lib, _readerService, subcommobj, category, Settings.ParsingState.CommentType.Subcomment)); } } res.Add(new CommentModel(parsedComment, parsedSubComments)); } return res; } private IActionResult _error404() { Response.StatusCode = 404; return Redirect("/Error404"); } }