/*
 * Copyright (C) 2013 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.server.location;

import android.hardware.location.GeofenceHardware;
import android.hardware.location.GeofenceHardwareImpl;
import android.hardware.location.GeofenceHardwareRequestParcelable;
import android.hardware.location.IFusedLocationHardware;
import android.hardware.location.IFusedLocationHardwareSink;
import android.location.IFusedGeofenceHardware;
import android.location.FusedBatchOptions;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationRequest;

import android.content.Context;
import android.os.Bundle;
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;

/**
 * This class is an interop layer for JVM types and the JNI code that interacts
 * with the FLP HAL implementation.
 *
 * {@hide}
 */
public class FlpHardwareProvider {
    private GeofenceHardwareImpl mGeofenceHardwareSink = null;
    private IFusedLocationHardwareSink mLocationSink = null;

    private static FlpHardwareProvider sSingletonInstance = null;

    private final static String TAG = "FlpHardwareProvider";
    private final Context mContext;
    private final Object mLocationSinkLock = new Object();

    // FlpHal result codes, they must be equal to the ones in fused_location.h
    private static final int FLP_RESULT_SUCCESS = 0;
    private static final int FLP_RESULT_ERROR = -1;
    private static final int FLP_RESULT_INSUFFICIENT_MEMORY = -2;
    private static final int FLP_RESULT_TOO_MANY_GEOFENCES = -3;
    private static final int FLP_RESULT_ID_EXISTS = -4;
    private static final int FLP_RESULT_ID_UNKNOWN = -5;
    private static final int FLP_RESULT_INVALID_GEOFENCE_TRANSITION = -6;

    // FlpHal monitor status codes, they must be equal to the ones in fused_location.h
    private static final int FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE = 1<<0;
    private static final int FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE = 1<<1;

    public static FlpHardwareProvider getInstance(Context context) {
        if (sSingletonInstance == null) {
            sSingletonInstance = new FlpHardwareProvider(context);
            sSingletonInstance.nativeInit();
        }

        return sSingletonInstance;
    }

    private FlpHardwareProvider(Context context) {
        mContext = context;

        // register for listening for passive provider data
        LocationManager manager = (LocationManager) mContext.getSystemService(
                Context.LOCATION_SERVICE);
        final long minTime = 0;
        final float minDistance = 0;
        final boolean oneShot = false;
        LocationRequest request = LocationRequest.createFromDeprecatedProvider(
                LocationManager.PASSIVE_PROVIDER,
                minTime,
                minDistance,
                oneShot);
        // Don't keep track of this request since it's done on behalf of other clients
        // (which are kept track of separately).
        request.setHideFromAppOps(true);
        manager.requestLocationUpdates(
                request,
                new NetworkLocationListener(),
                Looper.myLooper());
    }

    public static boolean isSupported() {
        return nativeIsSupported();
    }

