package io.particle.android.sdk.cloud;

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;

import com.squareup.okhttp.OkHttpClient;

import java.util.concurrent.Executors;

import javax.annotation.ParametersAreNonnullByDefault;

import io.particle.android.sdk.cloud.ApiDefs.CloudApi;
import io.particle.android.sdk.cloud.ApiDefs.IdentityApi;
import io.particle.android.sdk.cloud.ApiFactory.OauthBasicAuthCredentialsProvider;
import io.particle.android.sdk.cloud.ApiFactory.ResourceValueBasicAuthCredentialsProvider;
import io.particle.android.sdk.cloud.ApiFactory.TokenGetterDelegate;


// FIXME: there are a lot of details lacking in this class, but it's not public API, and the
// structure makes it easy enough to do something better later on.
@ParametersAreNonnullByDefault
class SDKProvider {

    private final Context ctx;
    private final CloudApi cloudApi;
    private final IdentityApi identityApi;
    private final ParticleCloud particleCloud;
    private final TokenGetterDelegateImpl tokenGetter;

    SDKProvider(Context context,
                @Nullable OauthBasicAuthCredentialsProvider oAuthCredentialsProvider,
                @Nullable OkHttpClient okHttpClient) {

        this.ctx = context.getApplicationContext();

        if (oAuthCredentialsProvider == null) {
            oAuthCredentialsProvider = new ResourceValueBasicAuthCredentialsProvider(
                    ctx, R.string.oauth_client_id, R.string.oauth_client_secret);
        }

        tokenGetter = new TokenGetterDelegateImpl();

        ApiFactory apiFactory = new ApiFactory(
                ctx, tokenGetter, oAuthCredentialsProvider, okHttpClient);
        cloudApi = apiFactory.buildNewCloudApi();
        identityApi = apiFactory.buildNewIdentityApi();
        particleCloud = buildCloud(apiFactory);
    }


    CloudApi getCloudApi() {
        return cloudApi;
    }

    IdentityApi getIdentityApi() {
        return identityApi;
    }

    ParticleCloud getParticleCloud() {
        return particleCloud;
    }


    private ParticleCloud buildCloud(ApiFactory apiFactory) {
        SDKGlobals.init(ctx);

        // FIXME: see if this TokenGetterDelegate setter issue can be resolved reasonably
        ParticleCloud cloud = new ParticleCloud(apiFactory.getApiUri(), cloudApi, identityApi,
                SDKGlobals.getAppDataStorage(), LocalBroadcastManager.getInstance(ctx),
                apiFactory.getGsonInstance(), Executors.newCachedThreadPool());
        // FIXME: gross circular dependency
        tokenGetter.cloud = cloud;

        return cloud;
    }


    private static class TokenGetterDelegateImpl implements TokenGetterDelegate {

        private volatile ParticleCloud cloud;

        @Override
        public String getTokenValue() {
            return cloud.getAccessToken();
        }
    }
}

@@ -2503,24 +2503,29 @@
 ance(), 
+build
 Executor
 s.newCac
@@ -2520,29 +2520,8 @@
 utor
-s.newCachedThreadPool
 ());
@@ -2593,32 +2593,32 @@
 cloud = cloud;%0A%0A
-
         return c
@@ -2623,32 +2623,905 @@
  cloud;%0A    %7D%0A%0A%0A
+    private static ExecutorService buildExecutor() %7B%0A        // lifted from AsyncTask's executor config%0A        int CPU_COUNT = Runtime.getRuntime().availableProcessors();%0A        int CORE_POOL_SIZE = CPU_COUNT + 1;%0A        int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;%0A        int KEEP_ALIVE = 1;%0A        // FIXME: how big should this queue be?%0A        BlockingQueue%3CRunnable%3E poolWorkQueue = new LinkedBlockingQueue%3C%3E(1024);%0A        ThreadFactory threadFactory = new ThreadFactory() %7B%0A            private final AtomicInteger mCount = new AtomicInteger(1);%0A            public Thread newThread(Runnable r) %7B%0A                return new Thread(r, %22Particle Exec #%22 + mCount.getAndIncrement());%0A            %7D%0A        %7D;%0A%0A        return new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,%0A                TimeUnit.SECONDS, poolWorkQueue, threadFactory);%0A    %7D%0A%0A%0A
     private stat

Use much, much smarter, more intentional executor config