package caldata import ( "sort" "time" "github.com/lukaszkasprzak/lectio/internal/calendar" ) var partOrder = map[string]int{"first": 0, "psalm": 1, "second": 2, "acclamation": 3, "gospel": 4} // ofFerial returns the day's Ordinary-Form ferial (weekday) readings, or nil. func ofFerial(sel calendar.Selection, date time.Time, day calendar.LiturgicalDay) []calendar.Reading { if day.WeekdayCycle == "" || date.Weekday() == time.Sunday { return nil } if temp := calendar.Compute(date, sel, nil); temp.Observed.Layer == "temporal" { return TemporalReadings("new", temp.Observed.Slug+"-"+day.WeekdayCycle) } return nil } // Readings resolves a day's Mass readings: the observed celebration's inline // propers, else the temporal lectionary for its slug, else -- for an EF // weekday with no proper Mass -- the preceding Sunday's Mass (the 1962 rule // that green-season ferias repeat the Sunday). Shared by the CLI (cli.dayReadings // delegates here) and calfeed.Build (injected as its readings func). func Readings(sel calendar.Selection, layers []calendar.Layer, date time.Time, day calendar.LiturgicalDay) []calendar.Reading { var rs []calendar.Reading for _, m := range day.Observed.Masses { rs = append(rs, m.Readings...) } if len(rs) > 0 { // OF: a memorial with only a PROPER gospel (or only a proper first) takes // the missing reading from the day's ferial -- e.g. the Guardian Angels are // the ferial first reading + their proper gospel (Matt 18), and St Barnabas // is his proper first (Acts 11) + the ferial gospel. A fully-proper feast // (first AND gospel present) is left untouched. have := map[string]bool{} for _, r := range rs { have[r.Part] = true } if sel.Form != "old" && !(have["first"] && have["gospel"]) { for _, fr := range ofFerial(sel, date, day) { if p := fr.Part; !have[p] && (p == "first" || p == "psalm" || p == "gospel") { rs = append(rs, fr) have[p] = true } } sort.SliceStable(rs, func(i, j int) bool { return partOrder[rs[i].Part] < partOrder[rs[j].Part] }) } return rs } // temporal table: EF by bare slug; OF by slug+cycle. Sundays & solemnities // use the 3-year Sunday cycle (A/B/C); ferial weekdays use the 2-year // weekday cycle (I/II). Sunday-slugs and weekday-slugs are disjoint, so // trying both cycle suffixes is unambiguous. if sel.Form == "old" { if r := TemporalReadings("old", day.Observed.Slug); len(r) > 0 { return r } } else { for _, cyc := range []string{day.SundayCycle, day.WeekdayCycle} { if cyc == "" { continue } if r := TemporalReadings("new", day.Observed.Slug+"-"+cyc); len(r) > 0 { return r } } } // OF: a sanctoral memorial / optional memorial with no proper readings of its // own reads the FERIAL (weekday) readings of the day -- the ordinary OF rule. if sel.Form != "old" && day.Observed.Layer != "temporal" { if r := ofFerial(sel, date, day); len(r) > 0 { return r } } // EF: a green-season weekday with no proper Mass repeats the preceding Sunday. if sel.Form == "old" && day.Observed.Layer == "temporal" && date.Weekday() != time.Sunday { sun := date.AddDate(0, 0, -int(date.Weekday())) // preceding Sunday (Sunday = 0) sd := calendar.Compute(sun, sel, layers) return TemporalReadings(sel.Form, sd.Observed.Slug) } return nil }