/*
 * Copyright (C) 2014 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.telecomm;

import android.Manifest;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.telecomm.AudioState;
import android.telecomm.CallState;
import android.telecomm.InCallService;
import android.telecomm.ParcelableCall;
import android.telecomm.PhoneCapabilities;
import android.telecomm.PropertyPresentation;
import android.util.ArrayMap;

import com.android.internal.telecomm.IInCallService;
import com.google.common.collect.ImmutableCollection;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Binds to {@link IInCallService} and provides the service to {@link CallsManager} through which it
 * can send updates to the in-call app. This class is created and owned by CallsManager and retains
 * a binding to the {@link IInCallService} (implemented by the in-call app).
 */
public final class InCallController extends CallsManagerListenerBase {
    /**
     * Used to bind to the in-call app and triggers the start of communication between
     * this class and in-call app.
     */
    private class InCallServiceConnection implements ServiceConnection {
        /** {@inheritDoc} */
        @Override public void onServiceConnected(ComponentName name, IBinder service) {
            onConnected(name, service);
        }

        /** {@inheritDoc} */
        @Override public void onServiceDisconnected(ComponentName name) {
            onDisconnected(name);
        }
    }

    private final Call.Listener mCallListener = new Call.ListenerBase() {
        @Override
        public void onCallCapabilitiesChanged(Call call) {
            updateCall(call);
        }

        @Override
        public void onCannedSmsResponsesLoaded(Call call) {
            updateCall(call);
        }

        @Override
        public void onVideoCallProviderChanged(Call call) {
            updateCall(call);
        }

        @Override
        public void onStatusHintsChanged(Call call) {
            updateCall(call);
        }

        @Override
        public void onHandleChanged(Call call) {
            updateCall(call);
        }

        @Override
        public void onCallerDisplayNameChanged(Call call) {
            updateCall(call);
        }

        @Override
        public void onVideoStateChanged(Call call) {
            updateCall(call);
        }

        @Override
        public void onStartActivityFromInCall(Call call, PendingIntent intent) {
            if (!mInCallServices.isEmpty()) {
                Log.i(this, "Calling startActivity, intent: %s", intent);
                for (IInCallService inCallService : mInCallServices.values()) {
                    try {
                        inCallService.startActivity(mCallIdMapper.getCallId(call), intent);
                    } catch (RemoteException ignored) {
                    }
                }
            }
        }

        @Override
        public void onTargetPhoneAccountChanged(Call call) {
            updateCall(call);
        }

        @Override
        public void onConferenceableCallsChanged(Call call) {
            updateCall(call);
        }
    };

    /**
     * Maintains a binding connection to the in-call app(s).
     * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
     * load factor before resizing, 1 means we only expect a single thread to
     * access the map so make only a single shard
     */
    private final Map<ComponentName, InCallServiceConnection> mServiceConnections =
            new ConcurrentHashMap<ComponentName, InCallServiceConnection>(8, 0.9f, 1);

    /** The in-call app implementations, see {@link IInCallService}. */
    private final Map<ComponentName, IInCallService> mInCallServices = new ArrayMap<>();

    private final CallIdMapper mCallIdMapper = new CallIdMapper("InCall");

    /** The {@link ComponentName} of the default InCall UI. */
    private ComponentName mInCallComponentName;

    public InCallController() {
        Context context = TelecommApp.getInstance();
        Resources resources = context.getResources();

        mInCallComponentName = new ComponentName(
                resources.getString(R.string.ui_default_package),
                resources.getString(R.string.incall_default_class));
    }

