/*
 * Copyright (C) 2019 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.content.Context;
import android.os.PersistableBundle;
import android.os.SystemProperties;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.Log;

import com.android.internal.util.FrameworkStatsLog;

import libcore.io.IoUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

/**
 * A utility class to hold GNSS configuration properties.
 *
 * The trigger to load/reload the configuration parameters should be managed by the class
 * that owns an instance of this class.
 *
 * Instances of this class are not thread-safe and should either be used from a single thread
 * or with external synchronization when used by multiple threads.
 */
class GnssConfiguration {
    private static final String TAG = "GnssConfiguration";

    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";

    // config.xml properties
    private static final String CONFIG_SUPL_HOST = "SUPL_HOST";
    private static final String CONFIG_SUPL_PORT = "SUPL_PORT";
    private static final String CONFIG_C2K_HOST = "C2K_HOST";
    private static final String CONFIG_C2K_PORT = "C2K_PORT";
    private static final String CONFIG_SUPL_VER = "SUPL_VER";
    private static final String CONFIG_SUPL_MODE = "SUPL_MODE";
    private static final String CONFIG_SUPL_ES = "SUPL_ES";
    private static final String CONFIG_LPP_PROFILE = "LPP_PROFILE";
    private static final String CONFIG_A_GLONASS_POS_PROTOCOL_SELECT =
            "A_GLONASS_POS_PROTOCOL_SELECT";
    private static final String CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL =
            "USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL";
    private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
    private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
    public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";

    // Limit on NI emergency mode time extension after emergency sessions ends
    private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum

    // Persist property for LPP_PROFILE
    static final String LPP_PROFILE = "persist.sys.gps.lpp";

    // Represents an HAL interface version. Instances of this class are created in the JNI layer
    // and returned through native methods.
    private static class HalInterfaceVersion {
        final int mMajor;
        final int mMinor;

        HalInterfaceVersion(int major, int minor) {
            mMajor = major;
            mMinor = minor;
        }
    }

    /**
     * Properties loaded from PROPERTIES_FILE.
     */
    private Properties mProperties;

    private int mEsExtensionSec = 0;

    private final Context mContext;

    GnssConfiguration(Context context) {
        mContext = context;
        mProperties = new Properties();
    }

    /**
     * Returns the full set of properties loaded.
     */
    Properties getProperties() {
        return mProperties;
    }

    /**
     * Returns the value of config parameter ES_EXTENSION_SEC. The value is range checked
     * and constrained to min/max limits.
     */
    int getEsExtensionSec() {
        return mEsExtensionSec;
    }

    /**
     * Returns the value of config parameter SUPL_HOST or {@code null} if no value is
     * provided.
     */
    String getSuplHost() {
        return mProperties.getProperty(CONFIG_SUPL_HOST);
    }

    /**
     * Returns the value of config parameter SUPL_PORT or {@code defaultPort} if no value is
     * provided or if there is an error parsing the configured value.
     */
    int getSuplPort(int defaultPort) {
        return getIntConfig(CONFIG_SUPL_PORT, defaultPort);
    }

    /**
     * Returns the value of config parameter C2K_HOST or {@code null} if no value is
     * provided.
     */
    String getC2KHost() {
        return mProperties.getProperty(CONFIG_C2K_HOST);
    }

    /**
     * Returns the value of config parameter C2K_PORT or {@code defaultPort} if no value is
     * provided or if there is an error parsing the configured value.
     */
    int getC2KPort(int defaultPort) {
        return getIntConfig(CONFIG_C2K_PORT, defaultPort);
    }

    /**
     * Returns the value of config parameter SUPL_MODE or {@code defaultMode} if no value is
     * provided or if there is an error parsing the configured value.
     */
    int getSuplMode(int defaultMode) {
        return getIntConfig(CONFIG_SUPL_MODE, defaultMode);
    }

    /**
     * Returns the value of config parameter SUPL_ES or {@code defaultSuplEs} if no value is
     * provided or if there is an error parsing the configured value.
     */
    int getSuplEs(int defaulSuplEs) {
        return getIntConfig(CONFIG_SUPL_ES, defaulSuplEs);
    }

