/*
 * 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.car.systembar;

import android.annotation.Nullable;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.dagger.SysUISingleton;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

/**
 * Some CarSystemBarButtons can be associated to a {@link RoleManager} role. When they are, it is
 * possible to have them display the icon of the default application (role holder) for the given
 * role.
 *
 * This class monitors the current role holders for each role type and updates the button icon for
 * this buttons with have this feature enabled.
 */
@SysUISingleton
public class ButtonRoleHolderController {
    private static final String TAG = "ButtonRoleHolderController";

    private final Context mContext;
    private final PackageManager mPackageManager;
    private final RoleManager mRoleManager;
    private final CarDeviceProvisionedController mDeviceController;
    private final Map<String, CarSystemBarButton> mButtonMap = new HashMap<>();
    private final OnRoleHoldersChangedListener mListener = this::onRoleChanged;
    private boolean mRegistered;

    @Inject
    public ButtonRoleHolderController(Context context, PackageManager packageManager,
            RoleManager roleManager, CarDeviceProvisionedController deviceController) {
        mContext = context;
        mPackageManager = packageManager;
        mRoleManager = roleManager;
        mDeviceController = deviceController;
    }

    /**
     * Iterate through a view looking for CarSystemBarButton and add it to this controller if it
     * opted to be associated with a {@link RoleManager} role type.
     *
     * @param v the View that may contain CarFacetButtons
     */
    void addAllButtonsWithRoleName(View v) {
        if (v instanceof CarSystemBarButton) {
            CarSystemBarButton button = (CarSystemBarButton) v;
            String roleName = button.getRoleName();
            if (roleName != null && button.isDefaultAppIconForRoleEnabled()) {
                addButtonWithRoleName(button, roleName);
            }
        } else if (v instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) v;
            for (int i = 0; i < viewGroup.getChildCount(); i++) {
                addAllButtonsWithRoleName(viewGroup.getChildAt(i));
            }
        }
    }

    private void addButtonWithRoleName(CarSystemBarButton button, String roleName) {
        mButtonMap.put(roleName, button);
        updateIcon(roleName);
        if (!mRegistered) {
            mRoleManager.addOnRoleHoldersChangedListenerAsUser(mContext.getMainExecutor(),
                    mListener, UserHandle.ALL);
            mRegistered = true;
        }
    }

    void removeAll() {
        mButtonMap.clear();
        if (mRegistered) {
            mRoleManager.removeOnRoleHoldersChangedListenerAsUser(mListener, UserHandle.ALL);
            mRegistered = false;
        }
    }

    @VisibleForTesting
    void onRoleChanged(String roleName, UserHandle user) {
        if (RoleManager.ROLE_ASSISTANT.equals(roleName)
                && user.getIdentifier() == mDeviceController.getCurrentUser()) {
            updateIcon(roleName);
        }
    }

    private void updateIcon(String roleName) {
        CarSystemBarButton button = mButtonMap.get(roleName);
        if (button == null) {
            return;
        }
        List<String> holders = mRoleManager.getRoleHoldersAsUser(button.getRoleName(),
                UserHandle.of(mDeviceController.getCurrentUser()));
        if (holders == null || holders.isEmpty()) {
            button.setAppIcon(null);
        } else {
            button.setAppIcon(loadIcon(holders.get(0)));
        }
    }

    @Nullable
    private Drawable loadIcon(String packageName) {
        try {
            ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName,
                    PackageManager.MATCH_ANY_USER);
            return appInfo.loadIcon(mPackageManager);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(ButtonRoleHolderController.TAG, "Package not found: " + packageName, e);
            return null;
        }
    }
}
