/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * 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.android.server.backup;

import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING;

import android.app.AlarmManager;
import android.app.job.JobInfo;
import android.content.ContentResolver;
import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.KeyValueListParser;
import android.util.KeyValueSettingObserver;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;

/**
 * Class to access backup manager constants.
 *
 * <p>The backup manager constants are encoded as a key value list separated by commas and stored as
 * a Settings.Secure.
 */
public class BackupManagerConstants extends KeyValueSettingObserver {
    private static final String TAG = "BackupManagerConstants";
    private static final String SETTING = Settings.Secure.BACKUP_MANAGER_CONSTANTS;

    // Key names stored in the secure settings value.
    @VisibleForTesting
    public static final String KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS =
            "key_value_backup_interval_milliseconds";

    @VisibleForTesting
    public static final String KEY_VALUE_BACKUP_FUZZ_MILLISECONDS =
            "key_value_backup_fuzz_milliseconds";

    @VisibleForTesting
    public static final String KEY_VALUE_BACKUP_REQUIRE_CHARGING =
            "key_value_backup_require_charging";

    @VisibleForTesting
    public static final String KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE =
            "key_value_backup_required_network_type";

    @VisibleForTesting
    public static final String FULL_BACKUP_INTERVAL_MILLISECONDS =
            "full_backup_interval_milliseconds";

    @VisibleForTesting
    public static final String FULL_BACKUP_REQUIRE_CHARGING = "full_backup_require_charging";

    @VisibleForTesting
    public static final String FULL_BACKUP_REQUIRED_NETWORK_TYPE =
            "full_backup_required_network_type";

    @VisibleForTesting
    public static final String BACKUP_FINISHED_NOTIFICATION_RECEIVERS =
            "backup_finished_notification_receivers";

    // Hard coded default values.
    @VisibleForTesting
    public static final long DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS =
            4 * AlarmManager.INTERVAL_HOUR;

    @VisibleForTesting
    public static final long DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS = 10 * 60 * 1000;

    @VisibleForTesting public static final boolean DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING = true;
    @VisibleForTesting
    public static final int DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE =
            JobInfo.NETWORK_TYPE_ANY;

    @VisibleForTesting
    public static final long DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS =
            24 * AlarmManager.INTERVAL_HOUR;

    @VisibleForTesting public static final boolean DEFAULT_FULL_BACKUP_REQUIRE_CHARGING = true;
    @VisibleForTesting
    public static final int DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE =
            JobInfo.NETWORK_TYPE_UNMETERED;

    @VisibleForTesting
    public static final String DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS = "";

    // Backup manager constants.
    private long mKeyValueBackupIntervalMilliseconds;
    private long mKeyValueBackupFuzzMilliseconds;
    private boolean mKeyValueBackupRequireCharging;
    private int mKeyValueBackupRequiredNetworkType;
    private long mFullBackupIntervalMilliseconds;
    private boolean mFullBackupRequireCharging;
    private int mFullBackupRequiredNetworkType;
    private String[] mBackupFinishedNotificationReceivers;

    public BackupManagerConstants(Handler handler, ContentResolver resolver) {
        super(handler, resolver, Settings.Secure.getUriFor(SETTING));
    }

    public String getSettingValue(ContentResolver resolver) {
        return Settings.Secure.getString(resolver, SETTING);
    }

