package main import ( "bufio" "encoding/json" "errors" "fmt" "os" "path/filepath" "strconv" "strings" "time" ) var readingsFilename string func init() { // Get user's homeDir directory homeDir, err := os.UserHomeDir() if err != nil { fmt.Println("Error fetching user's home directory:", err) os.Exit(1) } // Define the path to the application data directory ketotrackDir := filepath.Join(homeDir, ".ketotrack") // Create the directory if it does not exist err = os.MkdirAll(ketotrackDir, 0770) if err != nil { fmt.Println("Error creating .ketotrack directory:", err) os.Exit(1) } // Set data file path for readings readingsFilename = filepath.Join(ketotrackDir, "readings.json") } // Record holds a pointer to a Reading or Note. type Record struct { Reading *Reading `json:"reading,omitempty"` Note *Note `json:"note,omitempty"` } // Note holds a text note along with the time the note was taken. type Note struct { Time time.Time `json:"time"` Text string `json:"text"` } // Reading holds the glucose and ketone level measurements along with the time the measurements were taken. type Reading struct { Time time.Time `json:"time"` Glucose float64 `json:"glucose"` Ketone float64 `json:"ketone"` GKI float64 `json:"GKI"` } // NewReading creates and returns a new Reading instance with the provided glucose and ketone levels, and records // the current time. The glucose value should be provided in mg/dL, while the ketone level should be in mmol/L. func NewReading(glucose, ketone float64) Reading { var gki float64 if ketone == 0 { gki = 0 } else { gki = (glucose / 18) / ketone } return Reading{ Time: time.Now(), Glucose: glucose, Ketone: ketone, GKI: gki, } } // AppContext is the application data store that holds Records type AppContext struct { Records []Record } // LoadRecords will load records from file func (ctx *AppContext) LoadRecords(filename string) error { data, err := os.ReadFile(filename) if err != nil { return err } return json.Unmarshal(data, &ctx.Records) } // SaveRecords will save records to a file func (ctx *AppContext) SaveRecords(filename string) error { jsonData, err := json.Marshal(ctx.Records) if err != nil { return err } return os.WriteFile(filename, jsonData, 0660) } // AddReading will add a Reading to the AppContext func (ctx *AppContext) AddReading(reading Reading) { ctx.Records = append(ctx.Records, Record{Reading: &reading}) } // AddNote will a add a Note to the AppContext func (ctx *AppContext) AddNote(note Note) { ctx.Records = append(ctx.Records, Record{Note: ¬e}) } func main() { // Take a new reading from the user reading, err := getReading() if err != nil { fmt.Println(err.Error()) return } // Calculate GKI //gki, err := reading.GKI() //if err != nil { // fmt.Println(err.Error()) // fmt.Println("You are not in ketosis.") // return //} // Display GKI and level of ketosis fmt.Printf("\nYour GKI is: %0.2f\n", reading.GKI) switch { case reading.GKI <= 1: fmt.Println("You're in the highest level of ketosis.") case reading.GKI < 3: fmt.Println("You're in a high therapeutic level of ketosis.") case reading.GKI < 6: fmt.Println("You're in a moderate level of ketosis.") case reading.GKI <= 9: fmt.Println("You're in a low level of ketosis.") default: fmt.Println("You are not in ketosis.") } // Save latest reading to readings file readings, _ := loadReadingsFromFile(readingsFilename) readings = append(readings, reading) err = saveReadingsToFile(readingsFilename, readings) if err != nil { fmt.Printf("error saving data: %s\n", err.Error()) } } func saveReadingsToFile(filename string, data []Reading) error { jsonData, err := json.Marshal(data) if err != nil { return err } return os.WriteFile(filename, jsonData, 0660) } func loadReadingsFromFile(filename string) ([]Reading, error) { data, err := os.ReadFile(filename) if err != nil { return nil, err } var readings []Reading err = json.Unmarshal(data, &readings) if err != nil { return nil, err } return readings, nil } func getReading() (Reading, error) { // Get glucose reading glucose, err := getUserFloat("Enter glucose reading (mg/dL)") if err != nil { return Reading{}, fmt.Errorf("error getting glucose reading: %w", err) } // Validate glucose reading if glucose <= 0 { return Reading{}, errors.New("glucose reading cannot be less than or equal to 0") } // Get ketone reading ketone, err := getUserFloat("Enter ketone reading (mmol/L)") if err != nil { return Reading{}, fmt.Errorf("error getting ketone reading: %w", err) } // Validate ketone reading if ketone < 0 { fmt.Println("") return Reading{}, errors.New("ketone reading cannot be less than 0") } return NewReading(glucose, ketone), nil } func getUserInput(prompt string) (string, error) { fmt.Printf("%s: ", prompt) reader := bufio.NewReader(os.Stdin) input, err := reader.ReadString('\n') if err != nil { return "", err } return strings.TrimSpace(input), nil } func getUserFloat(prompt string) (float64, error) { // Get input as a string s, err := getUserInput(prompt) if err != nil { return 0, err } // Convert string to float f, err := strconv.ParseFloat(s, 64) if err != nil { return 0, err } return f, nil }