<commit_before>/*
 * Copyright (c) 2016 Bottle Rocket LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bottlerocketstudios.configuration;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Manages the state and ability to switch application configurations for different aspects of the application.
 * Will warn when in a non production mode. Each type of configuration that switch modes should have its
 * own ApplicationConfigurationController managed by the ApplicationConfigurationServiceLocator.
 */
public abstract class ApplicationConfigurationController<T extends ApplicationConfiguration> {
    
    private static final String TAG = ApplicationConfigurationController.class.getSimpleName();

    protected static final long INVALID_CONFIG_ID = -1;

    private Context mContext;
    
    private Boolean mStagingAllowed;
    private Long mSelectedConfigId;
    private long mProductionConfigId = INVALID_CONFIG_ID;
    private String mSettingKeyAddition;
    private Set<ApplicationConfigurationControllerListener> mListeners;
    private Map<Long, T> mApplicationConfigurationMap;

    public ApplicationConfigurationController() {
        mListeners = new HashSet<>();
        mApplicationConfigurationMap = new HashMap<>();
    }
    
    @SuppressWarnings("unused")
    public void initialize(Context context, String keyAddition, boolean stagingAllowed, boolean isDebugBuild) {
        mContext = context.getApplicationContext();
        mStagingAllowed = stagingAllowed;
        mSettingKeyAddition = keyAddition;

        addAllApplicationConfigurations();
        initAllApplicationConfigurations();
        validateAllApplicationConfigurations();

        if (isStagingEnabled() && !isDebugBuild) {
            Toast.makeText(mContext, "DEBUG: STAGING IS IN USE FOR " + keyAddition, Toast.LENGTH_LONG).show();
        }
    }

    /**
     * Are staging environments allowed for this controller.
     */
    public boolean isStagingAllowed() {
        return mStagingAllowed;
    }

    private boolean isStagingEnabled() {
        return getSelectedConfigId() != getProductionConfigId();
    }

    protected long getSelectedConfigId() {
        if (!isStagingAllowed()) {
            //Cannot be enabled if it is not allowed, ignore configuration value.
            mSelectedConfigId = getProductionConfigId();
        }

        if (mSelectedConfigId == null) {
            //Lazy load from config on first read.
            SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
            mSelectedConfigId = sharedPrefs.getLong(getSettingKey(), getDefaultAppConfigId());
        }

        return mSelectedConfigId;
    }

    /**
     * Select the specified application configuration by Id. This method will notify all listeners then
     * shutdown the application by calling System.exit(0);
     */
    public void setSelectedConfigId(long applicationConfigId) {
        T newApplicationConfig = getApplicationConfigurationById(applicationConfigId);
        if (isStagingAllowed() && newApplicationConfig != null && applicationConfigId != getSelectedConfigId()) {
            mSelectedConfigId = applicationConfigId;
            SharedPreferences.Editor sharedPrefsEditor = PreferenceManager.getDefaultSharedPreferences(mContext).edit();
            sharedPrefsEditor.putLong(getSettingKey(), applicationConfigId);
            sharedPrefsEditor.commit();
            Log.i(TAG, "Notifying listeners for switch to " + newApplicationConfig.getName() + ".");
            for (ApplicationConfigurationControllerListener listener: mListeners) {
                listener.onStagingSwitch(mContext, newApplicationConfig);
            }
            Log.i(TAG, "Shutting down VM to affect staging switch.");
            System.exit(0);
        }
    }
    
    protected String getSettingKey() {
        return "com.bottlerocketstudios.configuration.ApplicationConfigurationController."
                + mSettingKeyAddition + ".selectedConfigId";
    }

    /**
     * Register interest in configuration changes.
     */
    public void addListener(ApplicationConfigurationControllerListener<T> listener) {
        mListeners.add(listener);
    }<commit_msg>Fix failure to observe shouldExitOnChange<commit_after>/*
 * Copyright (c) 2016 Bottle Rocket LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bottlerocketstudios.configuration;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Manages the state and ability to switch application configurations for different aspects of the application.
 * Will warn when in a non production mode. Each type of configuration that switch modes should have its
 * own ApplicationConfigurationController managed by the ApplicationConfigurationServiceLocator.
 */
public abstract class ApplicationConfigurationController<T extends ApplicationConfiguration> {
    
