internal/loader.go (view raw)
1package bible
2
3import (
4 "encoding/json"
5 "os"
6)
7
8// Bible represents the complete Bible data
9type Bible struct {
10 Metadata struct {
11 Name string `json:"name"`
12 Lang string `json:"lang_short"`
13 } `json:"metadata"`
14 Verses []Verse `json:"verses"`
15
16 // Index for quick lookups
17 byBookChapterVerse map[int]map[int]map[int]*Verse
18}
19
20// LoadBible loads Bible data from a JSON file
21func LoadBible(filePath string) (*Bible, error) {
22 data, err := os.ReadFile(filePath)
23 if err != nil {
24 return nil, err
25 }
26
27 var bible Bible
28 if err := json.Unmarshal(data, &bible); err != nil {
29 return nil, err
30 }
31
32 bible.buildIndex()
33 return &bible, nil
34}
35
36// buildIndex creates a lookup index for verses
37func (b *Bible) buildIndex() {
38 b.byBookChapterVerse = make(map[int]map[int]map[int]*Verse)
39
40 for i := range b.Verses {
41 verse := &b.Verses[i]
42
43 if b.byBookChapterVerse[verse.Book] == nil {
44 b.byBookChapterVerse[verse.Book] = make(map[int]map[int]*Verse)
45 }
46
47 if b.byBookChapterVerse[verse.Book][verse.Chapter] == nil {
48 b.byBookChapterVerse[verse.Book][verse.Chapter] = make(map[int]*Verse)
49 }
50
51 b.byBookChapterVerse[verse.Book][verse.Chapter][verse.VerseNum] = verse
52 }
53}
54
55// GetVerse retrieves a specific verse
56func (b *Bible) GetVerse(book, chapter, verse int) (*Verse, bool) {
57 if chapterMap, ok := b.byBookChapterVerse[book]; ok {
58 if verseMap, ok := chapterMap[chapter]; ok {
59 if verse, ok := verseMap[verse]; ok {
60 return verse, true
61 }
62 }
63 }
64 return nil, false
65}
66
67// GetChapterText retrieves the full text of a chapter
68func (b *Bible) GetChapterText(book, chapter int) string {
69 if chapterMap, ok := b.byBookChapterVerse[book]; ok {
70 if verseMap, ok := chapterMap[chapter]; ok {
71 var text string
72 // We need to get verses in order
73 // Since we don't know the max verse number, we'll iterate
74 // This could be optimized but works for now
75 for i := 1; ; i++ {
76 if verse, ok := verseMap[i]; ok {
77 text += verse.Text + " "
78 } else {
79 break
80 }
81 }
82 return text
83 }
84 }
85 return ""
86}
87
88// CountVersesInChapter returns the number of verses in a chapter
89func (b *Bible) CountVersesInChapter(book, chapter int) int {
90 if chapterMap, ok := b.byBookChapterVerse[book]; ok {
91 if verseMap, ok := chapterMap[chapter]; ok {
92 return len(verseMap)
93 }
94 }
95 return 0
96}
97
98// GetVerseRange retrieves verses in a range
99func (b *Bible) GetVerseRange(book, chapter, firstVerse, lastVerse int) []*Verse {
100 var verses []*Verse
101
102 if chapterMap, ok := b.byBookChapterVerse[book]; ok {
103 if verseMap, ok := chapterMap[chapter]; ok {
104 for i := firstVerse; i <= lastVerse; i++ {
105 if verse, ok := verseMap[i]; ok {
106 verses = append(verses, verse)
107 }
108 }
109 }
110 }
111
112 return verses
113}