package poussecafe.discovery;

import java.util.HashSet;
import java.util.Set;
import poussecafe.domain.Module;
import poussecafe.environment.Bundle;
import poussecafe.environment.BundleDefinition;
import poussecafe.messaging.Messaging;
import poussecafe.messaging.internal.InternalMessaging;
import poussecafe.runtime.MessagingAndStorage;
import poussecafe.storage.Storage;
import poussecafe.storage.internal.InternalStorage;

public class BundleConfigurer {

    public static class Builder {

        private BundleConfigurer configurer = new BundleConfigurer();

        /**
         * @deprecated use module method instead.
         */
        @Deprecated(since = "0.17")
        public Builder moduleBasePackage(String packageName) {
            moduleBasePackages.add(packageName);
            return this;
        }

        private Set<String> moduleBasePackages = new HashSet<>();

        public Builder module(Class<? extends Module> moduleClass) {
            if(moduleClass == DefaultModule.class) {
                moduleBasePackages.add("");
            } else {
                moduleBasePackages.add(moduleClass.getPackageName());
            }
            return this;
        }

        public BundleConfigurer build() {
            configurer.classPathExplorer = new ClassPathExplorer(moduleBasePackages);
            return configurer;
        }
    }

    private BundleConfigurer() {

    }

    private ClassPathExplorer classPathExplorer;

    public BundleDefinition define() {
        BundleDefinition.Builder builder = new BundleDefinition.Builder();
        builder.withAggregateDefinitions(classPathExplorer.discoverAggregates());
        builder.withDomainProcesses(classPathExplorer.discoverDomainProcesses());
        builder.withServices(classPathExplorer.discoverServices());
        builder.withMessages(classPathExplorer.discoverMessages());
        builder.withMessageListeners(classPathExplorer.discoverListeners());
        return builder.build();
    }

    public Bundle.Builder defineAndImplementDefault() {
        return defineThenImplement()
                .messaging(InternalMessaging.instance())
                .storage(InternalStorage.instance());
    }

    public BundleWithoutImplementation defineThenImplement() {
        Bundle.Builder builder = new Bundle.Builder();
        builder.definition(define());
        builder.serviceImplementations(classPathExplorer.discoverServiceImplementations());
        return new BundleWithoutImplementation(builder);
    }

    public class BundleWithoutImplementation {

        private BundleWithoutImplementation(Bundle.Builder builder) {
            this.builder = builder;
        }

        private Bundle.Builder builder;

        public Bundle.Builder messagingAndStorage(MessagingAndStorage messagingAndStorage) {
            return messaging(messagingAndStorage.messaging())
                    .storage(messagingAndStorage.storage());
        }

        public BundleWithMessaging messaging(Messaging messaging) {
            builder.messagingImplementations(new MessagingImplementationDiscovery.Builder()
                    .classPathExplorer(classPathExplorer)
                    .messaging(messaging)
                    .build()
                    .discover());
            return new BundleWithMessaging(builder);
        }
    }

    public class BundleWithMessaging {

        private BundleWithMessaging(Bundle.Builder builder) {
            this.builder = builder;
        }

        private Bundle.Builder builder;

        public Bundle.Builder storage(Storage storage) {
            builder.storageImplementations(new StorageImplementationDiscovery.Builder()
                    .classPathExplorer(classPathExplorer)
                    .storage(storage)
                    .build()
                    .discover());
            return builder;
        }
    }
}

@@ -737,39 +737,33 @@
 ) %7B%0A            
-moduleB
+b
 asePackages.add(
@@ -840,23 +840,17 @@
 String%3E 
-moduleB
+b
 asePacka
@@ -1003,39 +1003,33 @@
                 
-moduleB
+b
 asePackages.add(
@@ -1070,23 +1070,17 @@
         
-moduleB
+b
 asePacka
@@ -1160,32 +1160,333 @@
 his;%0A        %7D%0A%0A
+        public Builder basePackage(String basePackage) %7B%0A            basePackages.add(basePackage);%0A            return this;%0A        %7D%0A%0A        public Builder basePackageClass(Class%3C?%3E basePackageClass) %7B%0A            basePackage(basePackageClass.getPackageName());%0A            return this;%0A        %7D%0A%0A
         public B
@@ -1576,23 +1576,17 @@
 xplorer(
-moduleB
+b
 asePacka

add bundler configuration methods.