package com.atlassian.stash.internal.plugin;

import com.atlassian.event.api.EventListener;
import com.atlassian.plugin.event.events.PluginEnabledEvent;
import com.atlassian.plugin.event.events.PluginFrameworkStartedEvent;
import com.atlassian.plugin.event.events.PluginFrameworkStartingEvent;
import com.atlassian.stash.internal.lifecycle.StartupProgressEvent;
import com.atlassian.stash.internal.plugin.event.PluginInstallRequestedEvent;
import com.atlassian.bitbucket.util.ProgressImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

/**
 * Listens for various plugin framework events during startup to track them against the system's lifecycle.
 * Progress events are published via the {@code ApplicationContext}, <i>not</i> via Atlassian Events, since
 * they are an internal detail related to the {@code ApplicationContext}'s processing and not intended to
 * be exposed to plugin developers.
 *
 * @since 3.2
 */
@Component
public class LifecyclePluginListener {

    private final ApplicationEventPublisher eventPublisher;

    private double started;
    private volatile boolean starting;
    private double total;

    @Autowired
    public LifecyclePluginListener(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    /**
     * Raised once before the the initial set of plugins are installed and started when the plugin framework is
     * started for the first time.
     *
     * @param event
     */
    @EventListener
    public void onInstallingPlugins(PluginInstallRequestedEvent event) {
        total = event.getTotal();
    }

    @EventListener
    public void onPluginEnabled(PluginEnabledEvent event) {
        if (starting) { //Ignore plugins enabled after startup is complete
            //Starting the plugin framework gets 50% of our startup weight. Though not all plugins are
            //created equal, divide that time evenly across the total
            int progress = 45 + (int) ((++started / total) * 50);

            eventPublisher.publishEvent(new StartupProgressEvent(this,
                    new ProgressImpl("Started " + event.getPlugin().getName(), progress)));
        }
    }

    @EventListener
    public void onPluginFrameworkStarted(PluginFrameworkStartedEvent event) {
        starting = false;
    }

    @EventListener
    public void onPluginFrameworkStarting(PluginFrameworkStartingEvent event) {
        //Preparing the plugin framework is 25% progress (LifecycleApplicationContextInitializer). This is 35%
        //because there's generally a fairly sizable delay between this step and the first plugin enabling, at
        //which point progress moves to 45% and then works its way to 95% as additional plugins are enabled
        eventPublisher.publishEvent(new StartupProgressEvent(this, new ProgressImpl("Starting plugin framework", 35)));
        starting = true;
    }
}