    private static final String TAG = ApplicationConfigurationController.class.getSimpleName();

    protected static final long INVALID_CONFIG_ID = -1;

    private Context mContext;
    
    private Boolean mStagingAllowed;
    private Long mSelectedConfigId;
    private long mProductionConfigId = INVALID_CONFIG_ID;
    private String mSettingKeyAddition;
    private Set<ApplicationConfigurationControllerListener> mListeners;
    private Map<Long, T> mApplicationConfigurationMap;

    public ApplicationConfigurationController() {
        mListeners = new HashSet<>();
        mApplicationConfigurationMap = new HashMap<>();
    }
    
    @SuppressWarnings("unused")
    public void initialize(Context context, String keyAddition, boolean stagingAllowed, boolean isDebugBuild) {
        mContext = context.getApplicationContext();
        mStagingAllowed = stagingAllowed;
        mSettingKeyAddition = keyAddition;

        addAllApplicationConfigurations();
        initAllApplicationConfigurations();
        validateAllApplicationConfigurations();

        if (isStagingEnabled() && !isDebugBuild) {
            Toast.makeText(mContext, "DEBUG: STAGING IS IN USE FOR " + keyAddition, Toast.LENGTH_LONG).show();
        }
    }

    /**
     * Are staging environments allowed for this controller.
     */
    public boolean isStagingAllowed() {
        return mStagingAllowed;
    }

    private boolean isStagingEnabled() {
        return getSelectedConfigId() != getProductionConfigId();
    }

    protected long getSelectedConfigId() {
        if (!isStagingAllowed()) {
            //Cannot be enabled if it is not allowed, ignore configuration value.
            mSelectedConfigId = getProductionConfigId();
        }

        if (mSelectedConfigId == null) {
            //Lazy load from config on first read.
            SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
            mSelectedConfigId = sharedPrefs.getLong(getSettingKey(), getDefaultAppConfigId());
        }

        return mSelectedConfigId;
    }

    /**
     * Select the specified application configuration by Id. This method will notify all listeners then
     * shutdown the application by calling System.exit(0);
     */
    public void setSelectedConfigId(long applicationConfigId) {
        T newApplicationConfig = getApplicationConfigurationById(applicationConfigId);
        if (isStagingAllowed() && newApplicationConfig != null && applicationConfigId != getSelectedConfigId()) {
            mSelectedConfigId = applicationConfigId;
            SharedPreferences.Editor sharedPrefsEditor = PreferenceManager.getDefaultSharedPreferences(mContext).edit();
            sharedPrefsEditor.putLong(getSettingKey(), applicationConfigId);
            sharedPrefsEditor.commit();
            Log.i(TAG, "Notifying listeners for switch to " + newApplicationConfig.getName() + ".");
            for (ApplicationConfigurationControllerListener listener: mListeners) {
                listener.onStagingSwitch(mContext, newApplicationConfig);
            }
            if (shouldExitOnChange()) {
                Log.i(TAG, "Shutting down VM to affect staging switch.");
                System.exit(0);
            }
        }
    }
    
    protected String getSettingKey() {
        return "com.bottlerocketstudios.configuration.ApplicationConfigurationController."
                + mSettingKeyAddition + ".selectedConfigId";
    }

    /**
     * Register interest in configuration changes.
     */
    public void addListener(ApplicationConfigurationControllerListener<T> listener) {
        mListeners.add(listener);
    }
{'fraction_non_alphanumeric': 0.07555821371610845, 'fraction_numerical': 0.0021929824561403508, 'mean_word_length': 3.3793103448275863, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '5717091', 'n_tokens_mistral': 2393, 'n_tokens_neox': 2347, 'n_words': 726}