    /**
     * Returns the value of config parameter LPP_PROFILE or {@code null} if no value is
     * provided.
     */
    String getLppProfile() {
        return mProperties.getProperty(CONFIG_LPP_PROFILE);
    }

    /**
     * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS or
     * {@Collections.EMPTY_LIST} if no value is provided.
     */
    List<String> getProxyApps() {
        // Space separated list of Android proxy app package names.
        String proxyAppsStr = mProperties.getProperty(CONFIG_NFW_PROXY_APPS);
        if (TextUtils.isEmpty(proxyAppsStr)) {
            return Collections.EMPTY_LIST;
        }

        String[] proxyAppsArray = proxyAppsStr.trim().split("\\s+");
        if (proxyAppsArray.length == 0) {
            return Collections.EMPTY_LIST;
        }

        ArrayList proxyApps = new ArrayList(proxyAppsArray.length);
        for (String proxyApp : proxyAppsArray) {
            proxyApps.add(proxyApp);
        }

        return proxyApps;
    }

    /**
     * Updates the GNSS HAL satellite blacklist.
     */
    void setSatelliteBlacklist(int[] constellations, int[] svids) {
        native_set_satellite_blacklist(constellations, svids);
    }

    interface SetCarrierProperty {
        boolean set(int value);
    }

    /**
     * Loads the GNSS properties from carrier config file followed by the properties from
     * gps debug config file.
     */
    void reloadGpsProperties() {
        if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + mProperties.size());
        loadPropertiesFromCarrierConfig();

        String lpp_prof = SystemProperties.get(LPP_PROFILE);
        if (!TextUtils.isEmpty(lpp_prof)) {
            // override default value of this if lpp_prof is not empty
            mProperties.setProperty(CONFIG_LPP_PROFILE, lpp_prof);
        }
        /*
         * Overlay carrier properties from a debug configuration file.
         */
        loadPropertiesFromGpsDebugConfig(mProperties);

        mEsExtensionSec = getRangeCheckedConfigEsExtensionSec();

        logConfigurations();

        final HalInterfaceVersion gnssConfigurationIfaceVersion =
                native_get_gnss_configuration_version();
        if (gnssConfigurationIfaceVersion != null) {
            // Set to a range checked value.
            if (isConfigEsExtensionSecSupported(gnssConfigurationIfaceVersion)
                    && !native_set_es_extension_sec(mEsExtensionSec)) {
                Log.e(TAG, "Unable to set " + CONFIG_ES_EXTENSION_SEC + ": " + mEsExtensionSec);
            }

            Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
                {
                    put(CONFIG_SUPL_VER, GnssConfiguration::native_set_supl_version);
                    put(CONFIG_SUPL_MODE, GnssConfiguration::native_set_supl_mode);

                    if (isConfigSuplEsSupported(gnssConfigurationIfaceVersion)) {
                        put(CONFIG_SUPL_ES, GnssConfiguration::native_set_supl_es);
                    }

                    put(CONFIG_LPP_PROFILE, GnssConfiguration::native_set_lpp_profile);
                    put(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT,
                            GnssConfiguration::native_set_gnss_pos_protocol_select);
                    put(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL,
                            GnssConfiguration::native_set_emergency_supl_pdn);

                    if (isConfigGpsLockSupported(gnssConfigurationIfaceVersion)) {
                        put(CONFIG_GPS_LOCK, GnssConfiguration::native_set_gps_lock);
                    }
                }
            };

