<commit_before>package info.nightscout.androidaps.plugins.iob.iobCobCalculator;

import android.os.SystemClock;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.LongSparseArray;

import org.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.events.EventConfigBuilderChange;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.treatments.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.T;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;

import static info.nightscout.androidaps.utils.DateUtil.now;

/**
 * Created by mike on 24.04.2017.
 */

public class IobCobCalculatorPlugin extends PluginBase {
    private Logger log = LoggerFactory.getLogger(L.AUTOSENS);
    private CompositeDisposable disposable = new CompositeDisposable();

    private static IobCobCalculatorPlugin plugin = null;

    public static IobCobCalculatorPlugin getPlugin() {
        if (plugin == null)
            plugin = new IobCobCalculatorPlugin();
        return plugin;
    }

    private LongSparseArray<IobTotal> iobTable = new LongSparseArray<>(); // oldest at index 0
    private LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0
    private LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0

    private volatile List<BgReading> bgReadings = null; // newest at index 0
    private volatile List<BgReading> bucketed_data = null;

    private final Object dataLock = new Object();

    boolean stopCalculationTrigger = false;
    private Thread thread = null;

    public IobCobCalculatorPlugin() {
        super(new PluginDescription()
                .mainType(PluginType.GENERAL)
                .pluginName(R.string.iobcobcalculator)
                .showInList(false)
                .neverVisible(true)
                .alwaysEnabled(true)
        );
    }

