/*
 * Copyright (C) 2020 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.systemui.statusbar.policy.dagger;

import android.content.Context;
import android.content.res.Resources;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Handler;
import android.os.UserManager;

import com.android.internal.R;
import com.android.settingslib.devicestate.AndroidSecureSettings;
import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManagerProvider;
import com.android.settingslib.devicestate.PostureDeviceStateConverter;
import com.android.settingslib.devicestate.SecureSettings;
import com.android.settingslib.notification.modes.ZenIconLoader;
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogBufferFactory;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.connectivity.AccessPointControllerImpl;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.NetworkControllerImpl;
import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.ConfigurationForwarder;
import com.android.systemui.statusbar.policy.BatteryControllerLogger;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastControllerImpl;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DeviceControlsController;
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.statusbar.policy.DevicePostureControllerImpl;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotControllerImpl;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.KeyguardStateControllerImpl;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.LocationControllerImpl;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.statusbar.policy.SecurityControllerImpl;
import com.android.systemui.statusbar.policy.SecurityControllerStartable;
import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController;
import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionControllerImpl;
import com.android.systemui.statusbar.policy.SplitShadeStateController;
import com.android.systemui.statusbar.policy.SplitShadeStateControllerImpl;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.WalletController;
import com.android.systemui.statusbar.policy.WalletControllerImpl;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
import com.android.systemui.statusbar.policy.bluetooth.data.repository.BluetoothRepository;
import com.android.systemui.statusbar.policy.bluetooth.data.repository.BluetoothRepositoryImpl;
import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepositoryModule;
import com.android.systemui.statusbar.policy.profile.data.repository.ManagedProfileRepository;
import com.android.systemui.statusbar.policy.profile.data.repository.impl.ManagedProfileRepositoryImpl;
import com.android.systemui.statusbar.policy.vpn.data.repository.VpnRepository;
import com.android.systemui.statusbar.policy.vpn.data.repository.impl.VpnRepositoryImpl;
import com.android.systemui.supervision.data.repository.SupervisionRepositoryModule;
import com.android.systemui.util.wrapper.CameraRotationSettingProvider;
import com.android.systemui.util.wrapper.CameraRotationSettingProviderImpl;

import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.ClassKey;
import dagger.multibindings.IntoMap;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;

import javax.inject.Named;

/** Dagger Module for code in the statusbar.policy package. */
@Module(includes = {DeviceProvisioningRepositoryModule.class, SupervisionRepositoryModule.class})
public interface StatusBarPolicyModule {

    String DEVICE_STATE_ROTATION_LOCK_DEFAULTS = "DEVICE_STATE_ROTATION_LOCK_DEFAULTS";

    /** */
    @Binds
    BluetoothController provideBluetoothController(BluetoothControllerImpl controllerImpl);

    /** */
    @Binds
    BluetoothRepository provideBluetoothRepository(BluetoothRepositoryImpl impl);

    /** */
    @Binds
    VpnRepository provideVpnRepository(VpnRepositoryImpl impl);

    /** */
    @Binds
    CastController provideCastController(CastControllerImpl controllerImpl);

    /**
     * @deprecated: unscoped configuration controller shouldn't be injected as it might lead to
     * wrong updates in case of secondary displays.
     */
    @Binds
    ConfigurationController bindConfigurationController(@Main ConfigurationController impl);

    /** */
    @Binds
    ExtensionController provideExtensionController(ExtensionControllerImpl controllerImpl);

    /** */
    @Binds
    FlashlightController provideFlashlightController(FlashlightControllerImpl controllerImpl);

    /** */
    @Binds
    KeyguardStateController provideKeyguardMonitor(KeyguardStateControllerImpl controllerImpl);

    /** */
    @Binds
    SplitShadeStateController provideSplitShadeStateController(
            SplitShadeStateControllerImpl splitShadeStateControllerImpl);

    /** */
    @Binds
    HotspotController provideHotspotController(HotspotControllerImpl controllerImpl);

    /** */
    @Binds
    LocationController provideLocationController(LocationControllerImpl controllerImpl);

    /** */
    @Binds
    ManagedProfileRepository provideManagedProfileRepository(
            ManagedProfileRepositoryImpl impl);

    /** */
    @Binds
    NetworkController provideNetworkController(NetworkControllerImpl controllerImpl);

    /** */
    @Binds
    NextAlarmController provideNextAlarmController(NextAlarmControllerImpl controllerImpl);

    /** */
    @Binds
    RotationLockController provideRotationLockController(RotationLockControllerImpl controllerImpl);

    /** */
    @Binds
    @SysUISingleton
    CameraRotationSettingProvider bindCameraRotationSettingProvider(
            CameraRotationSettingProviderImpl impl);