    /**
     * Private callback functions used by FLP HAL.
     */
    // FlpCallbacks members
    private void onLocationReport(Location[] locations) {
        for (Location location : locations) {
            location.setProvider(LocationManager.FUSED_PROVIDER);
            // set the elapsed time-stamp just as GPS provider does
            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
        }

        IFusedLocationHardwareSink sink;
        synchronized (mLocationSinkLock) {
            sink = mLocationSink;
        }
        try {
            if (sink != null) {
                sink.onLocationAvailable(locations);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException calling onLocationAvailable");
        }
    }

    // FlpDiagnosticCallbacks members
    private void onDataReport(String data) {
        IFusedLocationHardwareSink sink;
        synchronized (mLocationSinkLock) {
            sink = mLocationSink;
        }
        try {
            if (mLocationSink != null) {
                sink.onDiagnosticDataAvailable(data);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException calling onDiagnosticDataAvailable");
        }
    }

    // FlpGeofenceCallbacks members
    private void onGeofenceTransition(
            int geofenceId,
            Location location,
            int transition,
            long timestamp,
            int sourcesUsed) {
        // the transition Id does not require translation because the values in fused_location.h
        // and GeofenceHardware are in sync
        getGeofenceHardwareSink().reportGeofenceTransition(
                geofenceId,
                updateLocationInformation(location),
                transition,
                timestamp,
                GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
                sourcesUsed);
    }

    private void onGeofenceMonitorStatus(int status, int source, Location location) {
        // allow the location to be optional in this event
        Location updatedLocation = null;
        if(location != null) {
            updatedLocation = updateLocationInformation(location);
        }

        int monitorStatus;
        switch (status) {
            case FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE:
                monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
                break;
            case FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE:
                monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
                break;
            default:
                Log.e(TAG, "Invalid FlpHal Geofence monitor status: " + status);
                monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
                break;
        }

        getGeofenceHardwareSink().reportGeofenceMonitorStatus(
                GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
                monitorStatus,
                updatedLocation,
                source);
    }

    private void onGeofenceAdd(int geofenceId, int result) {
        getGeofenceHardwareSink().reportGeofenceAddStatus(
                geofenceId,
                translateToGeofenceHardwareStatus(result));
    }

    private void onGeofenceRemove(int geofenceId, int result) {
        getGeofenceHardwareSink().reportGeofenceRemoveStatus(
                geofenceId,
                translateToGeofenceHardwareStatus(result));
    }

    private void onGeofencePause(int geofenceId, int result) {
        getGeofenceHardwareSink().reportGeofencePauseStatus(
                geofenceId,
                translateToGeofenceHardwareStatus(result));
    }

    private void onGeofenceResume(int geofenceId, int result) {
        getGeofenceHardwareSink().reportGeofenceResumeStatus(
                geofenceId,
                translateToGeofenceHardwareStatus(result));
    }

    /**
     * Private native methods accessing FLP HAL.
     */
    static { nativeClassInit(); }

    // Core members
    private static native void nativeClassInit();
    private static native boolean nativeIsSupported();

    // FlpLocationInterface members
    private native void nativeInit();
    private native int nativeGetBatchSize();
    private native void nativeStartBatching(int requestId, FusedBatchOptions options);
    private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject);
    private native void nativeStopBatching(int id);
    private native void nativeRequestBatchedLocation(int lastNLocations);
    private native void nativeInjectLocation(Location location);
    // TODO [Fix] sort out the lifetime of the instance
    private native void nativeCleanup();

    // FlpDiagnosticsInterface members
    private native boolean nativeIsDiagnosticSupported();
    private native void nativeInjectDiagnosticData(String data);

    // FlpDeviceContextInterface members
    private native boolean nativeIsDeviceContextSupported();
    private native void nativeInjectDeviceContext(int deviceEnabledContext);

    // FlpGeofencingInterface members
    private native boolean nativeIsGeofencingSupported();
    private native void nativeAddGeofences(
            GeofenceHardwareRequestParcelable[] geofenceRequestsArray);
    private native void nativePauseGeofence(int geofenceId);
    private native void  nativeResumeGeofence(int geofenceId, int monitorTransitions);
    private native void nativeModifyGeofenceOption(
        int geofenceId,
        int lastTransition,
        int monitorTransitions,
        int notificationResponsiveness,
        int unknownTimer,
        int sourcesToUse);
    private native void nativeRemoveGeofences(int[] geofenceIdsArray);

    /**
     * Interface implementations for services built on top of this functionality.
     */
    public static final String LOCATION = "Location";
    public static final String GEOFENCING = "Geofencing";

    public IFusedLocationHardware getLocationHardware() {
        return mLocationHardware;
    }

    public IFusedGeofenceHardware getGeofenceHardware() {
        return mGeofenceHardwareService;
    }

    private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() {
        @Override
        public void registerSink(IFusedLocationHardwareSink eventSink) {
            synchronized (mLocationSinkLock) {
                // only one sink is allowed at the moment
                if (mLocationSink != null) {
                    throw new RuntimeException(
                            "IFusedLocationHardware does not support multiple sinks");
                }

                mLocationSink = eventSink;
            }
        }

        @Override
        public void unregisterSink(IFusedLocationHardwareSink eventSink) {
            synchronized (mLocationSinkLock) {
                // don't throw if the sink is not registered, simply make it a no-op
                if (mLocationSink == eventSink) {
                    mLocationSink = null;
                }
            }
        }

        @Override
        public int getSupportedBatchSize() {
            return nativeGetBatchSize();
        }

        @Override
        public void startBatching(int requestId, FusedBatchOptions options) {
            nativeStartBatching(requestId, options);
        }

        @Override
        public void stopBatching(int requestId) {
            nativeStopBatching(requestId);
        }

        @Override
        public void updateBatchingOptions(int requestId, FusedBatchOptions options) {
            nativeUpdateBatchingOptions(requestId, options);
        }

        @Override
        public void requestBatchOfLocations(int batchSizeRequested) {
            nativeRequestBatchedLocation(batchSizeRequested);
        }

        @Override
        public boolean supportsDiagnosticDataInjection() {
            return nativeIsDiagnosticSupported();
        }

        @Override
        public void injectDiagnosticData(String data) {
            nativeInjectDiagnosticData(data);
        }

        @Override
        public boolean supportsDeviceContextInjection() {
            return nativeIsDeviceContextSupported();
        }

        @Override
        public void injectDeviceContext(int deviceEnabledContext) {
            nativeInjectDeviceContext(deviceEnabledContext);
        }
    };

    private final IFusedGeofenceHardware mGeofenceHardwareService =
            new IFusedGeofenceHardware.Stub() {
        @Override
        public boolean isSupported() {
            return nativeIsGeofencingSupported();
        }

        @Override
        public void addGeofences(GeofenceHardwareRequestParcelable[] geofenceRequestsArray) {
            nativeAddGeofences(geofenceRequestsArray);
        }

        @Override
        public void removeGeofences(int[] geofenceIds) {
            nativeRemoveGeofences(geofenceIds);
        }

        @Override
        public void pauseMonitoringGeofence(int geofenceId) {
            nativePauseGeofence(geofenceId);
        }

        @Override
        public void resumeMonitoringGeofence(int geofenceId, int monitorTransitions) {
            nativeResumeGeofence(geofenceId, monitorTransitions);
        }

        @Override
        public void modifyGeofenceOptions(int geofenceId,
                int lastTransition,
                int monitorTransitions,
                int notificationResponsiveness,
                int unknownTimer,
                int sourcesToUse) {
            nativeModifyGeofenceOption(
                    geofenceId,
                    lastTransition,
                    monitorTransitions,
                    notificationResponsiveness,
                    unknownTimer,
                    sourcesToUse);
        }
    };

    /**
     * Internal classes and functions used by the provider.
     */
    private final class NetworkLocationListener implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            if (
                !LocationManager.NETWORK_PROVIDER.equals(location.getProvider()) ||
                !location.hasAccuracy()
                ) {
                return;
            }

            nativeInjectLocation(location);
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) { }

