ProfileManager.swift 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. //
  2. // ProfileManager.swift
  3. // LoopFollow
  4. //
  5. // Created by Jonas Björkert on 2024-07-12.
  6. // Copyright © 2024 Jon Fawcett. All rights reserved.
  7. //
  8. import Foundation
  9. struct ProfileManager {
  10. var isfSchedule: [TimeValue]
  11. var basalSchedule: [TimeValue]
  12. var carbRatioSchedule: [TimeValue]
  13. var overrides: [Override]
  14. var units: String
  15. var timezone: String
  16. var defaultProfile: String
  17. struct TimeValue {
  18. let timeAsSeconds: Int
  19. let value: Double
  20. }
  21. struct Override {
  22. let name: String
  23. let targetRange: [Double]
  24. let duration: Int
  25. let insulinNeedsScaleFactor: Double
  26. let symbol: String
  27. }
  28. init() {
  29. // Initialize with default values
  30. self.isfSchedule = []
  31. self.basalSchedule = []
  32. self.carbRatioSchedule = []
  33. self.overrides = []
  34. self.units = "mmol/L"
  35. self.timezone = "UTC"
  36. self.defaultProfile = ""
  37. }
  38. mutating func loadProfile(from profileData: NSProfile) {
  39. guard let store = profileData.store["default"] ?? profileData.store["Default"] else {
  40. return
  41. }
  42. self.units = profileData.units
  43. self.timezone = store.timezone
  44. self.defaultProfile = profileData.defaultProfile
  45. self.isfSchedule = store.sens.map { TimeValue(timeAsSeconds: Int($0.timeAsSeconds), value: $0.value) }
  46. self.basalSchedule = store.basal.map { TimeValue(timeAsSeconds: Int($0.timeAsSeconds), value: $0.value) }
  47. self.carbRatioSchedule = store.carbratio.map { TimeValue(timeAsSeconds: Int($0.timeAsSeconds), value: $0.value) }
  48. if let overrides = store.overrides {
  49. self.overrides = overrides.map { Override(name: $0.name ?? "", targetRange: $0.targetRange ?? [], duration: $0.duration ?? 0, insulinNeedsScaleFactor: $0.insulinNeedsScaleFactor ?? 1.0, symbol: $0.symbol ?? "") }
  50. } else {
  51. self.overrides = []
  52. }
  53. }
  54. func currentISF() -> String? {
  55. if let isf = getCurrentValue(from: isfSchedule) {
  56. return Localizer.formatLocalDouble(isf, unit: self.units)
  57. }
  58. return nil
  59. }
  60. func currentBasal() -> String? {
  61. if let basal = getCurrentValue(from: basalSchedule) {
  62. return Localizer.formatToLocalizedString(basal, maxFractionDigits: 2, minFractionDigits: 0)
  63. }
  64. return nil
  65. }
  66. func currentCarbRatio() -> String? {
  67. if let carbRatio = getCurrentValue(from: carbRatioSchedule) {
  68. return Localizer.formatToLocalizedString(carbRatio)
  69. }
  70. return nil
  71. }
  72. private func getCurrentValue(from schedule: [TimeValue]) -> Double? {
  73. guard !schedule.isEmpty else { return nil }
  74. let now = Date()
  75. let calendar = Calendar.current
  76. let currentTimeInSeconds = calendar.component(.hour, from: now) * 3600 +
  77. calendar.component(.minute, from: now) * 60 +
  78. calendar.component(.second, from: now)
  79. var lastValue: Double?
  80. for timeValue in schedule {
  81. if currentTimeInSeconds >= timeValue.timeAsSeconds {
  82. lastValue = timeValue.value
  83. } else {
  84. break
  85. }
  86. }
  87. return lastValue
  88. }
  89. private func formatValue(_ value: Double) -> String {
  90. if units == "mg/dL" {
  91. return String(format: "%.0f", value)
  92. } else {
  93. return String(format: "%.2f", value)
  94. }
  95. }
  96. mutating func clear() {
  97. self.isfSchedule = []
  98. self.basalSchedule = []
  99. self.carbRatioSchedule = []
  100. self.overrides = []
  101. self.units = "mmol/L"
  102. self.timezone = "UTC"
  103. self.defaultProfile = ""
  104. }
  105. }