    /** */
    @Binds
    SecurityController provideSecurityController(SecurityControllerImpl controllerImpl);

    /** */
    @Binds
    SensitiveNotificationProtectionController provideSensitiveNotificationProtectionController(
            SensitiveNotificationProtectionControllerImpl controllerImpl);

    /** */
    @Binds
    UserInfoController provideUserInfoContrller(UserInfoControllerImpl controllerImpl);

    /** */
    @Binds
    ZenModeController provideZenModeController(ZenModeControllerImpl controllerImpl);

    /** */
    @Binds
    DeviceControlsController provideDeviceControlsController(
            DeviceControlsControllerImpl controllerImpl);

    /** */
    @Binds
    WalletController provideWalletController(WalletControllerImpl controllerImpl);

    /** */
    @Binds
    AccessPointController provideAccessPointController(
            AccessPointControllerImpl accessPointControllerImpl);

    /** */
    @Binds
    DevicePostureController provideDevicePostureController(
            DevicePostureControllerImpl devicePostureControllerImpl);

    /** */
    @Binds
    @SysUISingleton
    @Main
    ConfigurationForwarder provideGlobalConfigurationForwarder(
            @Main ConfigurationController configurationController);

    /** */
    @Provides
    @SysUISingleton
    @Main
    static ConfigurationController provideGlobalConfigurationController(
            @Application Context context, ConfigurationControllerImpl.Factory factory) {
        return factory.create(context);
    }

    /** */
    @SysUISingleton
    @Provides
    static AccessPointControllerImpl  provideAccessPointControllerImpl(
            @Application Context context,
            UserManager userManager,
            UserTracker userTracker,
            @Main Executor mainExecutor,
            WifiPickerTrackerFactory wifiPickerTrackerFactory
    ) {
        AccessPointControllerImpl controller = new AccessPointControllerImpl(
                context,
                userManager,
                userTracker,
                mainExecutor,
                wifiPickerTrackerFactory
        );
        controller.init();
        return controller;
    }

    /** */
    @SysUISingleton
    @Provides
    static SecureSettings provideAndroidSecureSettings(Context context) {
        return new AndroidSecureSettings(context.getContentResolver());
    }

    /**  */
    @SysUISingleton
    @Provides
    static PostureDeviceStateConverter providePosturesHelper(Context context,
            DeviceStateManager deviceStateManager) {
        return new PostureDeviceStateConverter(context, deviceStateManager);
    }

    /** Returns a singleton instance of DeviceStateAutoRotateSettingManager based on auto-rotate
     * refactor flag. */
    @SysUISingleton
    @Provides
    static DeviceStateAutoRotateSettingManager provideAutoRotateSettingsManager(
            Context context,
            @Background Executor bgExecutor,
            SecureSettings secureSettings,
            @Main Handler mainHandler,
            PostureDeviceStateConverter postureDeviceStateConverter
    ) {
        return DeviceStateAutoRotateSettingManagerProvider.createInstance(context, bgExecutor,
                secureSettings, mainHandler, postureDeviceStateConverter);
    }

    /**
     * Default values for per-device state rotation lock settings.
     */
    @Provides
    @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS)
    static String[] providesDeviceStateRotationLockDefaults(@Main Resources resources) {
        return resources.getStringArray(
                R.array.config_perDeviceStateRotationLockDefaults);
    }

    /** */
    @Provides
    @SysUISingleton
    static DataSaverController provideDataSaverController(NetworkController networkController) {
        return networkController.getDataSaverController();
    }

    /** Provides a log buffer for BatteryControllerImpl */
    @Provides
    @SysUISingleton
    @BatteryControllerLog
    static LogBuffer provideBatteryControllerLog(LogBufferFactory factory) {
        return factory.create(BatteryControllerLogger.TAG, 150);
    }

    /** Provides a log buffer for CastControllerImpl */
    @Provides
    @SysUISingleton
    @CastControllerLog
    static LogBuffer provideCastControllerLog(LogBufferFactory factory) {
        return factory.create("CastControllerLog", 50);
    }

    /** Provides a {@link ZenIconLoader} that fetches icons in a background thread. */
    @Provides
    @SysUISingleton
    static ZenIconLoader provideZenIconLoader(
            @UiBackground ExecutorService backgroundExecutorService) {
        return new ZenIconLoader(backgroundExecutorService);
    }

    /** Binds {@link SecurityControllerStartable}. */
    @Binds
    @IntoMap
    @ClassKey(SecurityControllerStartable.class)
    CoreStartable bindSecurityControllerCoreStartable(SecurityControllerStartable startable);
}
