package org.pdxfinder;

import org.pdxfinder.utils.DataProviders;
import org.pdxfinder.utils.DataProviders.DataProvider;
import org.pdxfinder.utils.DataProviders.DataProviderGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.ArgGroup;

import java.io.File;
import java.util.*;
import java.util.concurrent.Callable;

@Component
@Command(name = "indexer",
    mixinStandardHelpOptions = true,
    subcommands = {FinderCommandLine.Load.class})
@Order(value = -100)
public class FinderCommandLine implements Callable<Integer> {

    @Override
    public Integer call() {
        return 23;
    }

    @Component
    @Order(value = -100)
    @Command(name = "load",
        description = "Loads and transforms data into the PDXFinder.",
        mixinStandardHelpOptions = true,
        exitCodeOnExecutionException = 34)
    static class Load implements Callable<Integer> {

        Logger log = LoggerFactory.getLogger(Load.class);

        @Autowired
        private FinderLoader finderLoader;

        @Option(
            names = {"-d", "--data-dir"},
            required = true,
            description = "Path of the PDXFinder data directory " +
                "(default: [${DEFAULT-VALUE}], set in application.properties)")
        private File dataDirectory;

        @Option(names = {"-c", "--cache"},
                description = "Clear cached data and reload, including NCIT ontology terms, etc.")
        private boolean loadCacheRequested;

        @Option(names = {"-k", "--keep-db"},
                description = "Skips clearing of the database before loading new data.")
        private boolean keepDatabaseRequested;

        @Option(names = "--spring.config.location")
        private String springConfigLocation;

        @ArgGroup(multiplicity = "0..1")
        Exclusive datasetRequested = new Exclusive();

        static class Exclusive {

            @Option(
                    names = {"-g", "--group"},
                    arity = "1",
                    description = "Load the data for groups of dataProvider (default: [${DEFAULT-VALUE}]). " +
                            "Accepted Values: [@|cyan ${COMPLETION-CANDIDATES} |@]")
            private DataProviderGroup dataProviderGroup;

            @Option(
                    names = {"-o", "--only"}, arity = "1..*",
                    description = "Load only the data for the listed dataProvider. " +
                            "Accepted Values: [@|cyan ${COMPLETION-CANDIDATES} |@]")
            private DataProvider[] dataProvider;

            public DataProviderGroup getDataProviderGroup() {
                return dataProviderGroup;
            }

            public DataProvider[] getDataProvider() {
                return dataProvider;
            }
        }

        @Override
        public Integer call() {

            log.info("Loading using supplied parameters:\n{}", this);
            List<DataProvider> providersRequested = getListOfRequestedProviders();

            finderLoader.run(
                providersRequested,
                loadCacheRequested,
                keepDatabaseRequested
            );
            return 0;
        }


        List<DataProvider> getListOfRequestedProviders() {

            Optional<DataProvider[]> dataProviders = Optional.ofNullable(
                    datasetRequested.getDataProvider()
            );

            Optional<DataProviderGroup> dataProviderGroup = Optional.ofNullable(
                    datasetRequested.getDataProviderGroup()
            );

            if (dataProviders.isPresent()) {

                return Arrays.asList(dataProviders.get());
            } else if (dataProviderGroup.isPresent()) {

                return DataProviders.getProvidersFrom(dataProviderGroup.get());
            } else {
                return new ArrayList<>();
            }

        }

        @Override
        public String toString() {
            return new StringJoiner("\n", Load.class.getSimpleName() + "[\n", "\n]")
                .add("dataDirectory=" + dataDirectory)
                .add("clearCacheRequested=" + loadCacheRequested)
                .add("keepDatabaseRequested=" + keepDatabaseRequested)
                .add("springConfigLocation='" + springConfigLocation + "'")
                .add("datasetRequested=" + getListOfRequestedProviders())
                .toString();
        }
    }

}

@@ -1923,16 +1923,18 @@
 (names =
+ %7B
  %22--spri
@@ -1940,69 +1940,388 @@
 ing.
-config.location%22)%0A        private String springConfigLocation
+data.neo4j.uri%22%7D, paramLabel = %22Neo4j DB Directory%22, description = %22Embedded Neo4j Database location%22, required=false, hidden=true)%0A        private String springDataNeo4jUri;%0A%0A        @Option(names = %7B %22--spring.datasource.url%22%7D, paramLabel = %22H2 DB Directory%22, description = %22Embedded H2 Database location%22, required=false, hidden=true)%0A        private String springDatasourceUrl
 ;%0A%0A 
@@ -4765,84 +4765,8 @@
 ed)%0A
-                .add(%22springConfigLocation='%22 + springConfigLocation + %22'%22)%0A
     

add other required Spring Boot configurable parameters to picoCli Callable element