package org.glucosio.android.tools;
import android.content.Context;
import android.support.annotation.NonNull;
import org.glucosio.android.object.GlucoseData;
import org.glucosio.android.object.PredictionData;
import org.glucosio.android.object.ReadingData;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class AlgorithmUtil {
private static final double TREND_UP_DOWN_LIMIT = 1;
private static final double TREND_SLIGHT_UP_DOWN_LIMIT = 0.5;
public enum TrendArrow {
UNKNOWN,
DOWN,
SLIGHTLY_DOWN,
FLAT,
SLIGHTLY_UP,
UP
}
public enum Danger {
HIGH,
LOW,
NOTHING
}
private static final int MINUTE = 60000;
// TODO: 15 a good value?
private static final int PREDICTION_TIME = 15;
private static final SimpleDateFormat mFormat = new SimpleDateFormat("HH:mm:ss");
public static String format(Date date) {
return mFormat.format(date);
}
private static int getGlucose(byte[] bytes) {
return (int)Math.round(((256 * (bytes[0] & 0xFF) + (bytes[1] & 0xFF)) & 0x0FFF) / 8.5);
}
public interface AlertRule {
enum AlertResult {
INVALID,
NO_ALERTS,
NOTHING,
ALERT_HIGH,
ALERT_LOW,
}
AlertResult doFilter(Context context, GlucoseData prediction);
}
public static TrendArrow getTrendArrow(Context context, GlucoseData data) {
if (data instanceof PredictionData) {
PredictionData predictionData = (PredictionData) data;
// TODO: Check what confidenceLimit is;
float confidenceLimit = 1;
if (predictionData.confidence > confidenceLimit) {
return TrendArrow.UNKNOWN;
} else {
if (predictionData.trend > TREND_UP_DOWN_LIMIT) {
return TrendArrow.UP;
} else if (predictionData.trend < -TREND_UP_DOWN_LIMIT) {
return TrendArrow.DOWN;
} else if (predictionData.trend > TREND_SLIGHT_UP_DOWN_LIMIT) {
return TrendArrow.SLIGHTLY_UP;
} else if (predictionData.trend < -TREND_SLIGHT_UP_DOWN_LIMIT) {
return TrendArrow.SLIGHTLY_DOWN;
} else {
return TrendArrow.FLAT;
}
}
} else {
return TrendArrow.UNKNOWN;
}
}
public static Danger danger(Context context, PredictionData data, List<AlertRule> rules) {
if (data.glucoseLevel < 10) return Danger.NOTHING;
Danger danger = Danger.NOTHING;
for (AlertRule rule : rules) {
AlertRule.AlertResult result = rule.doFilter(context, data);
switch (result) {
case ALERT_HIGH:
danger = Danger.HIGH;
break;
case ALERT_LOW:
danger = Danger.LOW;
break;
case NO_ALERTS:
return Danger.NOTHING;
}
}
return danger;
}
public static ReadingData parseData(int attempt, String tagId, byte[] data) {
long watchTime = System.currentTimeMillis();
int indexTrend = data[26] & 0xFF;
int indexHistory = data[27] & 0xFF;
final int sensorTime = 256 * (data[317] & 0xFF) + (data[316] & 0xFF);
long sensorStartTime = watchTime - sensorTime * MINUTE;
ArrayList<GlucoseData> historyList = new ArrayList<>();
// loads history values (ring buffer, starting at index_trent. byte 124-315)
for (int index = 0; index < 32; index++) {
int i = indexHistory - index - 1;
if (i < 0) i += 32;
GlucoseData glucoseData = new GlucoseData();
glucoseData.glucoseLevel =
getGlucose(new byte[]{data[(i * 6 + 125)], data[(i * 6 + 124)]});
int time = Math.max(0, Math.abs((sensorTime - 3) / 15) * 15 - index * 15);
glucoseData.realDate = sensorStartTime + time * MINUTE;
glucoseData.sensorId = tagId;
glucoseData.sensorTime = time;
historyList.add(glucoseData);
}
ArrayList<GlucoseData> trendList = new ArrayList<>();
// loads trend values (ring buffer, starting at index_trent. byte 28-123)
for (int index = 0; index < 16; index++) {
int i = indexTrend - index - 1;
if (i < 0) i += 16;
GlucoseData glucoseData = new GlucoseData();
glucoseData.glucoseLevel =
getGlucose(new byte[]{data[(i * 6 + 29)], data[(i * 6 + 28)]});
int time = Math.max(0, sensorTime - index);
glucoseData.realDate = sensorStartTime + time * MINUTE;
glucoseData.sensorId = tagId;
glucoseData.sensorTime = time;
trendList.add(glucoseData);
}
PredictionData predictedGlucose = getPredictionData(attempt, tagId, trendList);
return new ReadingData(predictedGlucose, trendList, historyList);
}
@NonNull
private static PredictionData getPredictionData(int attempt, String tagId, ArrayList<GlucoseData> trendList) {
PredictionData predictedGlucose = new PredictionData();
/* SimpleRegression regression = new SimpleRegression();
for (int i = 0; i < trendList.size(); i++) {
regression.addData(trendList.size() - i, (trendList.get(i)).glucoseLevel);
}
predictedGlucose.glucoseLevel = (int)regression.predict(15 + PREDICTION_TIME);
predictedGlucose.trend = regression.getSlope();
predictedGlucose.confidence = regression.getSlopeConfidenceInterval();*/
predictedGlucose.errorCode = PredictionData.Result.OK;
predictedGlucose.realDate = trendList.get(0).realDate;
predictedGlucose.sensorId = tagId;
predictedGlucose.attempt = attempt;
predictedGlucose.sensorTime = trendList.get(0).sensorTime;
return predictedGlucose;
}
}