package com.nbusy.app;

import android.app.Application;
import android.content.Context;

import com.nbusy.app.data.Config;
import com.nbusy.app.data.DB;
import com.nbusy.app.data.InMemDB;
import com.nbusy.app.data.Profile;
import com.nbusy.app.data.sqldb.SQLDB;
import com.nbusy.app.worker.ConnManager;
import com.nbusy.app.worker.LoginManager;
import com.nbusy.app.worker.Worker;
import com.nbusy.app.worker.eventbus.EventBus;
import com.nbusy.app.worker.eventbus.UIThreadExecutor;
import com.nbusy.sdk.Client;
import com.nbusy.sdk.ClientImpl;

/**
 * Creator and keeper of all the instances.
 * Values are initialized on first request.
 * All instances are singletons unless otherwise mentioned.
 */
public class InstanceManager extends Application {
    private static final String TAG = InstanceManager.class.getSimpleName();
    private static Context appContext;
    private static Config config;
    private static Worker worker;
    private static ConnManager connManager;
    private static LoginManager loginManager;
    private static Client client;
    private static EventBus eventBus;
    private static DB db;
    private static Profile userProfile;

    @Override
    public synchronized void onCreate() {
        super.onCreate();
        appContext = getApplicationContext();
    }

    public synchronized static Context getAppContext() {
        return appContext;
    }

    public static synchronized Config getConfig() {
        if (config == null) {
            config = new Config();
        }

        return config;
    }

    public static synchronized Worker getWorker() {
        if (worker == null) {
            worker = new Worker(getClient(), getEventBus(), getDB(), getUserProfile());
        }

        return worker;
    }

    public static synchronized ConnManager getConnManager() {
        if (connManager == null) {
            connManager = new ConnManager(getClient(), getEventBus(), getDB(), getUserProfile(), getAppContext());
        }

        return connManager;
    }

    public static synchronized LoginManager getLoginManager() {
        if (loginManager == null) {
            loginManager = new LoginManager(getClient(), getDB());
        }

        return loginManager;
    }

    public static synchronized Client getClient() {
        if (client == null) {
            if (getConfig().serverUrl != null) {
                client = new ClientImpl(getConfig().serverUrl, false);
            } else {
                client = new ClientImpl();
            }
        }

        return client;
    }

    public static synchronized EventBus getEventBus() {
        if (eventBus == null) {
            // todo: remove UIThreadExecutor if we don't need this any more
            eventBus = new EventBus(new UIThreadExecutor());
        }

        return eventBus;
    }

    public static synchronized DB getDB() {
        if (db == null) {
            if (getConfig().env == Config.Env.PRODUCTION) {
                db = new SQLDB();
            } else {
                db = new InMemDB();
            }
        }

        return db;
    }

    public static synchronized void setUserProfile(Profile prof) {
        if (userProfile != null) {
            throw new IllegalStateException("userProfile has already been initialized");
        }

        userProfile = prof;
    }

    public static synchronized Profile getUserProfile() {
        if (userProfile == null) {
            throw new IllegalStateException("userProfile is not retrieved yet or does not exist");
        }

        return userProfile;
    }

    public static synchronized boolean userProfileRetrieved() {
        return userProfile != null;
    }
}

@@ -2660,62 +2660,238 @@
 do: 
-remove UIThreadExecutor if we don't need this any more
+we need this as some events are raised on non-UI threads which then update the UI and cause an exception%0A            // though this approach is not the best either as it creates one thread per event invocation, which we don't need
 %0A   

replace legacy todo