    @Override
    protected void onStart() {
        super.onStart();
        // EventConfigBuilderChange
        disposable.add(RxBus.INSTANCE
                .toObservable(EventConfigBuilderChange.class)
                .observeOn(Schedulers.io())
                .subscribe(event -> {
                    if (this != getPlugin()) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Ignoring event for non default instance");
                        return;
                    }
                    stopCalculation("onEventConfigBuilderChange");
                    synchronized (dataLock) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
                        iobTable = new LongSparseArray<>();
                        autosensDataTable = new LongSparseArray<>();
                    }
                    runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), false, true, event);
                }, FabricPrivacy::logException)
        );
        // EventNewBasalProfile
        disposable.add(RxBus.INSTANCE
                .toObservable(EventNewBasalProfile.class)
                .observeOn(Schedulers.io())
                .subscribe(event -> {
                    if (this != getPlugin()) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Ignoring event for non default instance");
                        return;
                    }
                    if (ConfigBuilderPlugin.getPlugin() == null)
                        return; // app still initializing
                    if (event == null) { // on init no need of reset
                        return;
                    }
                    stopCalculation("onNewProfile");
                    synchronized (dataLock) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Invalidating cached data because of new profile. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
                        iobTable = new LongSparseArray<>();
                        autosensDataTable = new LongSparseArray<>();
                        basalDataTable = new LongSparseArray<>();
                    }
                    runCalculation("onNewProfile", System.currentTimeMillis(), false, true, event);
                }, FabricPrivacy::logException)
        );
        // EventNewBG
        disposable.add(RxBus.INSTANCE
                .toObservable(EventNewBG.class)
                .observeOn(Schedulers.io())
                .subscribe(event -> {
                    if (this != getPlugin()) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Ignoring event for non default instance");
                        return;
                    }
                    stopCalculation("onEventNewBG");
                    runCalculation("onEventNewBG", System.currentTimeMillis(), true, true, event);
                }, FabricPrivacy::logException)
        );
        // EventPreferenceChange
        disposable.add(RxBus.INSTANCE
                .toObservable(EventPreferenceChange.class)
                .observeOn(Schedulers.io())
                .subscribe(event -> {
                    if (this != getPlugin()) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Ignoring event for non default instance");
                        return;
                    }
                    if (event.isChanged(R.string.key_openapsama_autosens_period) ||
                            event.isChanged(R.string.key_age) ||
                            event.isChanged(R.string.key_absorption_maxtime) ||
                            event.isChanged(R.string.key_openapsama_min_5m_carbimpact) ||
                            event.isChanged(R.string.key_absorption_cutoff) ||
                            event.isChanged(R.string.key_openapsama_autosens_max) ||
                            event.isChanged(R.string.key_openapsama_autosens_min)
                    ) {
                        stopCalculation("onEventPreferenceChange");
                        synchronized (dataLock) {<commit_msg>Recalculate IOB on insulin peak time pref change.<commit_after>package info.nightscout.androidaps.plugins.iob.iobCobCalculator;

import android.os.SystemClock;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.LongSparseArray;

import org.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.events.EventConfigBuilderChange;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.treatments.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.T;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;

import static info.nightscout.androidaps.utils.DateUtil.now;

/**
 * Created by mike on 24.04.2017.
 */

public class IobCobCalculatorPlugin extends PluginBase {
    private Logger log = LoggerFactory.getLogger(L.AUTOSENS);
    private CompositeDisposable disposable = new CompositeDisposable();

    private static IobCobCalculatorPlugin plugin = null;

    public static IobCobCalculatorPlugin getPlugin() {
        if (plugin == null)
            plugin = new IobCobCalculatorPlugin();
        return plugin;
    }

    private LongSparseArray<IobTotal> iobTable = new LongSparseArray<>(); // oldest at index 0
    private LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0
    private LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0

    private volatile List<BgReading> bgReadings = null; // newest at index 0
    private volatile List<BgReading> bucketed_data = null;

    private final Object dataLock = new Object();

    boolean stopCalculationTrigger = false;
    private Thread thread = null;

    public IobCobCalculatorPlugin() {
        super(new PluginDescription()
                .mainType(PluginType.GENERAL)
                .pluginName(R.string.iobcobcalculator)
                .showInList(false)
                .neverVisible(true)
                .alwaysEnabled(true)
        );
    }

    @Override
    protected void onStart() {
        super.onStart();
        // EventConfigBuilderChange
        disposable.add(RxBus.INSTANCE
                .toObservable(EventConfigBuilderChange.class)
                .observeOn(Schedulers.io())
                .subscribe(event -> {
                    if (this != getPlugin()) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Ignoring event for non default instance");
                        return;
                    }
                    stopCalculation("onEventConfigBuilderChange");
                    synchronized (dataLock) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
                        iobTable = new LongSparseArray<>();
                        autosensDataTable = new LongSparseArray<>();
                    }
                    runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), false, true, event);
                }, FabricPrivacy::logException)
        );
        // EventNewBasalProfile
        disposable.add(RxBus.INSTANCE
                .toObservable(EventNewBasalProfile.class)
                .observeOn(Schedulers.io())
                .subscribe(event -> {
                    if (this != getPlugin()) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Ignoring event for non default instance");
                        return;
                    }
                    if (ConfigBuilderPlugin.getPlugin() == null)
                        return; // app still initializing
                    if (event == null) { // on init no need of reset
                        return;
                    }
                    stopCalculation("onNewProfile");
                    synchronized (dataLock) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Invalidating cached data because of new profile. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
                        iobTable = new LongSparseArray<>();
                        autosensDataTable = new LongSparseArray<>();
                        basalDataTable = new LongSparseArray<>();
                    }
                    runCalculation("onNewProfile", System.currentTimeMillis(), false, true, event);
                }, FabricPrivacy::logException)
        );
        // EventNewBG
        disposable.add(RxBus.INSTANCE
                .toObservable(EventNewBG.class)
                .observeOn(Schedulers.io())
                .subscribe(event -> {
                    if (this != getPlugin()) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Ignoring event for non default instance");
                        return;
                    }
                    stopCalculation("onEventNewBG");
                    runCalculation("onEventNewBG", System.currentTimeMillis(), true, true, event);
                }, FabricPrivacy::logException)
        );
        // EventPreferenceChange
        disposable.add(RxBus.INSTANCE
                .toObservable(EventPreferenceChange.class)
                .observeOn(Schedulers.io())
                .subscribe(event -> {
                    if (this != getPlugin()) {
                        if (L.isEnabled(L.AUTOSENS))
                            log.debug("Ignoring event for non default instance");
                        return;
                    }
                    if (event.isChanged(R.string.key_openapsama_autosens_period) ||
                            event.isChanged(R.string.key_age) ||
                            event.isChanged(R.string.key_absorption_maxtime) ||
                            event.isChanged(R.string.key_openapsama_min_5m_carbimpact) ||
                            event.isChanged(R.string.key_absorption_cutoff) ||
                            event.isChanged(R.string.key_openapsama_autosens_max) ||
                            event.isChanged(R.string.key_openapsama_autosens_min) ||
                            event.isChanged(R.string.key_insulin_oref_peak)
                    ) {
                        stopCalculation("onEventPreferenceChange");
                        synchronized (dataLock) {
{'fraction_non_alphanumeric': 0.0917786808377618, 'fraction_numerical': 0.0020006251953735544, 'mean_word_length': 2.1451042076287847, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5665375', 'n_tokens_mistral': 4378, 'n_tokens_neox': 4155, 'n_words': 714}