package p.studio;

import com.fasterxml.jackson.databind.ObjectMapper;
import p.studio.events.StudioEventBus;
import p.studio.events.StudioPackerEventAdapter;
import p.studio.utilities.ThemeService;
import p.studio.utilities.i18n.I18nService;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public final class AppContainer implements Container {
    private final I18nService i18nService;
    private final ThemeService themeService;
    private final StudioEventBus studioEventBus;
    private final ObjectMapper mapper;
    private final Packer packer;
    private final StudioBackgroundTasks backgroundTasks;

    public AppContainer() {
        this.i18nService = new I18nService();
        this.themeService = new ThemeService();
        this.studioEventBus = new StudioEventBus();
        this.mapper = new ObjectMapper();
        final ExecutorService backgroundExecutor = Executors.newFixedThreadPool(2, new StudioWorkerThreadFactory());
        this.backgroundTasks = new StudioBackgroundTasks(backgroundExecutor);
        final p.packer.Packer embeddedPacker = p.packer.Packer.bootstrap(new StudioPackerEventAdapter(studioEventBus));
        this.packer = new Packer(embeddedPacker.workspaceService(), embeddedPacker::close);
    }

    @Override
    public I18nService getI18n() {
        return i18nService;
    }

    @Override
    public ThemeService getTheme() {
        return themeService;
    }

    @Override
    public StudioEventBus getEventBus() {
        return studioEventBus;
    }

    @Override
    public ObjectMapper getMapper() {
        return mapper;
    }

    @Override
    public Packer getPacker() {
        return packer;
    }

    @Override
    public StudioBackgroundTasks getBackgroundTasks() {
        return backgroundTasks;
    }

    @Override
    public void shutdownContainer() {
        packer.shutdown();
        backgroundTasks.shutdown();
    }

    private static final class StudioWorkerThreadFactory implements ThreadFactory {
        private final AtomicInteger nextId = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable runnable) {
            final Thread thread = new Thread(runnable, "studio-worker-" + nextId.getAndIncrement());
            thread.setDaemon(true);
            return thread;
        }
    }
}
