using Microsoft.EntityFrameworkCore; using RMuseum.DbContext; using RMuseum.Models.Divan; using RSecurityBackend.Models.Generic; using RSecurityBackend.Services.Implementation; using System; using System.Data; using System.Linq; using System.Collections.Generic; using System.Threading.Tasks; using RSecurityBackend.Models.Generic.Db; namespace RMuseum.Services.Implementation { /// /// IDivanService implementation /// public partial class DivanService : IDivanService { /// /// filling poem formats /// /// public RServiceResult StartFillingSectionsPoemFormats() { try { _backgroundTaskQueue.QueueBackgroundWorkItem ( async token => { using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC { LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); var job = (await jobProgressServiceEF.NewJob("StartFillingSectionsPoemFormats", "Query data")).Result; int progress = 0; try { var sections = await context.DivanPoemSections.Where(s => s.SectionType == PoemSectionType.WholePoem).ToListAsync(); int count = sections.Count; int updatedSectionsCount = 0; for (int i = 0; i < count; i++) { var mainSection = sections[i]; mainSection.PoemFormat = null; var poem = await context.DivanPoems.AsNoTracking().Where(p => p.Id == mainSection.PoemId).SingleOrDefaultAsync(); if (poem == null) continue; if(poem.FullTitle.Contains("شاهنامه") || poem.FullTitle.Contains("مثنوی")) { mainSection.PoemFormat = DivanPoemFormat.Masnavi; context.Update(mainSection); await context.SaveChangesAsync(); updatedSectionsCount++; continue; } var nonCommentVerses = await context.DivanVerses.AsNoTracking().Where(v => v.PoemId == poem.Id && v.VersePosition != VersePosition.Comment && v.SectionIndex1 == mainSection.Index).OrderBy(v => v.VOrder).ToListAsync(); if (!nonCommentVerses.Any()) continue; bool multiBand = false; if (!nonCommentVerses.Where(v => v.VersePosition == VersePosition.Paragraph || v.VersePosition == VersePosition.Single).Any()) { if (nonCommentVerses.Where(v => v.VersePosition == VersePosition.CenteredVerse1 || v.VersePosition == VersePosition.CenteredVerse2 ).Any()) { multiBand = true; } } if (multiBand) { mainSection.PoemFormat = DivanPoemFormat.MultiBand; if (poem.FullTitle.Contains("ترجیع")) mainSection.PoemFormat = DivanPoemFormat.TarjeeBand; if (poem.FullTitle.Contains("ترکیب")) mainSection.PoemFormat = DivanPoemFormat.TarkibBand; if (poem.FullTitle.Contains("مسمط")) mainSection.PoemFormat = DivanPoemFormat.Mosammat; if (poem.FullTitle.Contains("مخمس")) mainSection.PoemFormat = DivanPoemFormat.Mosammat5; if (poem.FullTitle.Contains("مسدس")) mainSection.PoemFormat = DivanPoemFormat.Mosammat6; if (poem.FullTitle.Contains("چهارپاره")) mainSection.PoemFormat = DivanPoemFormat.ChaharPare; } else { if (!string.IsNullOrEmpty(mainSection.RhymeLetters)) { mainSection.PoemFormat = DivanPoemFormat.Generic; if (poem.FullTitle.Contains("رباعی")) mainSection.PoemFormat = DivanPoemFormat.Robaee; else if (poem.FullTitle.Contains("غزل")) mainSection.PoemFormat = DivanPoemFormat.Ghazal; else if (poem.FullTitle.Contains("قصاید") || poem.FullTitle.Contains("قصید")) mainSection.PoemFormat = DivanPoemFormat.Ghaside; else if (poem.FullTitle.Contains("قطعات") || poem.FullTitle.Contains("قطعه")) mainSection.PoemFormat = DivanPoemFormat.Ghete; if(nonCommentVerses.Count == 4) { if (mainSection.DivanMetreId == 24) //id for robaee from database mainSection.PoemFormat = DivanPoemFormat.Robaee; else if (mainSection.DivanMetreId == 12) //id for dobeyti from database mainSection.PoemFormat = DivanPoemFormat.Dobeyti; } } else if (_IsMasnavi(nonCommentVerses)) { mainSection.PoemFormat = DivanPoemFormat.Masnavi; } } if(mainSection.PoemFormat != null) { updatedSectionsCount++; context.Update(mainSection); await context.SaveChangesAsync(); } if ((i * 100 / count) > progress) { progress = i * 100 / count; await jobProgressServiceEF.UpdateJob(job.Id, progress, $"{updatedSectionsCount} sections updated"); } } await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); } catch (Exception exp) { await jobProgressServiceEF.UpdateJob(job.Id, progress, "", false, exp.ToString()); } } }); return new RServiceResult(true); } catch (Exception exp) { return new RServiceResult(false, exp.ToString()); } } /// /// sectionizing poems /// /// public RServiceResult StartFillingPoemSectionsCoupletIndex() { try { _backgroundTaskQueue.QueueBackgroundWorkItem ( async token => { using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC { LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); var job = (await jobProgressServiceEF.NewJob("StartFillingPoemSectionsCoupletIndex", "Query data")).Result; int progress = 0; try { var sections = await context.DivanPoemSections.OrderBy(s => s.SectionType).ToListAsync(); int count = sections.Count; for (int i = 0; i < count; i++) { var section = sections[i]; var firstSectionVerse = await context.DivanVerses.AsNoTracking() .Where (v => v.PoemId == section.PoemId && ( (section.VerseType == VersePoemSectionType.Second && v.SectionIndex2 == section.Index) || (section.VerseType == VersePoemSectionType.Third && v.SectionIndex3 == section.Index) || (section.VerseType == VersePoemSectionType.Forth && v.SectionIndex4 == section.Index) ) ) .OrderBy(v => v.VOrder) .FirstOrDefaultAsync(); if (firstSectionVerse != null && firstSectionVerse.CoupletIndex != null) { section.CachedFirstCoupletIndex = (int)firstSectionVerse.CoupletIndex; context.Update(section); } if ((i * 100 / count) > progress) { progress = i * 100 / count; await jobProgressServiceEF.UpdateJob(job.Id, progress); } } await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); } catch (Exception exp) { await jobProgressServiceEF.UpdateJob(job.Id, progress, "", false, exp.ToString()); } } }); return new RServiceResult(true); } catch (Exception exp) { return new RServiceResult(false, exp.ToString()); } } private bool _IsMasnavi(List verses, bool bandCouplet = false) { if (verses.Count % 2 != 0) return false; if (bandCouplet) { if (verses.Any(v => v.VersePosition != VersePosition.CenteredVerse1 && v.VersePosition != VersePosition.CenteredVerse2)) return false; } else { if (verses.Any(v => v.VersePosition != VersePosition.Right && v.VersePosition != VersePosition.Left)) return false; } int rhymingCouplets = 0; for (int i = 0; i < verses.Count; i += 2) { var rightVerse = verses[i]; if (bandCouplet) { if (rightVerse.VersePosition != VersePosition.CenteredVerse1) return false; } else { if (rightVerse.VersePosition != VersePosition.Right) return false; } var leftVerse = verses[i + 1]; if (bandCouplet) { if (leftVerse.VersePosition != VersePosition.CenteredVerse2) return false; } else { if (leftVerse.VersePosition != VersePosition.Left) return false; } List coupletVerses = new List(); coupletVerses.Add(rightVerse); coupletVerses.Add(leftVerse); var res = LanguageUtils.FindRhyme(coupletVerses, false, bandCouplet); if (!string.IsNullOrEmpty(res.Rhyme)) rhymingCouplets++; if (rhymingCouplets * 200 / verses.Count > 50) return true; } return false; } private async Task _SectionizePoem(RMuseumDbContext context, DivanPoem poem, LongRunningJobProgressServiceEF jobProgressServiceEF, RLongRunningJobStatus job, DivanCat cat) { if (true == await context.DivanPoemSections.AsNoTracking().Where(s => s.PoemId == poem.Id).AnyAsync()) { return true; } var nonCommentVerses = await context.DivanVerses.Where(v => v.PoemId == poem.Id && v.VersePosition != VersePosition.Comment).OrderBy(v => v.VOrder).ToListAsync(); if (!nonCommentVerses.Where(v => v.VersePosition == VersePosition.Paragraph || v.VersePosition == VersePosition.Single).Any()) { if (nonCommentVerses.Where(v => v.VersePosition == VersePosition.CenteredVerse1 || v.VersePosition == VersePosition.CenteredVerse2 ).Any()) { //multi-band poem _SectionizeMultibandVerses(context, nonCommentVerses, poem, 0, cat); } else if (!nonCommentVerses.Where(v => v.VersePosition != VersePosition.Right && v.VersePosition != VersePosition.Left).Any()) { _SectionizeNormalVerses(context, nonCommentVerses, poem, 0, cat); } } else { int sectionIndex = 0; int vIndex = 0; List singleVerses = new List(); List normalVerses = new List(); while (vIndex < nonCommentVerses.Count) { if (nonCommentVerses[vIndex].VersePosition == VersePosition.Single) { singleVerses.Add(nonCommentVerses[vIndex]); vIndex++; continue; } if (singleVerses.Count > 0) { DivanPoemSection mainSection = new DivanPoemSection() { PoemId = poem.Id, PoetId = cat.PoetId, SectionType = PoemSectionType.WholePoem, VerseType = VersePoemSectionType.First, Index = sectionIndex, Number = sectionIndex + 1, DivanMetreId = poem.DivanMetreId, RhymeLetters = poem.RhymeLetters, HtmlText = PrepareHtmlText(singleVerses), PlainText = PreparePlainText(singleVerses), CoupletsCount = singleVerses.Where(v => v.VersePosition == VersePosition.Left || v.VersePosition == VersePosition.CenteredVerse1).Count(), PoemFormat = DivanPoemFormat.New, }; context.Add(mainSection);//having a main section for مثنوی inside normal text helps keep track of related versess foreach (var verse in singleVerses) { verse.SectionIndex1 = mainSection.Index; verse.SectionIndex2 = null;//clear previous indices verse.SectionIndex3 = null;//clear previous indices verse.SectionIndex4 = null;//clear previous indices } context.UpdateRange(singleVerses); sectionIndex++; singleVerses = new List(); } if (nonCommentVerses[vIndex].VersePosition == VersePosition.Left || nonCommentVerses[vIndex].VersePosition == VersePosition.Right || nonCommentVerses[vIndex].VersePosition == VersePosition.CenteredVerse1 || nonCommentVerses[vIndex].VersePosition == VersePosition.CenteredVerse2 ) { normalVerses.Add(nonCommentVerses[vIndex]); vIndex++; continue; } if (normalVerses.Count > 0) { if (normalVerses.Where(v => v.VersePosition == VersePosition.CenteredVerse1 || v.VersePosition == VersePosition.CenteredVerse2 ).Any()) { //multi-band poem _SectionizeMultibandVerses(context, normalVerses, poem, sectionIndex, cat); } else { _SectionizeNormalVerses(context, normalVerses, poem, sectionIndex, cat); } sectionIndex++; normalVerses = new List(); } if (nonCommentVerses[vIndex].VersePosition != VersePosition.Paragraph) { if (jobProgressServiceEF != null) { await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, $"Poem: {poem.Id}, nonCommentVerses[{vIndex}].VersePosition != VersePosition.Paragraph"); } return false; } vIndex++; } if (singleVerses.Count > 0) { DivanPoemSection mainSection = new DivanPoemSection() { PoemId = poem.Id, PoetId = cat.PoetId, SectionType = PoemSectionType.WholePoem, VerseType = VersePoemSectionType.First, Index = sectionIndex, Number = sectionIndex + 1, DivanMetreId = poem.DivanMetreId, RhymeLetters = poem.RhymeLetters, HtmlText = PrepareHtmlText(singleVerses), PlainText = PreparePlainText(singleVerses), CoupletsCount = singleVerses.Where(v => v.VersePosition == VersePosition.Left || v.VersePosition == VersePosition.CenteredVerse1).Count(), PoemFormat = DivanPoemFormat.New, }; context.Add(mainSection);//having a main section for مثنوی inside normal text helps keep track of related versess foreach (var verse in singleVerses) { verse.SectionIndex1 = mainSection.Index; verse.SectionIndex2 = null;//clear previous indices verse.SectionIndex3 = null;//clear previous indices verse.SectionIndex4 = null;//clear previous indices } context.UpdateRange(singleVerses); } if (normalVerses.Count > 0) { if (normalVerses.Where(v => v.VersePosition == VersePosition.CenteredVerse1 || v.VersePosition == VersePosition.CenteredVerse2 ).Any()) { //multi-band poem _SectionizeMultibandVerses(context, normalVerses, poem, sectionIndex, cat); } else { _SectionizeNormalVerses(context, normalVerses, poem, sectionIndex, cat); } } } return true; } private void _SectionizeMultibandVerses(RMuseumDbContext context, List nonCommentVerses, DivanPoem poem, int index, DivanCat cat) { DivanPoemSection mainSection = new DivanPoemSection() { PoemId = poem.Id, PoetId = cat.PoetId, SectionType = PoemSectionType.WholePoem, VerseType = VersePoemSectionType.First, Index = index, Number = index + 1, DivanMetreId = poem.DivanMetreId, RhymeLetters = poem.RhymeLetters, HtmlText = PrepareHtmlText(nonCommentVerses), PlainText = PreparePlainText(nonCommentVerses), CoupletsCount = nonCommentVerses.Where(v => v.VersePosition == VersePosition.Left || v.VersePosition == VersePosition.CenteredVerse1).Count(), PoemFormat = DivanPoemFormat.MultiBand, }; if (poem.FullTitle.Contains("ترجیع")) mainSection.PoemFormat = DivanPoemFormat.TarjeeBand; if (poem.FullTitle.Contains("ترکیب")) mainSection.PoemFormat = DivanPoemFormat.TarkibBand; if (poem.FullTitle.Contains("مسمط")) mainSection.PoemFormat = DivanPoemFormat.Mosammat; if (poem.FullTitle.Contains("مخمس")) mainSection.PoemFormat = DivanPoemFormat.Mosammat5; if (poem.FullTitle.Contains("مسدس")) mainSection.PoemFormat = DivanPoemFormat.Mosammat6; if (poem.FullTitle.Contains("چهارپاره")) mainSection.PoemFormat = DivanPoemFormat.ChaharPare; index++; List currentBandVerses = new List(); DivanPoemSection currentBandSection = new DivanPoemSection() { PoemId = poem.Id, PoetId = cat.PoetId, SectionType = PoemSectionType.Band, VerseType = VersePoemSectionType.Second, Index = index, Number = index + 1, DivanMetreId = poem.DivanMetreId, DivanMetreRefSectionIndex = mainSection.Index, }; List bandVerses = new List(); foreach (var verse in nonCommentVerses) { verse.SectionIndex1 = mainSection.Index; verse.SectionIndex2 = null;//clear previous indices verse.SectionIndex3 = null;//clear previous indices verse.SectionIndex4 = null;//clear previous indices if (verse.VersePosition == VersePosition.Right || verse.VersePosition == VersePosition.Left) { currentBandVerses.Add(verse); } if (verse.VersePosition == VersePosition.CenteredVerse1 || verse.VersePosition == VersePosition.CenteredVerse2) { bandVerses.Add(verse); if (currentBandVerses.Count > 0) { foreach (var currentBandVerse in currentBandVerses) { currentBandVerse.SectionIndex2 = currentBandSection.Index; } currentBandSection.RhymeLetters = LanguageUtils.FindRhyme(currentBandVerses).Rhyme; currentBandSection.HtmlText = PrepareHtmlText(currentBandVerses); currentBandSection.CoupletsCount = currentBandVerses.Where(v => v.VersePosition == VersePosition.Left || v.VersePosition == VersePosition.CenteredVerse1).Count(); currentBandSection.PlainText = PreparePlainText(currentBandVerses); context.Add(currentBandSection); index++; currentBandVerses = new List(); currentBandSection = new DivanPoemSection() { PoemId = poem.Id, PoetId = cat.PoetId, SectionType = PoemSectionType.Band, VerseType = VersePoemSectionType.Second, Index = index, Number = index + 1, DivanMetreId = poem.DivanMetreId, DivanMetreRefSectionIndex = mainSection.Index, }; } } } if (currentBandVerses.Count > 0) { foreach (var currentBandVerse in currentBandVerses) { currentBandVerse.SectionIndex2 = currentBandSection.Index; } currentBandSection.RhymeLetters = LanguageUtils.FindRhyme(currentBandVerses).Rhyme; currentBandSection.CoupletsCount = currentBandVerses.Where(v => v.VersePosition == VersePosition.Left || v.VersePosition == VersePosition.CenteredVerse1).Count(); currentBandSection.HtmlText = PrepareHtmlText(currentBandVerses); currentBandSection.PlainText = PreparePlainText(currentBandVerses); context.Add(currentBandSection); } index++; DivanPoemSection bandSection = new DivanPoemSection() { PoemId = poem.Id, PoetId = cat.PoetId, SectionType = PoemSectionType.BandCouplets, VerseType = VersePoemSectionType.Second, Index = index, Number = index + 1, DivanMetreId = poem.DivanMetreId, DivanMetreRefSectionIndex = mainSection.Index, }; foreach (var bandVerse in bandVerses) { bandVerse.SectionIndex2 = bandSection.Index; } if (_IsMasnavi(bandVerses, true)) { if (mainSection.PoemFormat == DivanPoemFormat.MultiBand) { mainSection.PoemFormat = DivanPoemFormat.TarkibBand; } for (int v = 0; v < bandVerses.Count; v += 2) { if (bandVerses[v].VersePosition != VersePosition.CenteredVerse1 || bandVerses[v + 1].VersePosition != VersePosition.CenteredVerse2) continue; index++; var rightVerse = bandVerses[v]; var leftVerse = bandVerses[v + 1]; List coupletVerses = new List(); coupletVerses.Add(rightVerse); coupletVerses.Add(leftVerse); var res = LanguageUtils.FindRhyme(coupletVerses, false, true, true); if (string.IsNullOrEmpty(res.Rhyme)) { res = LanguageUtils.FindRhyme(coupletVerses, false, true, false); } DivanPoemSection verseSection = new DivanPoemSection() { PoemId = poem.Id, PoetId = cat.PoetId, SectionType = PoemSectionType.Couplet, VerseType = VersePoemSectionType.Third, Index = index, Number = index + 1, DivanMetreId = poem.DivanMetreId, RhymeLetters = res.Rhyme, DivanMetreRefSectionIndex = mainSection.Index, }; rightVerse.SectionIndex3 = verseSection.Index; leftVerse.SectionIndex3 = verseSection.Index; context.Update(rightVerse); context.Update(leftVerse); var rl = new List(); rl.Add(rightVerse); rl.Add(leftVerse); verseSection.HtmlText = PrepareHtmlText(rl); verseSection.PlainText = PreparePlainText(rl); verseSection.CoupletsCount = rl.Where(v => v.VersePosition == VersePosition.Left || v.VersePosition == VersePosition.CenteredVerse1).Count(); context.Add(verseSection); } } else { bandSection.RhymeLetters = LanguageUtils.FindRhyme(bandVerses).Rhyme; } bandSection.HtmlText = PrepareHtmlText(bandVerses); bandSection.PlainText = PreparePlainText(bandVerses); bandSection.CoupletsCount = bandVerses.Where(v => v.VersePosition == VersePosition.Left || v.VersePosition == VersePosition.CenteredVerse1).Count(); context.Add(mainSection); context.Add(bandSection); context.UpdateRange(nonCommentVerses); } private void _SectionizeNormalVerses(RMuseumDbContext context, List nonCommentVerses, DivanPoem poem, int index, DivanCat cat) { //normal poem DivanPoemSection mainSection = new DivanPoemSection() { PoemId = poem.Id, PoetId = cat.PoetId, SectionType = PoemSectionType.WholePoem, VerseType = VersePoemSectionType.First, Index = index, Number = index + 1, DivanMetreId = poem.DivanMetreId, RhymeLetters = poem.RhymeLetters, HtmlText = PrepareHtmlText(nonCommentVerses), PlainText = PreparePlainText(nonCommentVerses), CoupletsCount = nonCommentVerses.Where(v => v.VersePosition == VersePosition.Left || v.VersePosition == VersePosition.CenteredVerse1).Count(), PoemFormat = DivanPoemFormat.Unknown, }; //checking for مثنوی phase 1 if (string.IsNullOrEmpty(poem.RhymeLetters)) { mainSection.RhymeLetters = LanguageUtils.FindRhyme(nonCommentVerses).Rhyme; mainSection.PoemFormat = DivanPoemFormat.Generic; if (poem.FullTitle.Contains("رباعی")) mainSection.PoemFormat = DivanPoemFormat.Robaee; if (poem.FullTitle.Contains("غزل")) mainSection.PoemFormat = DivanPoemFormat.Ghazal; if (poem.FullTitle.Contains("قص")) mainSection.PoemFormat = DivanPoemFormat.Ghaside; if (poem.FullTitle.Contains("قطع")) mainSection.PoemFormat = DivanPoemFormat.Ghete; } context.Add(mainSection);//having a main section for مثنوی inside normal text helps keep track of related versess foreach (var verse in nonCommentVerses) { verse.SectionIndex1 = mainSection.Index; verse.SectionIndex2 = null;//clear previous indices verse.SectionIndex3 = null;//clear previous indices verse.SectionIndex4 = null;//clear previous indices } index++; //checking for مثنوی phase 2 if (nonCommentVerses.Count > 2 && string.IsNullOrEmpty(mainSection.RhymeLetters)) { if (_IsMasnavi(nonCommentVerses)) { mainSection.PoemFormat = DivanPoemFormat.Masnavi; for (int v = 0; v < nonCommentVerses.Count; v += 2) { index++; var rightVerse = nonCommentVerses[v]; var leftVerse = nonCommentVerses[v + 1]; List coupletVerses = new List(); coupletVerses.Add(rightVerse); coupletVerses.Add(leftVerse); var res = LanguageUtils.FindRhyme(coupletVerses); DivanPoemSection verseSection = new DivanPoemSection() { PoemId = poem.Id, PoetId = cat.PoetId, SectionType = PoemSectionType.Couplet, VerseType = VersePoemSectionType.Second, Index = index, Number = index,//couplet number DivanMetreId = poem.DivanMetreId, RhymeLetters = res.Rhyme, DivanMetreRefSectionIndex = mainSection.Index, }; rightVerse.SectionIndex2 = verseSection.Index; leftVerse.SectionIndex2 = verseSection.Index; var rl = new List(); rl.Add(rightVerse); rl.Add(leftVerse); verseSection.HtmlText = PrepareHtmlText(rl); verseSection.PlainText = PreparePlainText(rl); verseSection.CoupletsCount = rl.Where(v => v.VersePosition == VersePosition.Left || v.VersePosition == VersePosition.CenteredVerse1).Count(); context.Add(verseSection); } } } context.UpdateRange(nonCommentVerses); } /// /// filter secion verses /// /// /// /// public List FilterSectionVerses(DivanPoemSection section, List verses) { List sectionVerses = new List(); foreach (DivanVerse verse in verses) { switch (section.VerseType) { case VersePoemSectionType.First: if (verse.SectionIndex1 == section.Index) sectionVerses.Add(verse); break; case VersePoemSectionType.Second: if (verse.SectionIndex2 == section.Index) sectionVerses.Add(verse); break; case VersePoemSectionType.Third: if (verse.SectionIndex3 == section.Index) sectionVerses.Add(verse); break; default: if (verse.SectionIndex4 == section.Index) sectionVerses.Add(verse); break; } } return sectionVerses; } /// /// get couplet sections /// /// /// /// public async Task> GetCoupletSectionsAsync(int poemId, int coupletIndex) { var firstVerse = await _context.DivanVerses.AsNoTracking().Where(v => v.PoemId == poemId && v.CoupletIndex == coupletIndex).OrderBy(v => v.VOrder).FirstOrDefaultAsync(); if (firstVerse == null) return new RServiceResult(null);//not found try { return new RServiceResult ( await _context.DivanPoemSections.AsNoTracking().Include(s => s.DivanMetre) .Where(s => s.PoemId == poemId && ( s.Index == firstVerse.SectionIndex1 || s.Index == firstVerse.SectionIndex2 || s.Index == firstVerse.SectionIndex3 || s.Index == firstVerse.SectionIndex4 ) ) .OrderBy(s => s.SectionType).ThenBy(s => s.VerseType) .ToArrayAsync() ); } catch (Exception exp) { return new RServiceResult(null, exp.ToString()); } } /// /// get all poem sections /// /// /// public async Task> GetPoemSectionsAsync(int id) { var sections = await _context.DivanPoemSections.AsNoTracking().Include(s => s.DivanMetre).Where(s => s.PoemId == id).OrderBy(s => s.SectionType).ThenBy(s => s.VerseType).ToArrayAsync(); return new RServiceResult(sections); } /// /// regenerate poem sections (dangerous: wipes out existing data) /// /// /// public async Task> RegeneratePoemSections(int id) { LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(_context); var job = (await jobProgressServiceEF.NewJob($"RegeneratePoemSections - {id}", "Query data")).Result; try { var sections = await _context.DivanPoemSections.Where(s => s.PoemId == id).ToListAsync(); int? meterId = sections.Any(s => s.SectionType == PoemSectionType.WholePoem && s.VerseType == VersePoemSectionType.First) ? sections.First(s => s.SectionType == PoemSectionType.WholePoem && s.VerseType == VersePoemSectionType.First).DivanMetreId : null; _context.RemoveRange(sections); await _context.SaveChangesAsync(); var poem = await _context.DivanPoems.Include(p => p.Cat).AsNoTracking().SingleAsync(p => p.Id == id); await _SectionizePoem(_context, poem, jobProgressServiceEF, job, poem.Cat); if (meterId != null) { List rhymes = new List(); var newSections = await _context.DivanPoemSections.Where(s => s.PoemId == id).ToListAsync(); foreach (var section in newSections) { section.DivanMetreId = meterId; if (!string.IsNullOrEmpty(section.RhymeLetters)) { if (!rhymes.Contains(section.RhymeLetters)) { rhymes.Add(section.RhymeLetters); } } } _context.UpdateRange(newSections); await _context.SaveChangesAsync(); if (rhymes.Count > 0) { _backgroundTaskQueue.QueueBackgroundWorkItem ( async token => { using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC { LongRunningJobProgressServiceEF jobProgressServiceEF2 = new LongRunningJobProgressServiceEF(context); var job2 = (await jobProgressServiceEF2.NewJob($"RegeneratePoemSections - Updating related sections", "Query data")).Result; foreach (var rhyme in rhymes) { await _UpdateRelatedSections(context, (int)meterId, rhyme, jobProgressServiceEF2, job2); } } } ); } } await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); return new RServiceResult(true); } catch (Exception exp) { await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); return new RServiceResult(false, exp.ToString()); } } /// /// get a specific poem sections /// /// /// public async Task> GetPoemSectionByIdAsync(int sectionId) { return new RServiceResult ( await _context.DivanPoemSections.AsNoTracking().Include(s => s.DivanMetre).Where(s => s.Id == sectionId).SingleOrDefaultAsync() ); } /// /// delete a poem section /// /// /// /// /// public async Task> DeletePoemSectionByPoemIdAndIndexAsync(int poemId, int sectionIndex, bool convertVerses) { try { var section = await _context.DivanPoemSections.Where(s => s.PoemId == poemId && s.Index == sectionIndex).FirstOrDefaultAsync(); if (section == null) { return new RServiceResult(false);//Not found } var connextedVerses = await _context.DivanVerses .Where ( v => v.PoemId == poemId && (v.SectionIndex1 == sectionIndex || v.SectionIndex2 == sectionIndex || v.SectionIndex3 == sectionIndex || v.SectionIndex4 == sectionIndex) ).ToListAsync(); bool regenPageHtml = false; foreach (var verse in connextedVerses) { if (section.SectionType == PoemSectionType.WholePoem) { if (verse.VersePosition != VersePosition.Paragraph && verse.VersePosition != VersePosition.Comment) { if (convertVerses) { verse.VersePosition = VersePosition.Paragraph; regenPageHtml = true; } else { return new RServiceResult(false, "قطعه شامل مصرع‌های غیرپاراگرافی است."); } } } if (verse.SectionIndex1 == sectionIndex) { verse.SectionIndex1 = null; } if (verse.SectionIndex2 == sectionIndex) { verse.SectionIndex2 = null; } if (verse.SectionIndex3 == sectionIndex) { verse.SectionIndex3 = null; } if (verse.SectionIndex4 == sectionIndex) { verse.SectionIndex4 = null; } } _context.UpdateRange(connextedVerses); _context.Remove(section); await _context.SaveChangesAsync(); if (regenPageHtml) { var poemVerses = await _context.DivanVerses.AsNoTracking().Where(p => p.PoemId == poemId).OrderBy(v => v.VOrder).ToListAsync(); var dbPoem = await _context.DivanPoems.Include(p => p.DivanMetre).Where(p => p.Id == poemId).SingleAsync(); var dbPage = await _context.DivanPages.Where(p => p.Id == poemId).SingleAsync(); dbPoem.HtmlText = PrepareHtmlText(poemVerses); dbPoem.PlainText = PreparePlainText(poemVerses, dbPoem.Title); dbPage.HtmlText = dbPoem.HtmlText; _context.Update(dbPoem); _context.Update(dbPage); await _context.SaveChangesAsync(); } return new RServiceResult(true); } catch (Exception e) { return new RServiceResult(false, e.ToString()); } } /// /// start band couplets fix /// /// public RServiceResult StartOneTimeBandCoupletsFix() { try { _backgroundTaskQueue.QueueBackgroundWorkItem ( async token => { using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC { LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); var job = (await jobProgressServiceEF.NewJob("StartBandCoupletsFix", "Query data")).Result; int progress = 0; try { var sections = await context.DivanPoemSections.Where(s => s.SectionType == PoemSectionType.BandCouplets).ToListAsync(); int count = sections.Count; for (int i = 0; i < count; i++) { progress++; var section = sections[i]; section.OldRhymeLetters = section.RhymeLetters; var verses = await context.DivanVerses.Where(v => v.PoemId == section.PoemId).OrderBy(v => v.VOrder).ToListAsync(); var bandVerses = FilterSectionVerses(section, verses); var resRetry = LanguageUtils.FindRhyme(bandVerses, false, true, true); if (string.IsNullOrEmpty(resRetry.Rhyme)) resRetry = LanguageUtils.FindRhyme(bandVerses, false, true, false); if (!string.IsNullOrEmpty(resRetry.Rhyme) && section.OldRhymeLetters != resRetry.Rhyme) { section.RhymeLetters = resRetry.Rhyme; context.Update(section); await jobProgressServiceEF.UpdateJob(job.Id, progress); if (section.DivanMetreId != null && section.OldRhymeLetters != resRetry.Rhyme) { if (!string.IsNullOrEmpty(section.OldRhymeLetters)) { await _UpdateRelatedSections(context, (int)section.DivanMetreId, section.OldRhymeLetters); } await _UpdateRelatedSections(context, (int)section.DivanMetreId, section.RhymeLetters); } continue; } if (_IsMasnavi(bandVerses, true)) { var poemSections = await context.DivanPoemSections.Where(s => s.PoemId == section.PoemId).ToListAsync(); if (poemSections.Any(s => s.VerseType == VersePoemSectionType.Forth)) continue; var mainSections = poemSections.Where(s => s.SectionType == PoemSectionType.WholePoem && s.VerseType == VersePoemSectionType.First).ToList(); DivanPoemSection mainSection = null; if (mainSections.Count == 1) { mainSection = mainSections.First(); if (mainSection.PoemFormat == DivanPoemFormat.MultiBand) { mainSection.PoemFormat = DivanPoemFormat.TarkibBand; context.Update(mainSection); } } else continue; int index = poemSections.Max(s => s.Index); VersePoemSectionType verseType = poemSections.Any(s => s.VerseType == VersePoemSectionType.Third) ? VersePoemSectionType.Forth : VersePoemSectionType.Third; string preRhymeLetters = ""; for (int v = 0; v < bandVerses.Count; v += 2) { if (bandVerses[v].VersePosition != VersePosition.CenteredVerse1 || bandVerses[v + 1].VersePosition != VersePosition.CenteredVerse2) continue; index++; var rightVerse = bandVerses[v]; var leftVerse = bandVerses[v + 1]; List coupletVerses = new List(); coupletVerses.Add(rightVerse); coupletVerses.Add(leftVerse); var res = LanguageUtils.FindRhyme(coupletVerses); DivanPoemSection verseSection = new DivanPoemSection() { PoemId = section.PoemId, PoetId = section.PoetId, SectionType = PoemSectionType.Couplet, VerseType = verseType, Index = index, Number = index + 1, DivanMetreId = mainSection.DivanMetreId, RhymeLetters = res.Rhyme, DivanMetreRefSectionIndex = mainSection.Index, CachedFirstCoupletIndex = (int)rightVerse.CoupletIndex, }; if (verseType == VersePoemSectionType.Third) { rightVerse.SectionIndex3 = verseSection.Index; leftVerse.SectionIndex3 = verseSection.Index; } else { rightVerse.SectionIndex4 = verseSection.Index; leftVerse.SectionIndex4 = verseSection.Index; } context.Update(rightVerse); context.Update(leftVerse); var rl = new List(); rl.Add(rightVerse); rl.Add(leftVerse); verseSection.HtmlText = PrepareHtmlText(rl); verseSection.PlainText = PreparePlainText(rl); verseSection.CoupletsCount = rl.Where(v => v.VersePosition == VersePosition.Left || v.VersePosition == VersePosition.CenteredVerse1).Count(); context.Add(verseSection); await jobProgressServiceEF.UpdateJob(job.Id, progress); if (verseSection.DivanMetreId != null && !string.IsNullOrEmpty(verseSection.RhymeLetters) && preRhymeLetters != verseSection.RhymeLetters) { preRhymeLetters = verseSection.RhymeLetters; await _UpdateRelatedSections(context, (int)verseSection.DivanMetreId, verseSection.RhymeLetters); } } } } await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); } catch (Exception exp) { await jobProgressServiceEF.UpdateJob(job.Id, progress, "", false, exp.ToString()); } } }); return new RServiceResult(true); } catch (Exception exp) { return new RServiceResult(false, exp.ToString()); } } } }