/**
 * Wi-Fi в метро (pw.thedrhax.mosmetro, Moscow Wi-Fi autologin)
 * Copyright © 2015 Dmitry Karikh <[email protected]>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package pw.thedrhax.mosmetro.services;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiManager;
import android.preference.PreferenceManager;

import java.util.Locale;

import pw.thedrhax.util.Logger;
import pw.thedrhax.util.WifiUtils;

/**
 * This BroadcastReceiver filters and sends Intents to the ConnectionService.
 *
 * There are two types of Intents accepted by the ConnectionService:
 *     1) Wi-Fi network is definitely connected (startService())
 *     2) No Wi-Fi networks are connected (stopService())
 *
 * NetworkReceiver doesn't take care of:
 *     1) Ignoring duplicated Intents
 *     2) Determining if current SSID is supported by the Provider
 *
 * @see ConnectionService
 * @author Dmitry Karikh <[email protected]>
 */
public class NetworkReceiver extends BroadcastReceiver {
    private Context context;
    private Intent intent;

    public void onReceive(Context context, Intent intent) {
        this.context = context;
        this.intent = intent;

        // Stop if Intent is empty
        if (intent == null || intent.getAction() == null)
            return;

        // Stop if automatic connection is disabled in settings
        SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
        if (!settings.getBoolean("pref_autoconnect", true))
            return;

        // If Wi-Fi is disabled, stop ConnectionService immediately
        WifiUtils wifi = new WifiUtils(context);
        if (!wifi.isEnabled()) {
            Logger.log(this, "Wi-Fi not enabled");
            stopService();
            return;
        }

        SupplicantState state = null;

        /**
         * Listen to all Wi-Fi state changes and start ConnectionService if Wi-Fi is connected
         */
        if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) {
            state = wifi.getWifiInfo(intent).getSupplicantState();
        }

        /**
         * Catch extra SupplicantState broadcast for devices that are skipping
         * STATE_CHANGE with state == DISCONNECTED
         */
        if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(intent.getAction())) {
            state = intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
        }

        if (state != null) {
            Logger.log(this, String.format(Locale.ENGLISH, "Intent: %s (%s)",
                    intent.getAction(), state.name()
            ));

            switch (state) {
                case COMPLETED:
                case ASSOCIATED: // This appears randomly between multiple CONNECTED states
                    startService();
                    break;
                case SCANNING: // Some devices do not report DISCONNECTED state so...
                case DISCONNECTED:
                    stopService();
                    break;
                default:
                    Logger.log(this, "Unknown SupplicantState: " + state.name());
            }
        } else {
            Logger.log(this, "Unknown Intent: " + intent.getAction());
        }
    }

    /**
     * Start ConnectionService and pass received Intent's content
     */
    private void startService() {
        Intent service = new Intent(context, ConnectionService.class);
        service.setAction(intent.getAction());
        service.putExtras(intent);
        context.startService(service);
    }

    /**
     * Stop ConnectionService
     */
    private void stopService() {
        context.startService(new Intent(context, ConnectionService.class).setAction("STOP"));
    }
}