package li.vin.net;

import android.app.Activity;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import rx.Observable;
import rx.Observer;

public final class Vinli {
  /*protected*/ static final String VINLI_PREFS = "li.vin.net.Vinli";
  /*protected*/ static final String SIGN_IN_ERROR = "li.vin.net.Vinli#SIGN_IN_ERROR";
  /*protected*/ static final String ACCESS_TOKEN = "li.vin.net.Vinli#ACCESS_TOKEN";

  /** Pass one of these constants to {@link #overrideDefaultEnvironment(Environment)}
   * to override the default production environment. This must be called before any other Vinli
   * app functionality is initialized, ideally in {@link Application#onCreate()}. */
  public enum Environment {
    PRODUCTION(Endpoint.DOMAIN_PROD),
    DEV(Endpoint.DOMAIN_DEV),
    DEMO(Endpoint.DOMAIN_DEMO);

    private final String domainStr;

    private Environment(String domainStr) {
      this.domainStr = domainStr;
    }
  }

  public static final void signIn(@NonNull Activity context, @NonNull String clientId,
      @NonNull String redirectUri, @NonNull PendingIntent pendingIntent) {
    context.startActivity(SignInActivity.newIntent(context, clientId, redirectUri, pendingIntent));
  }

  public static final @Nullable String getSignInError(@NonNull Intent intent) {
    final Bundle extras = intent.getExtras();
    if (extras == null) {
      return null;
    }

    return extras.getString(SIGN_IN_ERROR);
  }

  private static VinliApp sApp = null;

  public static void clearApp(@NonNull Context context) {
    context.getSharedPreferences(VINLI_PREFS, Context.MODE_PRIVATE)
        .edit()
        .putString(ACCESS_TOKEN, null)
        .apply();
    sApp = null;
  }

  public static final @Nullable VinliApp initApp(Context context, @NonNull Intent intent) {
    if (sApp == null) {
      final Bundle extras = intent.getExtras();
      if (extras != null) {
        String accessToken = extras.getString("li.vin.my.access_token");
        if (accessToken == null) {
          // fallback for backwards compat
          accessToken = extras.getString(ACCESS_TOKEN);
        }
        if (accessToken != null) {
          context.getSharedPreferences(VINLI_PREFS, Context.MODE_PRIVATE)
              .edit()
              .putString(ACCESS_TOKEN, accessToken)
              .apply();

          sApp = new VinliApp(accessToken);
        }
      }
    }

    return loadApp(context);
  }

  public static final @Nullable VinliApp initApp(Context context, @NonNull String accessToken) {
    if (sApp == null) {
      context.getSharedPreferences(VINLI_PREFS, Context.MODE_PRIVATE)
          .edit()
          .putString(ACCESS_TOKEN, accessToken)
          .apply();

      sApp = new VinliApp(accessToken);
    }

    return loadApp(context);
  }

  public static final @Nullable VinliApp loadApp(@NonNull Context context) {
    if (sApp == null) {
      final String accessToken = context
          .getSharedPreferences(VINLI_PREFS, Context.MODE_PRIVATE)
          .getString(ACCESS_TOKEN, null);

      if (accessToken != null) {
        sApp = new VinliApp(accessToken);
      }
    }

    return sApp;
  }

  /*package*/ static final VinliApp curApp() {
    if (sApp == null) {
      throw new IllegalStateException("no current app exists");
    }
    return sApp;
  }

  public static <T> void registerObserver(@NonNull Observer<T> observer,
      @NonNull Observable<T> observable) {
    ObserverManager.registerObserver(observer, observable, null);
  }

  public static <T> void registerObserver(@NonNull Observer<T> observer,
      @NonNull Observable<T> observable,
      @Nullable Object binding) {
    ObserverManager.registerObserver(observer, observable, binding);
  }

  public static void unregisterObserver(@NonNull Observer<?> observer) {
    ObserverManager.unregisterObserver(observer);
  }

  /** Override the default environment with one of the constants from {@link Environment}.
   * Be sure to call this before making any other Vinli calls or it may have no effect. */
  public static void overrideDefaultEnvironment(@NonNull Environment environment) {
    Endpoint.setDomain(environment.domainStr);
  }

  private Vinli() { }
}

@@ -47,40 +47,8 @@
 ty;%0A
-import android.app.Application;%0A
 impo
@@ -568,530 +568,8 @@
 %22;%0A%0A
-  /** Pass one of these constants to %7B@link #overrideDefaultEnvironment(Environment)%7D%0A   * to override the default production environment. This must be called before any other Vinli%0A   * app functionality is initialized, ideally in %7B@link Application#onCreate()%7D. */%0A  public enum Environment %7B%0A    PRODUCTION(Endpoint.DOMAIN_PROD),%0A    DEV(Endpoint.DOMAIN_DEV),%0A    DEMO(Endpoint.DOMAIN_DEMO);%0A%0A    private final String domainStr;%0A%0A    private Environment(String domainStr) %7B%0A      this.domainStr = domainStr;%0A    %7D%0A  %7D%0A%0A
   pu
@@ -3468,268 +3468,145 @@
 %0A%0A  
-/** Override the default environment with one of the constants from %7B@link Environment%7D.%0A   * Be sure to call this before 
+private static void setEnvironmentToDev() %7B%0A    Endpoint.setDo
 ma
-k
 in
-g any other Vinli calls or it may have no effect. */%0A  public static void overrideDefaultEnvironment(@NonNull Environment environment
+(Endpoint.DOMAIN_DEV);%0A  %7D%0A%0A  private static void setEnvironmentToDemo(
 ) %7B%0A
@@ -3632,29 +3632,28 @@
 ain(
-environment.domainStr
+Endpoint.DOMAIN_DEMO
 );%0A 

Remove public api for setting environment to anything other than prod - instead, we can use reflection on Vinli.java to set non-prod environments