        @Override
        public void onProviderEnabled(String provider) { }

        @Override
        public void onProviderDisabled(String provider) { }
    }

    private GeofenceHardwareImpl getGeofenceHardwareSink() {
        if (mGeofenceHardwareSink == null) {
            mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext);
        }

        return mGeofenceHardwareSink;
    }

    private static int translateToGeofenceHardwareStatus(int flpHalResult) {
        switch(flpHalResult) {
            case FLP_RESULT_SUCCESS:
                return GeofenceHardware.GEOFENCE_SUCCESS;
            case FLP_RESULT_ERROR:
                return GeofenceHardware.GEOFENCE_FAILURE;
            // TODO: uncomment this once the ERROR definition is marked public
            //case FLP_RESULT_INSUFFICIENT_MEMORY:
            //    return GeofenceHardware.GEOFENCE_ERROR_INSUFFICIENT_MEMORY;
            case FLP_RESULT_TOO_MANY_GEOFENCES:
                return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
            case FLP_RESULT_ID_EXISTS:
                return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
            case FLP_RESULT_ID_UNKNOWN:
                return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
            case FLP_RESULT_INVALID_GEOFENCE_TRANSITION:
                return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
            default:
                Log.e(TAG, String.format("Invalid FlpHal result code: %d", flpHalResult));
                return GeofenceHardware.GEOFENCE_FAILURE;
        }
    }

    private Location updateLocationInformation(Location location) {
        location.setProvider(LocationManager.FUSED_PROVIDER);
        // set the elapsed time-stamp just as GPS provider does
        location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
        return location;
    }
}
