package info.nightscout.androidaps.plugins.TempBasals; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.annotation.Nullable; import com.j256.ormlite.dao.Dao; import com.squareup.otto.Subscribe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.db.TempBasal; import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventTempBasalChange; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.TempBasalsInterface; import info.nightscout.androidaps.data.IobTotal; /** * Created by mike on 05.08.2016. */ public class TempBasalsPlugin implements PluginBase, TempBasalsInterface { private static Logger log = LoggerFactory.getLogger(TempBasalsPlugin.class); public static long lastCalculationTimestamp = 0; public static IobTotal lastCalculation; private static List<TempBasal> tempBasals; private static List<TempBasal> extendedBoluses; private static boolean useExtendedBoluses = false; private static boolean fragmentEnabled = true; private static boolean fragmentVisible = true; public TempBasalsPlugin() { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); useExtendedBoluses = sharedPreferences.getBoolean("danar_useextended", false); initializeData(); MainApp.bus().register(this); } @Override public String getFragmentClass() { return TempBasalsFragment.class.getName(); } @Override public String getName() { return MainApp.instance().getString(R.string.tempbasals); } @Override public String getNameShort() { String name = MainApp.sResources.getString(R.string.tempbasals_shortname); if (!name.trim().isEmpty()){ //only if translation exists return name; } // use long name as fallback return getName(); } @Override public boolean isEnabled(int type) { return type == TEMPBASAL && fragmentEnabled && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable; } @Override public boolean isVisibleInTabs(int type) { return type == TEMPBASAL && fragmentVisible && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable; } @Override public boolean canBeHidden(int type) { return true; } @Override public void setFragmentEnabled(int type, boolean fragmentEnabled) { if (type == TEMPBASAL) this.fragmentEnabled = fragmentEnabled; } @Override public void setFragmentVisible(int type, boolean fragmentVisible) { if (type == TEMPBASAL) this.fragmentVisible = fragmentVisible; } @Override public int getType() { return PluginBase.TEMPBASAL; } private void initializeData() { double dia = 3; if (MainApp.getConfigBuilder().getActiveProfile() != null && MainApp.getConfigBuilder().getActiveProfile().getProfile() != null) dia = MainApp.getConfigBuilder().getActiveProfile().getProfile().getDia(); long fromMills = (long) (new Date().getTime() - 60 * 60 * 1000L * (24 + dia)); tempBasals = MainApp.getDbHelper().getTempbasalsDataFromTime(fromMills, false, false); extendedBoluses = MainApp.getDbHelper().getTempbasalsDataFromTime(fromMills, false, true); // Update ended checkForExpiredExtended(); checkForExpiredTemps(); } public void checkForExpiredTemps() { checkForExpired(tempBasals); } public void checkForExpiredExtended() { checkForExpired(extendedBoluses); } private void checkForExpired(List<TempBasal> list) { long now = new Date().getTime(); for (int position = list.size() - 1; position >= 0; position--) { TempBasal t = list.get(position); boolean update = false; if (t.timeEnd == null && t.getPlannedTimeEnd().getTime() < now) { t.timeEnd = new Date(t.getPlannedTimeEnd().getTime()); if (Config.logTempBasalsCut) log.debug("Add timeEnd to old record"); update = true; } if (position > 0) { Date startofnewer = list.get(position - 1).timeStart; if (t.timeEnd == null) { t.timeEnd = new Date(Math.min(startofnewer.getTime(), t.getPlannedTimeEnd().getTime())); if (Config.logTempBasalsCut) log.debug("Add timeEnd to old record"); update = true; } else if (t.timeEnd.getTime() > startofnewer.getTime()) { t.timeEnd = startofnewer; update = true; } } if (update) { try { Dao<TempBasal, Long> dao = MainApp.getDbHelper().getDaoTempBasals(); dao.update(t); } catch (SQLException e) { e.printStackTrace(); } if (Config.logTempBasalsCut) { log.debug("Fixing unfinished temp end: " + t.log()); if (position > 0) log.debug("Previous: " + list.get(position - 1).log()); } } } } /* * Recalculate IOB if value is older than 1 minute */ public void updateTotalIOBIfNeeded() { if (lastCalculationTimestamp > new Date().getTime() - 60 * 1000) return; updateTotalIOB(); } @Override public IobTotal getLastCalculation() { return lastCalculation; } @Override public IobTotal getCalculationToTime(long time) { checkForExpired(tempBasals); checkForExpired(extendedBoluses); Date now = new Date(time); IobTotal total = new IobTotal(time); for (Integer pos = 0; pos < tempBasals.size(); pos++) { TempBasal t = tempBasals.get(pos); if (t.timeStart.getTime() > time) continue; IobTotal calc = t.iobCalc(now); total.plus(calc); } if (useExtendedBoluses) { for (Integer pos = 0; pos < extendedBoluses.size(); pos++) { TempBasal t = extendedBoluses.get(pos); if (t.timeStart.getTime() > time) continue; IobTotal calc = t.iobCalc(now); total.plus(calc); } } return total; } @Override public void updateTotalIOB() { IobTotal total = getCalculationToTime(new Date().getTime()); lastCalculationTimestamp = new Date().getTime(); lastCalculation = total; } @Nullable @Override public TempBasal getTempBasal(Date time) { checkForExpired(tempBasals); for (TempBasal t : tempBasals) { if (t.isInProgress(time)) return t; } return null; } @Override public TempBasal getExtendedBolus(Date time) { checkForExpired(extendedBoluses); for (TempBasal t : extendedBoluses) { if (t.isInProgress(time)) return t; } return null; } @Override public long oldestDataAvaialable() { long oldestTemp = new Date().getTime(); if (tempBasals.size() > 0) oldestTemp = Math.min(oldestTemp, tempBasals.get(tempBasals.size() - 1).timeStart.getTime()); if (extendedBoluses.size() > 0) oldestTemp = Math.min(oldestTemp, extendedBoluses.get(extendedBoluses.size() - 1).timeStart.getTime()); oldestTemp -= 15 * 60 * 1000L; // allow 15 min before return oldestTemp; } List<TempBasal> getMergedList() { if (useExtendedBoluses) { List<TempBasal> merged = new ArrayList<TempBasal>(); merged.addAll(tempBasals); merged.addAll(extendedBoluses); class CustomComparator implements Comparator<TempBasal> { public int compare(TempBasal object1, TempBasal object2) { return (int) (object2.timeIndex - object1.timeIndex); } } Collections.sort(merged, new CustomComparator()); return merged; } else { return tempBasals; } } @Subscribe public void onStatusEvent(final EventTempBasalChange ev) { initializeData(); } public void onStatusEvent(final EventPreferenceChange s) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); useExtendedBoluses = sharedPreferences.getBoolean("danar_useextended", false); initializeData(); } }