            for (Entry<String, SetCarrierProperty> entry : map.entrySet()) {
                String propertyName = entry.getKey();
                String propertyValueString = mProperties.getProperty(propertyName);
                if (propertyValueString != null) {
                    try {
                        int propertyValueInt = Integer.decode(propertyValueString);
                        boolean result = entry.getValue().set(propertyValueInt);
                        if (!result) {
                            Log.e(TAG, "Unable to set " + propertyName);
                        }
                    } catch (NumberFormatException e) {
                        Log.e(TAG, "Unable to parse propertyName: " + propertyValueString);
                    }
                }
            }
        } else if (DEBUG) {
            Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
                    + " supported");
        }
    }

    private void logConfigurations() {
        FrameworkStatsLog.write(FrameworkStatsLog.GNSS_CONFIGURATION_REPORTED,
                getSuplHost(),
                getSuplPort(0),
                getC2KHost(),
                getC2KPort(0),
                getIntConfig(CONFIG_SUPL_VER, 0),
                getSuplMode(0),
                getSuplEs(0) == 1,
                getIntConfig(CONFIG_LPP_PROFILE, 0),
                getIntConfig(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT, 0),
                getIntConfig(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL, 0) == 1,
                getIntConfig(CONFIG_GPS_LOCK, 0),
                getEsExtensionSec(),
                mProperties.getProperty(CONFIG_NFW_PROXY_APPS));
    }

    /**
     * Loads GNSS properties from carrier config file.
     */
    void loadPropertiesFromCarrierConfig() {
        CarrierConfigManager configManager = (CarrierConfigManager)
                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
        if (configManager == null) {
            return;
        }

        int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
        PersistableBundle configs = SubscriptionManager.isValidSubscriptionId(ddSubId)
                ? configManager.getConfigForSubId(ddSubId) : null;
        if (configs == null) {
            if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config.");
            configs = CarrierConfigManager.getDefaultConfig();
        }
        for (String configKey : configs.keySet()) {
            if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) {
                String key = configKey
                        .substring(CarrierConfigManager.Gps.KEY_PREFIX.length())
                        .toUpperCase();
                Object value = configs.get(configKey);
                if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value);
                if (value instanceof String) {
                    // Most GPS properties are of String type; convert so.
                    mProperties.setProperty(key, (String) value);
                } else if (value != null) {
                    mProperties.setProperty(key, value.toString());
                }
            }
        }
    }

    private void loadPropertiesFromGpsDebugConfig(Properties properties) {
        try {
            File file = new File(DEBUG_PROPERTIES_FILE);
            FileInputStream stream = null;
            try {
                stream = new FileInputStream(file);
                properties.load(stream);
            } finally {
                IoUtils.closeQuietly(stream);
            }
        } catch (IOException e) {
            if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE);
        }
    }

    private int getRangeCheckedConfigEsExtensionSec() {
        int emergencyExtensionSeconds = getIntConfig(CONFIG_ES_EXTENSION_SEC, 0);
        if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) {
            Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds
                    + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS);
            emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS;
        } else if (emergencyExtensionSeconds < 0) {
            Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds
                    + " is negative, reset to zero.");
            emergencyExtensionSeconds = 0;
        }
        return emergencyExtensionSeconds;
    }

    private int getIntConfig(String configParameter, int defaultValue) {
        String valueString = mProperties.getProperty(configParameter);
        if (TextUtils.isEmpty(valueString)) {
            return defaultValue;
        }
        try {
            return Integer.decode(valueString);
        } catch (NumberFormatException e) {
            Log.e(TAG, "Unable to parse config parameter " + configParameter + " value: "
                    + valueString + ". Using default value: " + defaultValue);
            return defaultValue;
        }
    }

    private static boolean isConfigEsExtensionSecSupported(
            HalInterfaceVersion gnssConfiguartionIfaceVersion) {
        // ES_EXTENSION_SEC is introduced in @2.0::IGnssConfiguration.hal
        return gnssConfiguartionIfaceVersion.mMajor >= 2;
    }

    private static boolean isConfigSuplEsSupported(
            HalInterfaceVersion gnssConfiguartionIfaceVersion) {
        // SUPL_ES is deprecated in @2.0::IGnssConfiguration.hal
        return gnssConfiguartionIfaceVersion.mMajor < 2;
    }

    private static boolean isConfigGpsLockSupported(
            HalInterfaceVersion gnssConfiguartionIfaceVersion) {
        // GPS_LOCK is deprecated in @2.0::IGnssConfiguration.hal
        return gnssConfiguartionIfaceVersion.mMajor < 2;
    }

    private static native HalInterfaceVersion native_get_gnss_configuration_version();

    private static native boolean native_set_supl_version(int version);

    private static native boolean native_set_supl_mode(int mode);

    private static native boolean native_set_supl_es(int es);

    private static native boolean native_set_lpp_profile(int lppProfile);

    private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);

    private static native boolean native_set_gps_lock(int gpsLock);

    private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);

    private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);

    private static native boolean native_set_es_extension_sec(int emergencyExtensionSeconds);
}
