/*
 * 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) {
                    Log.e(TAG, "Replacing an existing IFusedLocationHardware sink");
                }

                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;
            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;
    }
}
