/*
 * Copyright (C) 2021 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.car.cluster;

import static android.content.Intent.ACTION_MAIN;

import static com.android.car.hal.ClusterHalService.DISPLAY_OFF;
import static com.android.car.hal.ClusterHalService.DISPLAY_ON;
import static com.android.car.hal.ClusterHalService.DONT_CARE;
import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;

import android.app.ActivityOptions;
import android.car.Car;
import android.car.CarOccupantZoneManager;
import android.car.ICarOccupantZoneCallback;
import android.car.cluster.ClusterHomeManager;
import android.car.cluster.ClusterState;
import android.car.cluster.IClusterHomeCallback;
import android.car.cluster.IClusterHomeService;
import android.car.cluster.navigation.NavigationState.NavigationStateProto;
import android.car.navigation.CarNavigationInstrumentCluster;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
import android.view.Display;

import com.android.car.CarLog;
import com.android.car.CarOccupantZoneService;
import com.android.car.CarServiceBase;
import com.android.car.R;
import com.android.car.am.FixedActivityService;
import com.android.car.hal.ClusterHalService;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.server.utils.Slogf;

/**
 * Service responsible for interactions between ClusterOS and ClusterHome.
 */
public class ClusterHomeService extends IClusterHomeService.Stub
        implements CarServiceBase, ClusterNavigationService.ClusterNavigationServiceCallback,
        ClusterHalService.ClusterHalEventCallback {
    private static final String TAG = CarLog.TAG_CLUSTER;
    private static final int DEFAULT_MIN_UPDATE_INTERVAL_MILLIS = 1000;
    private static final String NAV_STATE_PROTO_BUNDLE_KEY = "navstate2";

    private final Context mContext;
    private final ClusterHalService mClusterHalService;
    private final ClusterNavigationService mClusterNavigationService;
    private final CarOccupantZoneService mOccupantZoneService;
    private final FixedActivityService mFixedActivityService;
    private final ComponentName mClusterHomeActivity;

    private boolean mServiceEnabled;

    private int mClusterDisplayId = Display.INVALID_DISPLAY;

    private int mOnOff = DISPLAY_OFF;
    private Rect mBounds = new Rect();
    private Insets mInsets = Insets.NONE;
    private int mUiType = ClusterHomeManager.UI_TYPE_CLUSTER_HOME;
    private Intent mLastIntent;
    private int mLastIntentUserId = UserHandle.USER_SYSTEM;

    private final RemoteCallbackList<IClusterHomeCallback> mClientCallbacks =
            new RemoteCallbackList<>();

    public ClusterHomeService(Context context, ClusterHalService clusterHalService,
            ClusterNavigationService navigationService,
            CarOccupantZoneService occupantZoneService,
            FixedActivityService fixedActivityService) {
        mContext = context;
        mClusterHalService = clusterHalService;
        mClusterNavigationService = navigationService;
        mOccupantZoneService = occupantZoneService;
        mFixedActivityService = fixedActivityService;
        mClusterHomeActivity = ComponentName.unflattenFromString(
                mContext.getString(R.string.config_clusterHomeActivity));
        mLastIntent = new Intent(ACTION_MAIN).setComponent(mClusterHomeActivity);
    }

    @Override
    public void init() {
        Slogf.d(TAG, "initClusterHomeService");
        if (TextUtils.isEmpty(mClusterHomeActivity.getPackageName())
                || TextUtils.isEmpty(mClusterHomeActivity.getClassName())) {
            Slogf.i(TAG, "Improper ClusterHomeActivity: %s", mClusterHomeActivity);
            return;
        }
        if (!mClusterHalService.isCoreSupported()) {
            Slogf.e(TAG, "No Cluster HAL properties");
            return;
        }

        mServiceEnabled = true;
        mClusterHalService.setCallback(this);
        mClusterNavigationService.setClusterServiceCallback(this);

        mOccupantZoneService.registerCallback(mOccupantZoneCallback);
        initClusterDisplay();
    }

    private void initClusterDisplay() {
        int clusterDisplayId = mOccupantZoneService.getDisplayIdForDriver(
                CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER);
        Slogf.d(TAG, "initClusterDisplay: displayId=%d", clusterDisplayId);
        if (clusterDisplayId == Display.INVALID_DISPLAY) {
            Slogf.i(TAG, "No cluster display is defined");
        }
        if (clusterDisplayId == mClusterDisplayId) {
            return;  // Skip if the cluster display isn't changed.
        }
        mClusterDisplayId = clusterDisplayId;
        sendDisplayState(ClusterHomeManager.CONFIG_DISPLAY_ID);
        if (clusterDisplayId == Display.INVALID_DISPLAY) {
            return;
        }

        // Initialize mBounds only once.
        if (mBounds.right == 0 && mBounds.bottom == 0 && mBounds.left == 0 && mBounds.top == 0) {
            DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
            Display clusterDisplay = displayManager.getDisplay(clusterDisplayId);
            Point size = new Point();
            clusterDisplay.getRealSize(size);
            mBounds.right = size.x;
            mBounds.bottom = size.y;
            Slogf.d(TAG, "Found cluster displayId=%d, bounds=%s", clusterDisplayId, mBounds);
        }

        ActivityOptions activityOptions = ActivityOptions.makeBasic()
                .setLaunchDisplayId(clusterDisplayId);
        mFixedActivityService.startFixedActivityModeForDisplayAndUser(
                mLastIntent, activityOptions, clusterDisplayId, mLastIntentUserId);
    }

    private final ICarOccupantZoneCallback mOccupantZoneCallback =
            new ICarOccupantZoneCallback.Stub() {
                @Override
                public void onOccupantZoneConfigChanged(int flags) throws RemoteException {
                    if ((flags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY) != 0) {
                        initClusterDisplay();
                    }
                }
            };

    @Override
    public void release() {
        Slogf.d(TAG, "releaseClusterHomeService");
        mOccupantZoneService.unregisterCallback(mOccupantZoneCallback);
        mClusterHalService.setCallback(null);
        mClusterNavigationService.setClusterServiceCallback(null);
        mClientCallbacks.kill();
    }

    @Override
    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
    public void dump(IndentingPrintWriter writer) {
        // TODO: record the latest states from both sides
    }

    // ClusterHalEventListener starts
    @Override
    public void onSwitchUi(int uiType) {
        Slogf.d(TAG, "onSwitchUi: uiType=%d", uiType);
        int changes = 0;
        if (mUiType != uiType) {
            mUiType = uiType;
            changes |= ClusterHomeManager.CONFIG_UI_TYPE;
        }
        sendDisplayState(changes);
    }

    @Override
    public void onDisplayState(int onOff, Rect bounds, Insets insets) {
        Slogf.d(TAG, "onDisplayState: onOff=%d, bounds=%s, insets=%s", onOff, bounds, insets);
        int changes = 0;
        if (onOff != DONT_CARE && mOnOff != onOff) {
            mOnOff = onOff;
            changes |= ClusterHomeManager.CONFIG_DISPLAY_ON_OFF;
        }
        if (bounds != null && !mBounds.equals(bounds)) {
            mBounds = bounds;
            changes |= ClusterHomeManager.CONFIG_DISPLAY_BOUNDS;
        }
        if (insets != null && !mInsets.equals(insets)) {
            mInsets = insets;
            changes |= ClusterHomeManager.CONFIG_DISPLAY_INSETS;
        }
        sendDisplayState(changes);
    }
    // ClusterHalEventListener ends

    private void sendDisplayState(int changes) {
        ClusterState state = createClusterState();
        int n = mClientCallbacks.beginBroadcast();
        for (int i = 0; i < n; i++) {
            IClusterHomeCallback callback = mClientCallbacks.getBroadcastItem(i);
            try {
                callback.onClusterStateChanged(state, changes);
            } catch (RemoteException ignores) {
                // ignore
            }
        }
        mClientCallbacks.finishBroadcast();
    }

    // ClusterNavigationServiceCallback starts
    @Override
    public void onNavigationStateChanged(Bundle bundle) {
        byte[] protoBytes = bundle.getByteArray(NAV_STATE_PROTO_BUNDLE_KEY);

        sendNavigationState(protoBytes);
    }

    private void sendNavigationState(byte[] protoBytes) {
        final int n = mClientCallbacks.beginBroadcast();
        for (int i = 0; i < n; i++) {
            IClusterHomeCallback callback = mClientCallbacks.getBroadcastItem(i);
            try {
                callback.onNavigationStateChanged(protoBytes);
            } catch (RemoteException ignores) {
                // ignore
            }
        }
        mClientCallbacks.finishBroadcast();

        if (!mClusterHalService.isNavigationStateSupported()) {
            Slogf.d(TAG, "No Cluster NavigationState HAL property");
            return;
        }
        mClusterHalService.sendNavigationState(protoBytes);
    }

    @Override
    public CarNavigationInstrumentCluster getInstrumentClusterInfo() {
        return CarNavigationInstrumentCluster.createCluster(DEFAULT_MIN_UPDATE_INTERVAL_MILLIS);
    }

    @Override
    public void notifyNavContextOwnerChanged(ClusterNavigationService.ContextOwner owner) {
        Slogf.d(TAG, "notifyNavContextOwnerChanged: owner=%s", owner);
        // Sends the empty NavigationStateProto to clear out the last direction
        // when the app context owner is changed or the navigation is finished.
        NavigationStateProto emptyProto = NavigationStateProto.newBuilder()
                .setServiceStatus(NavigationStateProto.ServiceStatus.NORMAL).build();
        sendNavigationState(emptyProto.toByteArray());
    }
    // ClusterNavigationServiceCallback ends

    // IClusterHomeService starts
    @Override
    public void reportState(int uiTypeMain, int uiTypeSub, byte[] uiAvailability) {
        Slogf.d(TAG, "reportState: main=%d, sub=%d", uiTypeMain, uiTypeSub);
        enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
        if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");

        mClusterHalService.reportState(mOnOff, mBounds, mInsets,
                uiTypeMain, uiTypeSub, uiAvailability);
    }

    @Override
    public void requestDisplay(int uiType) {
        Slogf.d(TAG, "requestDisplay: uiType=%d", uiType);
        enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
        if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");

        mClusterHalService.requestDisplay(uiType);
    }

    @Override
    public boolean startFixedActivityModeAsUser(Intent intent,
            Bundle activityOptionsBundle, int userId) {
        Slogf.d(TAG, "startFixedActivityModeAsUser: intent=%s, userId=%d", intent, userId);
        enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
        if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");
        if (mClusterDisplayId == Display.INVALID_DISPLAY) {
            Slogf.e(TAG, "Cluster display is not ready.");
            return false;
        }

        ActivityOptions activityOptions = ActivityOptions.fromBundle(activityOptionsBundle);
        activityOptions.setLaunchDisplayId(mClusterDisplayId);
        mLastIntent = intent;
        mLastIntentUserId = userId;
        return mFixedActivityService.startFixedActivityModeForDisplayAndUser(
                intent, activityOptions, mClusterDisplayId, userId);
    }

    @Override
    public void stopFixedActivityMode() {
        enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
        if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");
        if (mClusterDisplayId == Display.INVALID_DISPLAY) {
            Slogf.e(TAG, "Cluster display is not ready.");
            return;
        }

        mFixedActivityService.stopFixedActivityMode(mClusterDisplayId);
    }

    @Override
    public void registerCallback(IClusterHomeCallback callback) {
        enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
        if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");

        mClientCallbacks.register(callback);
    }

    @Override
    public void unregisterCallback(IClusterHomeCallback callback) {
        enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
        if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");

        mClientCallbacks.unregister(callback);
    }

    @Override
    public ClusterState getClusterState() {
        Slogf.d(TAG, "getClusterState");
        enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
        if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");
        return createClusterState();
    }
    // IClusterHomeService ends

    private void enforcePermission(String permissionName) {
        if (mContext.checkCallingOrSelfPermission(permissionName)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("requires permission " + permissionName);
        }
    }

    private ClusterState createClusterState() {
        ClusterState state = new ClusterState();
        state.on = mOnOff == DISPLAY_ON;
        state.bounds = mBounds;
        state.insets = mInsets;
        state.uiType = mUiType;
        state.displayId = mClusterDisplayId;
        return state;
    }
}