    @Override
    public void onCallAdded(Call call) {
        if (mInCallServices.isEmpty()) {
            bind();
        } else {
            Log.i(this, "Adding call: %s", call);
            // Track the call if we don't already know about it.
            addCall(call);

            for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
                ComponentName componentName = entry.getKey();
                IInCallService inCallService = entry.getValue();

                ParcelableCall parcelableCall = toParcelableCall(call,
                        componentName.equals(mInCallComponentName) /* includeVideoProvider */);
                try {
                    inCallService.addCall(parcelableCall);
                } catch (RemoteException ignored) {
                }
            }
        }
    }

    @Override
    public void onCallRemoved(Call call) {
        if (CallsManager.getInstance().getCalls().isEmpty()) {
            // TODO: Wait for all messages to be delivered to the service before unbinding.
            unbind();
        }
        call.removeListener(mCallListener);
        mCallIdMapper.removeCall(call);
    }

    @Override
    public void onCallStateChanged(Call call, int oldState, int newState) {
        updateCall(call);
    }

    @Override
    public void onConnectionServiceChanged(
            Call call,
            ConnectionServiceWrapper oldService,
            ConnectionServiceWrapper newService) {
        updateCall(call);
    }

    @Override
    public void onAudioStateChanged(AudioState oldAudioState, AudioState newAudioState) {
        if (!mInCallServices.isEmpty()) {
            Log.i(this, "Calling onAudioStateChanged, audioState: %s -> %s", oldAudioState,
                    newAudioState);
            for (IInCallService inCallService : mInCallServices.values()) {
                try {
                    inCallService.onAudioStateChanged(newAudioState);
                } catch (RemoteException ignored) {
                }
            }
        }
    }

    void onPostDialWait(Call call, String remaining) {
        if (!mInCallServices.isEmpty()) {
            Log.i(this, "Calling onPostDialWait, remaining = %s", remaining);
            for (IInCallService inCallService : mInCallServices.values()) {
                try {
                    inCallService.setPostDialWait(mCallIdMapper.getCallId(call), remaining);
                } catch (RemoteException ignored) {
                }
            }
        }
    }

    @Override
    public void onIsConferencedChanged(Call call) {
        Log.d(this, "onIsConferencedChanged %s", call);
        updateCall(call);
    }

    void bringToForeground(boolean showDialpad) {
        if (!mInCallServices.isEmpty()) {
            for (IInCallService inCallService : mInCallServices.values()) {
                try {
                    inCallService.bringToForeground(showDialpad);
                } catch (RemoteException ignored) {
                }
            }
        } else {
            Log.w(this, "Asking to bring unbound in-call UI to foreground.");
        }
    }

    /**
     * Unbinds an existing bound connection to the in-call app.
     */
    private void unbind() {
        ThreadUtil.checkOnMainThread();
        if (!mInCallServices.isEmpty()) {
            Log.i(this, "Unbinding from InCallService");
            for (InCallServiceConnection connection : mServiceConnections.values()) {
                TelecommApp.getInstance().unbindService(connection);
            }
            mInCallServices.clear();
        }
    }

    /**
     * Binds to the in-call app if not already connected by binding directly to the saved
     * component name of the {@link IInCallService} implementation.
     */
    private void bind() {
        ThreadUtil.checkOnMainThread();
        if (mInCallServices.isEmpty()) {
            mServiceConnections.clear();
            Context context = TelecommApp.getInstance();
            PackageManager packageManager = TelecommApp.getInstance().getPackageManager();
            Intent intent = new Intent(InCallService.SERVICE_INTERFACE);

            for (ResolveInfo entry : packageManager.queryIntentServices(intent, 0)) {
                ServiceInfo serviceInfo = entry.serviceInfo;
                if (serviceInfo != null) {
                    boolean hasServiceBindPermission = serviceInfo.permission != null &&
                            serviceInfo.permission.equals(
                                    Manifest.permission.BIND_INCALL_SERVICE);
                    boolean hasControlInCallPermission = packageManager.checkPermission(
                            Manifest.permission.CONTROL_INCALL_EXPERIENCE,
                            serviceInfo.packageName) == PackageManager.PERMISSION_GRANTED;

                    if (!hasServiceBindPermission) {
                        Log.w(this, "InCallService does not have BIND_INCALL_SERVICE permission: " +
                                serviceInfo.packageName);
                        continue;
                    }

                    if (!hasControlInCallPermission) {
                        Log.w(this,
                                "InCall UI does not have CONTROL_INCALL_EXPERIENCE permission: " +
                                        serviceInfo.packageName);
                        continue;
                    }

                    Log.i(this, "Attempting to bind to InCall " + serviceInfo.packageName);
                    InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
                    ComponentName componentName = new ComponentName(serviceInfo.packageName,
                            serviceInfo.name);
                    intent.setComponent(componentName);

                    if (context.bindServiceAsUser(intent, inCallServiceConnection,
                            Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
                        mServiceConnections.put(componentName, inCallServiceConnection);
                    }
                }
            }
        }
    }

    /**
     * Persists the {@link IInCallService} instance and starts the communication between
     * this class and in-call app by sending the first update to in-call app. This method is
     * called after a successful binding connection is established.
     *
     * @param componentName The service {@link ComponentName}.
     * @param service The {@link IInCallService} implementation.
     */
    private void onConnected(ComponentName componentName, IBinder service) {
        ThreadUtil.checkOnMainThread();

        IInCallService inCallService = IInCallService.Stub.asInterface(service);

        try {
            inCallService.setInCallAdapter(new InCallAdapter(CallsManager.getInstance(),
                    mCallIdMapper));
            mInCallServices.put(componentName, inCallService);
        } catch (RemoteException e) {
            Log.e(this, e, "Failed to set the in-call adapter.");
            return;
        }

        // Upon successful connection, send the state of the world to the service.
        ImmutableCollection<Call> calls = CallsManager.getInstance().getCalls();
        if (!calls.isEmpty()) {
            for (Call call : calls) {
                try {
                    // Track the call if we don't already know about it.
                    addCall(call);

                    inCallService.addCall(toParcelableCall(call,
                            componentName.equals(mInCallComponentName) /* includeVideoProvider */));
                } catch (RemoteException ignored) {
                }
            }
            onAudioStateChanged(null, CallsManager.getInstance().getAudioState());
        } else {
            unbind();
        }
    }

    /**
     * Cleans up an instance of in-call app after the service has been unbound.
     *
     * @param disconnectedComponent The {@link ComponentName} of the service which disconnected.
     */
    private void onDisconnected(ComponentName disconnectedComponent) {
        ThreadUtil.checkOnMainThread();
        if (mInCallServices.containsKey(disconnectedComponent)) {
            mInCallServices.remove(disconnectedComponent);
        }

        // If the default in-call UI has disconnected, disconnect all calls and un-bind all other
        // InCallService implementations.
        if (disconnectedComponent.equals(mInCallComponentName)) {
            Log.i(this, "In-call UI %s disconnected.", disconnectedComponent);
            CallsManager.getInstance().disconnectAllCalls();

            // Iterate through the in-call services, removing them as they are un-bound.
            Iterator<Map.Entry<ComponentName, IInCallService>> it =
                    mInCallServices.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<ComponentName, IInCallService> entry = it.next();
                ComponentName componentName = entry.getKey();

                InCallServiceConnection connection =  mServiceConnections.remove(componentName);
                it.remove();
                if (connection == null) {
                    continue;
                }

                Log.i(this, "Unbinding other InCallService %s", componentName);
                TelecommApp.getInstance().unbindService(connection);
            }
        }
    }

    /**
     * Informs all {@link InCallService} instances of the updated call information.  Changes to the
     * video provider are only communicated to the default in-call UI.
     *
     * @param call The {@link Call}.
     */
    private void updateCall(Call call) {
        if (!mInCallServices.isEmpty()) {
            for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
                ComponentName componentName = entry.getKey();
                IInCallService inCallService = entry.getValue();
                ParcelableCall parcelableCall = toParcelableCall(call,
                        componentName.equals(mInCallComponentName) /* includeVideoProvider */);

                Log.v(this, "updateCall %s ==> %s", call, parcelableCall);
                try {
                    inCallService.updateCall(parcelableCall);
                } catch (RemoteException ignored) {
                }
            }
        }
    }

    /**
     * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
     *
     * @param call The {@link Call} to parcel.
     * @param includeVideoProvider When {@code true}, the {@link IVideoProvider} is included in the
     *      parcelled call.  When {@code false}, the {@link IVideoProvider} is not included.
     * @return The {@link ParcelableCall} containing all call information from the {@link Call}.
     */
    private ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider) {
        String callId = mCallIdMapper.getCallId(call);

        int capabilities = call.getCallCapabilities();
        if (CallsManager.getInstance().isAddCallCapable(call)) {
            capabilities |= PhoneCapabilities.ADD_CALL;
        }
        if (!call.isEmergencyCall()) {
            capabilities |= PhoneCapabilities.MUTE;
        }

        int state = call.getState();
        if (state == CallState.ABORTED) {
            state = CallState.DISCONNECTED;
        }

        String parentCallId = null;
        Call parentCall = call.getParentCall();
        if (parentCall != null) {
            parentCallId = mCallIdMapper.getCallId(parentCall);
        }

        long connectTimeMillis = call.getConnectTimeMillis();
        List<Call> childCalls = call.getChildCalls();
        List<String> childCallIds = new ArrayList<>();
        if (!childCalls.isEmpty()) {
            connectTimeMillis = Long.MAX_VALUE;
            for (Call child : childCalls) {
                connectTimeMillis = Math.min(child.getConnectTimeMillis(), connectTimeMillis);
                childCallIds.add(mCallIdMapper.getCallId(child));
            }
        }

        if (call.isRespondViaSmsCapable()) {
            capabilities |= PhoneCapabilities.RESPOND_VIA_TEXT;
        }

        Uri handle = call.getHandlePresentation() == PropertyPresentation.ALLOWED ?
                call.getHandle() : null;
        String callerDisplayName = call.getCallerDisplayNamePresentation() ==
                PropertyPresentation.ALLOWED ?  call.getCallerDisplayName() : null;

        List<Call> conferenceableCalls = call.getConferenceableCalls();
        List<String> conferenceableCallIds = new ArrayList<String>(conferenceableCalls.size());
        for (Call otherCall : conferenceableCalls) {
            String otherId = mCallIdMapper.getCallId(otherCall);
            if (otherId != null) {
                conferenceableCallIds.add(otherId);
            }
        }

        return new ParcelableCall(
                callId,
                state,
                call.getDisconnectCause(),
                call.getDisconnectMessage(),
                call.getCannedSmsResponses(),
                capabilities,
                connectTimeMillis,
                handle,
                call.getHandlePresentation(),
                callerDisplayName,
                call.getCallerDisplayNamePresentation(),
                call.getGatewayInfo(),
                call.getTargetPhoneAccount(),
                includeVideoProvider ? call.getVideoProvider() : null,
                parentCallId,
                childCallIds,
                call.getStatusHints(),
                call.getVideoState(),
                conferenceableCallIds,
                call.getExtras());
    }

    /**
     * Adds the call to the list of calls tracked by the {@link InCallController}.
     * @param call The call to add.
     */
    private void addCall(Call call) {
        if (mCallIdMapper.getCallId(call) == null) {
            mCallIdMapper.addCall(call);
            call.addListener(mCallListener);
        }
    }
}