    public synchronized void update(KeyValueListParser parser) {
        mKeyValueBackupIntervalMilliseconds =
                parser.getLong(
                        KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS,
                        DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS);
        mKeyValueBackupFuzzMilliseconds =
                parser.getLong(
                        KEY_VALUE_BACKUP_FUZZ_MILLISECONDS,
                        DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS);
        mKeyValueBackupRequireCharging =
                parser.getBoolean(
                        KEY_VALUE_BACKUP_REQUIRE_CHARGING,
                        DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING);
        mKeyValueBackupRequiredNetworkType =
                parser.getInt(
                        KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE,
                        DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE);
        mFullBackupIntervalMilliseconds =
                parser.getLong(
                        FULL_BACKUP_INTERVAL_MILLISECONDS,
                        DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS);
        mFullBackupRequireCharging =
                parser.getBoolean(
                        FULL_BACKUP_REQUIRE_CHARGING, DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
        mFullBackupRequiredNetworkType =
                parser.getInt(
                        FULL_BACKUP_REQUIRED_NETWORK_TYPE,
                        DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE);
        String backupFinishedNotificationReceivers =
                parser.getString(
                        BACKUP_FINISHED_NOTIFICATION_RECEIVERS,
                        DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS);
        if (backupFinishedNotificationReceivers.isEmpty()) {
            mBackupFinishedNotificationReceivers = new String[] {};
        } else {
            mBackupFinishedNotificationReceivers = backupFinishedNotificationReceivers.split(":");
        }
    }

    // The following are access methods for the individual parameters.
    // To be sure to retrieve values from the same set of settings,
    // group the calls of these methods in a block syncrhonized on
    // a reference of this object.
    public synchronized long getKeyValueBackupIntervalMilliseconds() {
        if (DEBUG_SCHEDULING) {
            Slog.v(
                    TAG,
                    "getKeyValueBackupIntervalMilliseconds(...) returns "
                            + mKeyValueBackupIntervalMilliseconds);
        }
        return mKeyValueBackupIntervalMilliseconds;
    }

    public synchronized long getKeyValueBackupFuzzMilliseconds() {
        if (DEBUG_SCHEDULING) {
            Slog.v(
                    TAG,
                    "getKeyValueBackupFuzzMilliseconds(...) returns "
                            + mKeyValueBackupFuzzMilliseconds);
        }
        return mKeyValueBackupFuzzMilliseconds;
    }

    public synchronized boolean getKeyValueBackupRequireCharging() {
        if (DEBUG_SCHEDULING) {
            Slog.v(
                    TAG,
                    "getKeyValueBackupRequireCharging(...) returns "
                            + mKeyValueBackupRequireCharging);
        }
        return mKeyValueBackupRequireCharging;
    }

    public synchronized int getKeyValueBackupRequiredNetworkType() {
        if (DEBUG_SCHEDULING) {
            Slog.v(
                    TAG,
                    "getKeyValueBackupRequiredNetworkType(...) returns "
                            + mKeyValueBackupRequiredNetworkType);
        }
        return mKeyValueBackupRequiredNetworkType;
    }

    public synchronized long getFullBackupIntervalMilliseconds() {
        if (DEBUG_SCHEDULING) {
            Slog.v(
                    TAG,
                    "getFullBackupIntervalMilliseconds(...) returns "
                            + mFullBackupIntervalMilliseconds);
        }
        return mFullBackupIntervalMilliseconds;
    }

    public synchronized boolean getFullBackupRequireCharging() {
        if (DEBUG_SCHEDULING) {
            Slog.v(TAG, "getFullBackupRequireCharging(...) returns " + mFullBackupRequireCharging);
        }
        return mFullBackupRequireCharging;
    }

    public synchronized int getFullBackupRequiredNetworkType() {
        if (DEBUG_SCHEDULING) {
            Slog.v(
                    TAG,
                    "getFullBackupRequiredNetworkType(...) returns "
                            + mFullBackupRequiredNetworkType);
        }
        return mFullBackupRequiredNetworkType;
    }

    /** Returns an array of package names that should be notified whenever a backup finishes. */
    public synchronized String[] getBackupFinishedNotificationReceivers() {
        if (DEBUG_SCHEDULING) {
            Slog.v(
                    TAG,
                    "getBackupFinishedNotificationReceivers(...) returns "
                            + TextUtils.join(", ", mBackupFinishedNotificationReceivers));
        }
        return mBackupFinishedNotificationReceivers;
    }
}
