package org.wildfly.extras.patch.internal;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBException;

import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wildfly.extras.patch.ManagedPath;
import org.wildfly.extras.patch.PatchException;
import org.wildfly.extras.patch.PatchId;
import org.wildfly.extras.patch.PatchTool;
import org.wildfly.extras.patch.PatchToolBuilder;

public class SelfExecutingMain {
    private static final Logger LOG = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) {
        try {
            mainInternal(args);
        } catch (Throwable th) {
            Runtime.getRuntime().exit(1);
        }
    }

    // Entry point with no system exit
    public static void mainInternal(String[] args) throws Throwable {
        SelfExecutingOptions options = new SelfExecutingOptions();
        CmdLineParser parser = new CmdLineParser(options);
        try {
            parser.parseArgument(args);
        } catch (CmdLineException ex) {
            parser.printUsage(System.err);
            throw ex;
        }

        try {
            run(parser, options);
        } catch (PatchException ex) {
            LOG.error("ERROR {}", ex.getMessage());
            LOG.debug("Patch Exception", ex);
            throw ex;
        } catch (Throwable th) {
            LOG.error("Error executing command", th);
            throw th;
        }
    }

    private static void run(CmdLineParser cmdParser, SelfExecutingOptions options) throws IOException, JAXBException {
        // Configure the patch tool builder
        PatchToolBuilder builder = new PatchToolBuilder();
        // See JarURLConnection
        builder.repositoryURL(SelfExecutingMain.class.getClassLoader().getResource("repository.index"));
        if (options.serverHome != null) {
            builder.serverPath(options.serverHome);
        }

        boolean opfound = false;

        // Query the repository
        if (options.queryRepository) {
            PatchTool patchTool = builder.build();
            printPatches(patchTool.getRepository().queryAvailable(null));
            opfound = true;
        }

        // Query the server
        if (options.queryServer) {
            PatchTool patchTool = builder.serverPath(options.serverHome).build();
            printPatches(patchTool.getServer().queryAppliedPatches());
            opfound = true;
        }

        // Query the server paths
        if (options.queryServerPaths != null) {
            PatchTool patchTool = builder.serverPath(options.serverHome).build();
            List<String> managedPaths = new ArrayList<String>();
            for (ManagedPath managedPath : patchTool.getServer().queryManagedPaths(options.queryServerPaths)) {
                managedPaths.add(managedPath.toString());
            }
            printLines(managedPaths);
            opfound = true;
        }

        // Install to server
        if (options.installId != null) {
            PatchTool patchTool = builder.serverPath(options.serverHome).build();
            patchTool.getServer().cleanUp();
            patchTool.install(PatchId.fromString(options.installId), options.force);
            opfound = true;
        }

        // Update the server
        if (options.updateName != null) {
            PatchTool patchTool = builder.serverPath(options.serverHome).build();
            patchTool.getServer().cleanUp();
            patchTool.update(options.updateName, options.force);
            opfound = true;
        }

        // Uninstall patch from server
        if (options.uninstallId != null) {
            PatchTool patchTool = builder.serverPath(options.serverHome).build();
            patchTool.getServer().cleanUp();
            patchTool.uninstall(PatchId.fromString(options.uninstallId));
            opfound = true;
        }

        // Print the audit log
        if (options.auditLog) {
            PatchTool patchTool = builder.serverPath(options.serverHome).build();
            printLines(patchTool.getServer().getAuditLog());
            opfound = true;
        }

        // Show help screen
        if (!opfound) {
            cmdParser.printUsage(System.err);
        }
    }

    private static void printLines(List<String> lines) {
        for (String line : lines) {
            System.out.println(line);
        }
    }

    private static void printPatches(List<PatchId> patches) {
        for (PatchId patchId : patches) {
            System.out.println(patchId.toString());
        }
    }
}

@@ -56,43 +56,184 @@
 .io.
-IOException;%0Aimport java.util.Array
+BufferedReader;%0Aimport java.io.IOException;%0Aimport java.io.InputStreamReader;%0Aimport java.net.URL;%0Aimport java.util.ArrayList;%0Aimport java.util.HashSet;%0Aimport java.util.Linked
 List
@@ -377,24 +377,69 @@
 LineParser;%0A
+import org.kohsuke.args4j.spi.OptionHandler;%0A
 import org.s
@@ -1230,32 +1230,131 @@
 arser(options);%0A
+%0A        // Remove any options marked for removal by patch creator%0A        removeOptions(parser);%0A%0A
         try %7B%0A  
@@ -4941,11 +4941,1070 @@
  %7D%0A    %7D
+%0A%0A    private static void removeOptions(CmdLineParser parser) throws IOException %7B%0A        HashSet%3CString%3E removeNames = new HashSet%3CString%3E();%0A        URL removalFile = SelfExecutingMain.class.getClassLoader().getResource(%22fp_option_removals%22);%0A        if (removalFile != null) %7B%0A            BufferedReader reader = new BufferedReader(new InputStreamReader(removalFile.openStream()));%0A            String line = null;%0A            while ((line = reader.readLine()) != null) %7B%0A                line = line.trim();%0A                if (line != %22%22) %7B%0A                    // ex: --uninstall%0A                    removeNames.add(line);%0A                %7D%0A            %7D%0A        %7D%0A%0A        LinkedList%3COptionHandler%3C?%3E%3E toRemove = new LinkedList%3COptionHandler%3C?%3E%3E();%0A        for (OptionHandler%3C?%3E option : parser.getOptions()) %7B%0A            if (removeNames.contains(option.option.toString())) %7B%0A                toRemove.add(option);%0A            %7D%0A        %7D%0A%0A        for (OptionHandler%3C?%3E option : toRemove) %7B%0A            parser.getOptions().remove(option);%0A        %7D%0A    %7D
 %0A%7D%0A

Add optional resource file to allow the patch creator to remove CLI options like --uninstall