package com.hartwig.healthchecks;

import java.io.IOException;
import java.util.Collection;
import java.util.Optional;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;

import com.hartwig.healthchecks.common.adapter.HealthCheckAdapter;
import com.hartwig.healthchecks.common.exception.GenerateReportException;
import com.hartwig.healthchecks.common.exception.NotFoundException;
import com.hartwig.healthchecks.common.report.JsonReport;
import com.hartwig.healthchecks.util.adapter.HealthChecksFlyweight;

import rx.Observable;
import rx.schedulers.Schedulers;

public class HealthChecksApplication {

    private static final String REPORT_GENERATED_MSG = "Report generated with following name -> %s";

    private static final Logger LOGGER = LogManager.getLogger(HealthChecksApplication.class);

    private static final String RUN_DIRECTORY = "rundir";

    private static final String CHECK_TYPE = "checktype";

    private static final String ALL_CHECKS = "all";

    private final String runDirectory;

    private final String checkType;

    public HealthChecksApplication(@NotNull final String runDirectory, @NotNull final String checkType) {
        this.runDirectory = runDirectory;
        this.checkType = checkType;
    }

    public static void main(final String... args) throws ParseException, IOException {
        final Options options = createOptions();
        final CommandLine cmd = createCommandLine(options, args);

        final String runDirectory = cmd.getOptionValue(RUN_DIRECTORY);
        final String checkType = cmd.getOptionValue(CHECK_TYPE);

        if (runDirectory == null || checkType == null) {
            final HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp("Health-Checks", options);
        }

        final HealthChecksApplication healthChecksApplication = new HealthChecksApplication(runDirectory, checkType);
        healthChecksApplication.processHealthChecks();
    }

    @NotNull
    private static Options createOptions() {
        final Options options = new Options();
        options.addOption(RUN_DIRECTORY, true, "The path containing the data for a single run");
        options.addOption(CHECK_TYPE, true, "The type of check to b executed for a single run");
        return options;
    }

    @NotNull
    private static CommandLine createCommandLine(@NotNull final Options options, @NotNull final String... args)
                    throws ParseException {
        final CommandLineParser parser = new DefaultParser();
        return parser.parse(options, args);
    }

    public void processHealthChecks() {
        if (checkType.equals(ALL_CHECKS)) {
            executeAllcheck(runDirectory);
        } else {
            final HealthChecksFlyweight flyweight = HealthChecksFlyweight.getInstance();
            try {
                final HealthCheckAdapter healthCheckAdapter = flyweight.getAdapter(checkType);
                healthCheckAdapter.runCheck(runDirectory);
            } catch (final NotFoundException e) {
                LOGGER.error(e.getMessage());
            }
        }

        try {
            final Optional<String> fileName = JsonReport.getInstance().generateReport();
            LOGGER.info(String.format(REPORT_GENERATED_MSG, fileName.get()));
        } catch (final GenerateReportException e) {
            LOGGER.log(Level.ERROR, e.getMessage());
        }
    }

    protected void executeAllcheck(@NotNull final String runDirectory) {
        final HealthChecksFlyweight flyweight = HealthChecksFlyweight.getInstance();
        final Collection<HealthCheckAdapter> adapters = flyweight.getAllAdapters();

        Observable.from(adapters).subscribeOn(Schedulers.io()).subscribe((adapter) -> adapter.runCheck(runDirectory),
                        (error) -> LOGGER.error(error.getMessage()), () -> {
                            try {
                                final Optional<String> fileName = JsonReport.getInstance().generateReport();
                                LOGGER.info(String.format(REPORT_GENERATED_MSG, fileName.get()));
                            } catch (final GenerateReportException e) {
                                LOGGER.log(Level.ERROR, e.getMessage());
                            }
                        });

    }
}

@@ -904,16 +904,58 @@
 rvable;%0A
+import rx.observables.BlockingObservable;%0A
 import r
@@ -3016,24 +3016,115 @@
 hChecks() %7B%0A
+        LOGGER.info(String.format(%22Check yype sent via command line -%3E %25s%22, ALL_CHECKS));%0A%0A
         if (
@@ -3139,16 +3139,26 @@
 e.equals
+IgnoreCase
 (ALL_CHE
@@ -3187,21 +3187,22 @@
 ecuteAll
-c
+C
 heck
+s
 (runDire
@@ -3597,34 +3597,772 @@
       %7D%0A        
-%7D%0A
+    generateReport();%0A        %7D%0A    %7D%0A%0A    protected void executeAllChecks(@NotNull final String runDirectory) %7B%0A        final HealthChecksFlyweight flyweight = HealthChecksFlyweight.getInstance();%0A        final Collection%3CHealthCheckAdapter%3E adapters = flyweight.getAllAdapters();%0A%0A        Observable%3CHealthCheckAdapter%3E adapterObservable =  Observable.from(adapters)%0A                .subscribeOn(Schedulers.io());%0A%0A        BlockingObservable.from(adapterObservable)%0A                .subscribe(%0A                        adapter -%3E adapter.runCheck(runDirectory),%0A                        (error) -%3E LOGGER.error(error.getMessage()),%0A                        () -%3E generateReport()%0A                );%0A    %7D%0A%0A    private void generateReport() %7B
 %0A        try %7B%0A 
@@ -4536,38 +4536,32 @@
        %7D catch (
-final 
 GenerateReportEx
@@ -4645,897 +4645,7 @@
    %7D
-%0A%0A    protected void executeAllcheck(@NotNull final String runDirectory) %7B%0A        final HealthChecksFlyweight flyweight = HealthChecksFlyweight.getInstance();%0A        final Collection%3CHealthCheckAdapter%3E adapters = flyweight.getAllAdapters();%0A%0A        Observable.from(adapters).subscribeOn(Schedulers.io()).subscribe((adapter) -%3E adapter.runCheck(runDirectory),%0A                        (error) -%3E LOGGER.error(error.getMessage()), () -%3E %7B%0A                            try %7B%0A                                final Optional%3CString%3E fileName = JsonReport.getInstance().generateReport();%0A                                LOGGER.info(String.format(REPORT_GENERATED_MSG, fileName.get()));%0A                            %7D catch (final GenerateReportException e) %7B%0A                                LOGGER.log(Level.ERROR, e.getMessage());%0A                            %7D%0A                        %7D);%0A%0A    %7D
 %0A%7D%0A

Use BlockingObservable to avoid closing the app before the process is done.