all repos — bibel @ c045b445fe953f81a929780728841400a44ce422

Unnamed repository; edit this file 'description' to name the repository.

internal/loader.go (view raw)

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