/*
 * Copyright (c) 2016, Psiphon Inc.
 * All rights reserved.
 *
 * 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 com.dragonssh.xhttpdemo.core.tunnel.vpn;

import android.annotation.TargetApi;
import android.content.Intent;
import android.net.VpnService;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.dragonssh.xhttpdemo.core.logger.SkStatus;

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class TunnelVpnService extends VpnService {

  private static final String LOG_TAG = "TunnelVpnService";
  public static final String TUNNEL_VPN_DISCONNECT_BROADCAST =
      "tunnelVpnDisconnectBroadcast";
  public static final String TUNNEL_VPN_START_BROADCAST =
      "tunnelVpnStartBroadcast";
  public static final String TUNNEL_VPN_START_SUCCESS_EXTRA =
      "tunnelVpnStartSuccessExtra";

  private TunnelVpnManager m_tunnelManager = new TunnelVpnManager(this);

  public class LocalBinder extends Binder {
    public TunnelVpnService getService() {
      return TunnelVpnService.this;
    }
  }

  private final IBinder m_binder = new LocalBinder();

  @Override
  public IBinder onBind(Intent intent) {
    String action = intent.getAction();
    if (action != null && action.equals(SERVICE_INTERFACE)) {
      return super.onBind(intent);
    }
    return m_binder;
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    //Log.d(LOG_TAG, "on start");
    return m_tunnelManager.onStartCommand(intent, flags, startId);
  }

  @Override
  public void onCreate() {
    //Log.d(LOG_TAG, "on create");
    SocketProtector.setVpnService(this);
    TunnelState.getTunnelState().setTunnelManager(m_tunnelManager);
  }

  @Override
  public void onDestroy() {
    SkStatus.logInfo("<strong>VPN service destroyed</strong>");

    // Keep the SSH service and the Android VPN state synchronized. If Android
    // kills or destroys only the VpnService, the main tunnel manager must be
    // notified so it can reconnect instead of leaving the app marked connected
    // while the phone VPN interface is gone.
    broadcastVpnDisconnect();

    TunnelState.getTunnelState().setTunnelManager(null);
    SocketProtector.clearVpnService(this);
    m_tunnelManager.onDestroy();

    super.onDestroy();
  }

  @Override
  public void onRevoke() {
    SkStatus.logInfo("<strong>VPN service revoked</strong>");
    broadcastVpnDisconnect();
    // stopSelf will trigger onDestroy in the main thread.
    stopSelf();
  }

  public VpnService.Builder newBuilder() {
    return new VpnService.Builder();
  }

  // Broadcast non-user-initiated VPN disconnect.
  public void broadcastVpnDisconnect() {
    dispatchBroadcast(new Intent(TUNNEL_VPN_DISCONNECT_BROADCAST));
  }

  // Broadcast VPN start. |success| is true if the VPN and tunnel were started
  // successfully, and false otherwise.
  public void broadcastVpnStart(boolean success) {
    Intent vpnStart = new Intent(TUNNEL_VPN_START_BROADCAST);
    vpnStart.putExtra(TUNNEL_VPN_START_SUCCESS_EXTRA, success);
    dispatchBroadcast(vpnStart);
  }

  private void dispatchBroadcast(final Intent broadcast) {
    LocalBroadcastManager.getInstance(TunnelVpnService.this)
        .sendBroadcast(broadcast);
  }
}
