package org.nightscout.lasso.alarm.ar2;
import android.content.Context;
import android.util.Log;
import com.nightscout.core.dexcom.records.EGVRecord;
import com.nightscout.core.model.GlucoseUnit;
import org.joda.time.DateTime;
import org.joda.time.Hours;
import org.joda.time.Minutes;
import org.nightscout.lasso.BuildConfig;
import org.nightscout.lasso.R;
import org.nightscout.lasso.alarm.AlarmResults;
import org.nightscout.lasso.alarm.AlarmSeverity;
import org.nightscout.lasso.alarm.AlarmStrategy;
import java.util.List;
public class Ar2 implements AlarmStrategy {
public static final int BG_REF = 140;
public static final int BG_MIN = 36;
public static final int BG_MAX = 400;
public static final double WARN_THRESHOLD = 0.05;
public static final double URGENT_THRESHOLD = 0.10;
private Context context;
public Ar2(Context context) {
this.context = context;
Log.d(this.getClass().getSimpleName(), "Initialized");
}
private Ar2Result forecast(List<EGVRecord> sgvs) {
Ar2Result result = new Ar2Result();
if (sgvs.size() < 2) {
return new Ar2Result();
}
if (sgvs.get(sgvs.size() - 1).getBgMgdl() > 39 && sgvs.get(sgvs.size() - 2).getBgMgdl() > 39) {
int lastIndex = sgvs.size() - 1;
DateTime lastValidReadingTime = sgvs.get(lastIndex).getWallTime();
long ONE_MINUTE = Minutes.minutes(1).toStandardDuration().getMillis();
double elapsedTime = (sgvs.get(lastIndex).getWallTime().getMillis() - sgvs.get(lastIndex - 1).getWallTime().getMillis()) / ONE_MINUTE;
double y = Math.log((double) sgvs.get(lastIndex).getBgMgdl() / (double) BG_REF);
double[] yPair = {y, y};
if (elapsedTime < 5.1) {
yPair = new double[]{Math.log((double) sgvs.get(lastIndex - 1).getBgMgdl() / (double) BG_REF), y};
}
long ONE_HOUR = Hours.ONE.toStandardDuration().getMillis();
Long currentTimelong = new DateTime().getMillis();
Long lastValidReadingTimeLong = lastValidReadingTime.getMillis();
double n = Math.ceil(12 * (0.5d + (double) (currentTimelong - lastValidReadingTimeLong) / (double) ONE_HOUR));
double[] AR = {-0.723, 1.716};
DateTime dt = lastValidReadingTime;
for (int i = 0; i <= n; i++) {
yPair = new double[]{yPair[1], AR[0] * yPair[0] + AR[1] * yPair[1]};
dt = dt.plus(Minutes.minutes(5));
BGPoint point = new BGPoint(dt, Math.max(BG_MIN, Math.min(BG_MAX, Math.round(BG_REF * Math.exp(yPair[1])))));
result.predicted.add(point);
}
long size = Math.min(result.predicted.size() - 1, 6);
for (int j = 0; j <= size; j++) {
result.avgLoss += 1 / (double) size * Math.pow(Math.log10((double) result.predicted.get(j).y / (double) 120), 2);
}
}
Log.e("AR2", "Results: avgLoss=" + result.avgLoss);
int count = 0;
for (BGPoint bgPoint : result.predicted) {
if (BuildConfig.DEBUG) {
Log.e("AR2", "Results: Predicted #" + count + "=" + bgPoint.y + " by " + bgPoint.x);
}
count += 1;
}
return result;
}
@Override
public AlarmResults analyze(List<EGVRecord> egvRecords, GlucoseUnit unit) {
if (egvRecords.size() == 0) {
throw new IllegalArgumentException("No records to analyze");
}
AlarmResults alarmResults = new AlarmResults();
EGVRecord lastEgvRecord = egvRecords.get(egvRecords.size() - 1);
Ar2Result ar2Results = forecast(egvRecords);
alarmResults.message = context.getString(R.string.alarm_notification_urgent_body,
lastEgvRecord.getReading().asStr(unit),
lastEgvRecord.getTrend().symbol());
if (ar2Results.avgLoss > URGENT_THRESHOLD) {
Log.w("Alarm", "Urgent alarm");
alarmResults.severity = AlarmSeverity.URGENT;
alarmResults.title = context.getString(R.string.alarm_notification_urgent_title, context.getString(R.string.app_name));
} else if (ar2Results.avgLoss > WARN_THRESHOLD) {
Log.w("Alarm", "Warning");
alarmResults.severity = AlarmSeverity.WARNING;
alarmResults.title = context.getString(R.string.alarm_notification_warning_title, context.getString(R.string.app_name));
} else {
Log.w("Alarm", "All is good");
alarmResults.severity = AlarmSeverity.NONE;
alarmResults.title = context.getString(R.string.alarm_notification_normal_title, context.getString(R.string.app_name));
}
return alarmResults;
}
}