package com.atlassian.stash.sal.api.lifecycle;

import com.atlassian.event.api.EventListener;
import com.atlassian.plugin.PluginAccessor;
import com.atlassian.plugin.event.PluginEventManager;
import com.atlassian.sal.core.lifecycle.DefaultLifecycleManager;
import com.atlassian.bitbucket.event.server.ApplicationSetupEvent;
import com.atlassian.bitbucket.server.ApplicationPropertiesService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;

/**
 * Implements SAL's {@code LifecycleManager}, extending {@code DefaultLifecycleManager} to provide most of the
 * implementation bits.
 * <p>
 * There's a bit of hidden magic here, performed by the wiring in {@code spring-context.xml}. Specifically, in
 * the wiring for the injected {@code osgi:list} of {@code LifecycleAware} components, two important flags are
 * set:
 * <ul>
 *     <li>{@code comparator}: Uses {@link LifecycleAwareComparator} to sort {@code LifecycleAware} components
 *     using Spring's {@code Ordered}/{@code PriorityOrdered} interfaces if they're implemented</li>
 *     <li>{@code greedy-proxying}: Proxies <i>all</i> interfaces exported by {@code LifecycleAware} components,
 *     because otherwise {@code Ordered}/{@code PriorityOrdered} are dropped on the OSGi proxy in the list</li>
 * </ul>
 */
public class StashLifecycleManager extends PatchedLifecycleManager {

    private final ApplicationPropertiesService propertiesService;

    public StashLifecycleManager(PluginEventManager pluginEventManager,
                                 ApplicationPropertiesService propertiesService,
                                 PluginAccessor pluginAccessor,
                                 BundleContext bundleContext) {
        super(pluginEventManager, pluginAccessor, bundleContext);

        this.propertiesService = propertiesService;
    }

    @Override
    public boolean isApplicationSetUp() {
        return propertiesService.isSetup();
    }

    /**
     * Runs {@code LifecycleAware} callbacks when setup completes. Without this, after initial product setup, the
     * {@code LifecycleAware} callbacks don't get invoked until the server is restarted.
     * <p>
     * Now that SSH server startup is handled by {@code LifecycleAware}, this causes the server to not be started
     * after setup.
     *
     * @param event the setup event
     * @since 2.9
     */
    @EventListener
    public void onApplicationSetup(ApplicationSetupEvent event) {
        if (event.getNewValue()) {
            start();
        }
    }
}
