// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.gcore;

import org.chromium.base.ApplicationStatus;
import org.chromium.base.ApplicationStatus.ApplicationStateListener;
import org.chromium.base.Log;
import org.chromium.base.ThreadUtils;

import java.util.HashSet;
import java.util.Set;

/**
 * Listens to application state changes. It is created lazily when we want to register a
 * {@link GoogleApiClientHelper}.
 * Thread safe.
 */
class LifecycleHook implements ApplicationStateListener {
    private static LifecycleHook sInstance;
    private static final Object sInstanceLock = new Object();
    private static final String TAG = "GCore";

    public static LifecycleHook getInstance() {
        synchronized (sInstanceLock) {
            if (sInstance == null) sInstance = new LifecycleHook();
            return sInstance;
        }
    }

    /**
     * Reset static singletons.
     * This is needed for JUnit tests as statics are not reset between runs and previous states can
     * make other tests fail. It is not needed in instrumentation tests (and will be removed by
     * Proguard in release builds) since the application lifecycle will naturally do the work.
     */
    public static void destroyInstanceForJUnitTests() {
        LifecycleHook hook;
        synchronized (sInstanceLock) {
            if (sInstance == null) return;
            hook = sInstance;
            sInstance = null;
        }
        ApplicationStatus.unregisterApplicationStateListener(hook);
    }

    private final Set<GoogleApiClientHelper> mClientHelpers;
    private boolean mIsApplicationVisible;

    private LifecycleHook() {
        mClientHelpers = new HashSet<GoogleApiClientHelper>();
        mIsApplicationVisible = ApplicationStatus.hasVisibleActivities();
        ApplicationStatus.registerApplicationStateListener(this);
        Log.d(TAG, "lifecycle hook registered.");
    }

    public void registerClientHelper(GoogleApiClientHelper clientHelper) {
        synchronized (mClientHelpers) {
            mClientHelpers.add(clientHelper);
        }
    }

    public void unregisterClientHelper(GoogleApiClientHelper clientHelper) {
        synchronized (mClientHelpers) {
            mClientHelpers.remove(clientHelper);
        }
    }


    @Override
    public void onApplicationStateChange(int newState) {
        Log.d(TAG, "onApplicationStateChange");
        ThreadUtils.assertOnUiThread();

        boolean newVisibility = ApplicationStatus.hasVisibleActivities();
        if (mIsApplicationVisible == newVisibility) return;

        Log.d(TAG, "Application visibilty changed to %s. Updating state of %d client(s).",
                newVisibility, mClientHelpers.size());

        mIsApplicationVisible = newVisibility;

        synchronized (mClientHelpers) {
            for (GoogleApiClientHelper clientHelper : mClientHelpers) {
                if (mIsApplicationVisible) clientHelper.restoreConnectedState();
                else clientHelper.scheduleDisconnection();
            }
        }
    }
}