156 lines
6.5 KiB
Swift
156 lines
6.5 KiB
Swift
//
|
|
// TreatmentNSResponse.swift
|
|
// xdrip
|
|
//
|
|
// Created by Eduardo Pietre on 11/01/22.
|
|
// Copyright © 2022 Johan Degraeve. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import CoreData
|
|
|
|
/// Class that represents the Nightscout response for adding a single new treatment.
|
|
///
|
|
/// NS API docs states:
|
|
/// "The client should not create the identifier, the server automatically assigns it when the document is inserted."
|
|
public struct TreatmentNSResponse {
|
|
|
|
/// id received from NightScout , incusive the extension "-insulin", "-carbs" or "-exercise"
|
|
public let id: String
|
|
|
|
public let createdAt: Date
|
|
|
|
/// - eventType either insulin, carbs or exercise
|
|
/// - only used internally in the app
|
|
public let eventType: TreatmentType
|
|
|
|
/// - eventType received from NightScout (for downloaded treatments) or uploaded to NightScout (for treatments created in xdrip4ios)
|
|
public let nightscoutEventType: String?
|
|
|
|
public let value: Double
|
|
|
|
/// Takes a NSDictionary from nightscout response and returns an array TreatmentNSResponse. Can be more than one, eg NightScout treatment of type 'Snack Bolus' could contain an insulin value and a carbs value
|
|
///
|
|
/// id will be the id retrieved from nightscout + "-insulin", "-carbs", "-exercise", according to treatment type
|
|
public static func fromNightscout(dictionary: NSDictionary) -> [TreatmentNSResponse] {
|
|
|
|
var treatmentNSResponses: [TreatmentNSResponse] = []
|
|
|
|
// we need this to be optional in case the created_at string cannot be transformed successfully into a valid date
|
|
var nightscoutDate: Date?
|
|
|
|
if let createdAt = dictionary["created_at"] as? String {
|
|
|
|
let dateFormatter = DateFormatter()
|
|
|
|
// add the locale and timeZone properties as per dateFromISOString()
|
|
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
|
dateFormatter.timeZone = TimeZone(abbreviation: "GMT")
|
|
|
|
// let's check which date format is return by Nightscout and deal with it accordingly
|
|
// if the date string contains a decimal point, then it must contain milliseconds
|
|
// if we don't take this into account, .date(from: string) will be returned as nil if the milliseconds (.SSS) are missing
|
|
if createdAt.contains(".") {
|
|
|
|
// this is the way Loop, FreeAPS (Loop), OpenAPS and FreeAPS X store the created_at date/time
|
|
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
|
|
|
|
} else {
|
|
|
|
// and AndroidAPS stores it without milliseconds
|
|
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
|
|
|
|
}
|
|
|
|
// assign the date to the optional nightscoutDate
|
|
nightscoutDate = dateFormatter.date(from: createdAt)
|
|
|
|
}
|
|
|
|
// first check that _id exists and that created_at was successfully converted into a Date
|
|
if let id = dictionary["_id"] as? String, let date = nightscoutDate {
|
|
|
|
// retrieve nightScoutEventType from the nightscout response
|
|
// if not present then it's set to nil (it should be present)
|
|
let nightScoutEventType: String? = dictionary["eventType"] as? String
|
|
|
|
if let carbs = dictionary["carbs"] as? Double {
|
|
|
|
treatmentNSResponses.append(TreatmentNSResponse(id: id + TreatmentType.Carbs.idExtension(), createdAt: date, eventType: .Carbs, nightscoutEventType: nightScoutEventType, value: carbs))
|
|
|
|
}
|
|
|
|
if let insulin = dictionary["insulin"] as? Double {
|
|
|
|
treatmentNSResponses.append(TreatmentNSResponse(id: id + TreatmentType.Insulin.idExtension(), createdAt: date, eventType: .Insulin, nightscoutEventType: nightScoutEventType, value: insulin))
|
|
|
|
}
|
|
|
|
if nightScoutEventType == "Exercise", let duration = dictionary["duration"] as? Double {
|
|
|
|
treatmentNSResponses.append(TreatmentNSResponse(id: id + TreatmentType.Carbs.idExtension(), createdAt: date, eventType: .Exercise, nightscoutEventType: nightScoutEventType, value: duration))
|
|
|
|
}
|
|
|
|
if let glucose = dictionary["glucose"] as? Double, let units = dictionary["units"] as? String {
|
|
|
|
treatmentNSResponses.append(TreatmentNSResponse(id: id + TreatmentType.BgCheck.idExtension(), createdAt: date, eventType: .BgCheck, nightscoutEventType: nightScoutEventType, value: units == "mg/dl" ? glucose : glucose.mmolToMgdl()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return treatmentNSResponses
|
|
|
|
}
|
|
|
|
/// Instantiates multiples TreatmentNSResponse from a NSArray of NSDictionary.
|
|
public static func arrayFromNSArray(_ array: NSArray) -> [TreatmentNSResponse] {
|
|
|
|
var responses: [TreatmentNSResponse] = []
|
|
|
|
for element in array {
|
|
if let dictionary = element as? NSDictionary {
|
|
|
|
responses = responses + TreatmentNSResponse.fromNightscout(dictionary: dictionary)
|
|
|
|
}
|
|
}
|
|
|
|
return responses
|
|
|
|
}
|
|
|
|
/// Instantiates multiples TreatmentNSResponse from Data response.
|
|
///
|
|
/// JSONSerialization may throw an exception.
|
|
public static func arrayFromData(_ data: Data?) throws -> [TreatmentNSResponse]? {
|
|
|
|
if let data = data, let array = try JSONSerialization.jsonObject(with: data, options: []) as? NSArray {
|
|
|
|
return TreatmentNSResponse.arrayFromNSArray(array)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
/// Compares this TreatmentNSResponse to a given TreatmentEntry
|
|
public func matchesTreatmentEntry(_ entry: TreatmentEntry) -> Bool {
|
|
|
|
return entry.date.toMillisecondsAsInt64() == self.createdAt.toMillisecondsAsInt64() && entry.treatmentType == self.eventType && entry.value == self.value
|
|
|
|
}
|
|
|
|
/// Converts self (TreatmentNSResponse) to TreatmentEntry and creates a TreatmentEntry
|
|
///
|
|
/// Be extra carefull when creating new TreatmentEntry, will create the new entry in CoreData but does not save in CoreData
|
|
public func asNewTreatmentEntry(nsManagedObjectContext: NSManagedObjectContext) -> TreatmentEntry? {
|
|
|
|
return TreatmentEntry(id: id, date: createdAt, value: value, treatmentType: eventType, nightscoutEventType: nightscoutEventType, nsManagedObjectContext: nsManagedObjectContext)
|
|
|
|
}
|
|
|
|
}
|