/*
 * Copyright (C) 2018 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.settings.sound;

import static android.bluetooth.BluetoothHearingAid.HI_SYNC_ID_INVALID;

import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.text.TextUtils;

import androidx.preference.ListPreference;
import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.HeadsetProfile;
import com.android.settingslib.bluetooth.HearingAidProfile;

/**
 * This class allows switching between HFP-connected & HAP-connected BT devices
 * while in on-call state.
 */
public class HandsFreeProfileOutputPreferenceController extends AudioSwitchPreferenceController
        implements Preference.OnPreferenceChangeListener {

    private static final int INVALID_INDEX = -1;

    public HandsFreeProfileOutputPreferenceController(Context context, String key) {
        super(context, key);
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        final String address = (String) newValue;
        if (!(preference instanceof ListPreference)) {
            return false;
        }

        final CharSequence defaultSummary = mContext.getText(R.string.media_output_default_summary);
        final ListPreference listPreference = (ListPreference) preference;
        if (TextUtils.equals(address, defaultSummary)) {
            // Switch to default device which address is device name
            mSelectedIndex = getDefaultDeviceIndex();
            setActiveBluetoothDevice(null);
            listPreference.setSummary(defaultSummary);
        } else {
            // Switch to BT device which address is hardware address
            final int connectedDeviceIndex = getConnectedDeviceIndex(address);
            if (connectedDeviceIndex == INVALID_INDEX) {
                return false;
            }
            final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex);
            mSelectedIndex = connectedDeviceIndex;
            setActiveBluetoothDevice(btDevice);
            listPreference.setSummary(btDevice.getAlias());
        }
        return true;
    }

    private int getConnectedDeviceIndex(String hardwareAddress) {
        if (mConnectedDevices != null) {
            for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
                final BluetoothDevice btDevice = mConnectedDevices.get(i);
                if (TextUtils.equals(btDevice.getAddress(), hardwareAddress)) {
                    return i;
                }
            }
        }
        return INVALID_INDEX;
    }

    @Override
    public void updateState(Preference preference) {
        if (preference == null) {
            // In case UI is not ready.
            return;
        }

        if (!Utils.isAudioModeOngoingCall(mContext)) {
            // Without phone call, disable the switch entry.
            mPreference.setVisible(false);
            preference.setSummary(mContext.getText(R.string.media_output_default_summary));
            return;
        }

        // Ongoing call status, list all the connected devices support hands free profile.
        // Select current active device.
        // Disable switch entry if there is no connected device.
        mConnectedDevices.clear();
        mConnectedDevices.addAll(getConnectedHfpDevices());
        mConnectedDevices.addAll(getConnectedHearingAidDevices());
        mConnectedDevices.addAll(getConnectedLeAudioDevices());

        final int numDevices = mConnectedDevices.size();
        if (numDevices == 0) {
            // No connected devices, disable switch entry.
            mPreference.setVisible(false);
            final CharSequence summary = mContext.getText(R.string.media_output_default_summary);
            final CharSequence[] defaultMediaOutput = new CharSequence[]{summary};
            mSelectedIndex = getDefaultDeviceIndex();
            preference.setSummary(summary);
            setPreference(defaultMediaOutput, defaultMediaOutput, preference);
            return;
        }

        mPreference.setVisible(true);
        CharSequence[] mediaOutputs = new CharSequence[numDevices + 1];
        CharSequence[] mediaValues = new CharSequence[numDevices + 1];

        // Setup devices entries, select active connected device
        setupPreferenceEntries(mediaOutputs, mediaValues, findActiveDevice());

        // Display connected devices, default device and show the active device
        setPreference(mediaOutputs, mediaValues, preference);
    }

    int getDefaultDeviceIndex() {
        // Default device is after all connected devices.
        return mConnectedDevices.size();
    }

    void setupPreferenceEntries(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
            BluetoothDevice activeDevice) {
        // default to current device
        mSelectedIndex = getDefaultDeviceIndex();
        // default device is after all connected devices.
        final CharSequence defaultSummary = mContext.getText(R.string.media_output_default_summary);
        mediaOutputs[mSelectedIndex] = defaultSummary;
        // use default device name as address
        mediaValues[mSelectedIndex] = defaultSummary;
        for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
            final BluetoothDevice btDevice = mConnectedDevices.get(i);
            mediaOutputs[i] = btDevice.getAlias();
            mediaValues[i] = btDevice.getAddress();
            if (btDevice.equals(activeDevice)) {
                // select the active connected device.
                mSelectedIndex = i;
            }
        }
    }

    void setPreference(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
            Preference preference) {
        final ListPreference listPreference = (ListPreference) preference;
        listPreference.setEntries(mediaOutputs);
        listPreference.setEntryValues(mediaValues);
        listPreference.setValueIndex(mSelectedIndex);
        listPreference.setSummary(mediaOutputs[mSelectedIndex]);
        mAudioSwitchPreferenceCallback.onPreferenceDataChanged(listPreference);
    }

    public void setActiveBluetoothDevice(BluetoothDevice device) {
        if (!Utils.isAudioModeOngoingCall(mContext)) {
            return;
        }
        final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
        final HeadsetProfile hfpProfile = mProfileManager.getHeadsetProfile();
        if (hapProfile != null && hfpProfile != null && device == null) {
            hfpProfile.setActiveDevice(null);
            hapProfile.setActiveDevice(null);
        } else if (hapProfile != null && device != null
                && hapProfile.getHiSyncId(device) != HI_SYNC_ID_INVALID) {
            hapProfile.setActiveDevice(device);
        } else if (hfpProfile != null) {
            hfpProfile.setActiveDevice(device);
        }
    }

    @Override
    public BluetoothDevice findActiveDevice() {
        BluetoothDevice haActiveDevice = findActiveHearingAidDevice();
        BluetoothDevice leAudioActiveDevice = findActiveLeAudioDevice();
        final HeadsetProfile headsetProfile = mProfileManager.getHeadsetProfile();

        if (haActiveDevice != null) {
            return haActiveDevice;
        }

        if (leAudioActiveDevice != null) {
            return leAudioActiveDevice;
        }

        if (headsetProfile != null && headsetProfile.getActiveDevice() != null) {
            return headsetProfile.getActiveDevice();
        }

        return null;
    }
}
