// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.physicalweb;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;

import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.ChromeApplication;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;

/**
 * This class provides the basic interface to the Physical Web feature.
 */
public class PhysicalWeb {
    public static final int OPTIN_NOTIFY_MAX_TRIES = 1;
    private static final String PREF_PHYSICAL_WEB_NOTIFY_COUNT = "physical_web_notify_count";
    private static final String PREF_IGNORE_OTHER_CLIENTS = "physical_web_ignore_other_clients";
    private static final String FEATURE_NAME = "PhysicalWeb";
    private static final String IGNORE_OTHER_CLIENTS_FEATURE_NAME = "PhysicalWebIgnoreOtherClients";
    private static final int MIN_ANDROID_VERSION = 18;

    /**
     * Evaluate whether the environment is one in which the Physical Web should
     * be enabled.
     * @return true if the PhysicalWeb should be enabled
     */
    public static boolean featureIsEnabled() {
        return ChromeFeatureList.isEnabled(FEATURE_NAME)
                && Build.VERSION.SDK_INT >= MIN_ANDROID_VERSION;
    }

    /**
     * Checks whether the Physical Web preference is switched to On.
     *
     * @param context An instance of android.content.Context
     * @return boolean {@code true} if the preference is On.
     */
    public static boolean isPhysicalWebPreferenceEnabled(Context context) {
        return PrivacyPreferencesManager.getInstance().isPhysicalWebEnabled();
    }

    /**
     * Checks whether the Physical Web onboard flow is active and the user has
     * not yet elected to either enable or decline the feature.
     *
     * @param context An instance of android.content.Context
     * @return boolean {@code true} if onboarding is complete.
     */
    public static boolean isOnboarding(Context context) {
        return PrivacyPreferencesManager.getInstance().isPhysicalWebOnboarding();
    }

    /**
     * Start the Physical Web feature.
     * At the moment, this only enables URL discovery over BLE.
     * @param application An instance of {@link ChromeApplication}, used to get the
     * appropriate PhysicalWebBleClient implementation.
     */
    public static void startPhysicalWeb(final ChromeApplication application) {
        PhysicalWebBleClient.getInstance(application).backgroundSubscribe(new Runnable() {
            @Override
            public void run() {
                // We need to clear the list of nearby URLs so that they can be repopulated by the
                // new subscription, but we don't know whether we are already subscribed, so we need
                // to pass a callback so that we can clear as soon as we are resubscribed.
                UrlManager.getInstance(application).clearNearbyUrls();
            }
        });
    }

    /**
     * Stop the Physical Web feature.
     * @param application An instance of {@link ChromeApplication}, used to get the
     * appropriate PhysicalWebBleClient implementation.
     */
    public static void stopPhysicalWeb(final ChromeApplication application) {
        PhysicalWebBleClient.getInstance(application).backgroundUnsubscribe(new Runnable() {
            @Override
            public void run() {
                // This isn't absolutely necessary, but it's nice to clean up all our shared prefs.
                UrlManager.getInstance(application).clearAllUrls();
            }
        });
    }

    /**
     * Returns true if we should fire notifications regardless of the existence of other Physical
     * Web clients.
     * This method is for use when the native library is not available.
     */
    public static boolean shouldIgnoreOtherClients() {
        return ContextUtils.getAppSharedPreferences().getBoolean(PREF_IGNORE_OTHER_CLIENTS, false);
    }

    /**
     * Increments a value tracking how many times we've shown the Physical Web
     * opt-in notification.
     *
     * @param context An instance of android.content.Context
     */
    public static void recordOptInNotification(Context context) {
        SharedPreferences sharedPreferences =
                ContextUtils.getAppSharedPreferences();
        int value = sharedPreferences.getInt(PREF_PHYSICAL_WEB_NOTIFY_COUNT, 0);
        sharedPreferences.edit().putInt(PREF_PHYSICAL_WEB_NOTIFY_COUNT, value + 1).apply();
    }

    /**
     * Gets the current count of how many times a high-priority opt-in notification
     * has been shown.
     *
     * @param context An instance of android.content.Context
     * @return an integer representing the high-priority notifification display count.
     */
    public static int getOptInNotifyCount(Context context) {
        SharedPreferences sharedPreferences =
                ContextUtils.getAppSharedPreferences();
        return sharedPreferences.getInt(PREF_PHYSICAL_WEB_NOTIFY_COUNT, 0);
    }

    /**
     * Perform various Physical Web operations that should happen on startup.
     * @param application An instance of {@link ChromeApplication}.
     */
    public static void onChromeStart(ChromeApplication application) {
        // The PhysicalWebUma calls in this method should be called only when the native library is
        // loaded.  This is always the case on chrome startup.
        if (featureIsEnabled()
                && (isPhysicalWebPreferenceEnabled(application) || isOnboarding(application))) {
            boolean ignoreOtherClients =
                    ChromeFeatureList.isEnabled(IGNORE_OTHER_CLIENTS_FEATURE_NAME);
            ContextUtils.getAppSharedPreferences().edit()
                    .putBoolean(PREF_IGNORE_OTHER_CLIENTS, ignoreOtherClients)
                    .apply();
            startPhysicalWeb(application);
            PhysicalWebUma.uploadDeferredMetrics(application);
        } else {
            stopPhysicalWeb(application);
        }
    }
}