class TerminalOptionsBuilder {

    public static Options options() {
        final Options options = new Options();

        final OptionGroup actionGroup = new OptionGroup();
        actionGroup.addOption(Option.builder()
            .longOpt(TerminalAction.upload.name())
            .desc("Upload file or folder recursively")
            .hasArgs().numberOfArgs(2).argName("url> <file").build());
        actionGroup.addOption(Option.builder("d")
            .longOpt(TerminalAction.download.name())
            .desc("Download file or folder. Denote a folder with a trailing '/'")
            .hasArgs().numberOfArgs(2).argName("url> <file").build());
        actionGroup.addOption(Option.builder()
            .longOpt(TerminalAction.copy.name())
            .desc("Copy between servers")
            .hasArgs().numberOfArgs(2).argName("url> <url").build());
        actionGroup.addOption(Option.builder("l")
            .longOpt(TerminalAction.list.name())
            .desc("List files in remote folder")
            .hasArg().argName("url").build());
        actionGroup.addOption(Option.builder("L")
            .longOpt(TerminalAction.longlist.name())
            .desc("Long list format with modification date and permission mask")
            .hasArg().argName("url").build());
        actionGroup.addOption(Option.builder("D")
            .longOpt(TerminalAction.delete.name())
            .desc("Delete")
            .hasArg().argName("url").build());
        actionGroup.addOption(Option.builder("c")
            .longOpt(TerminalAction.mkdir.name())
            .desc("Make directory")
            .hasArg().argName("url").build());
        actionGroup.addOption(Option.builder()
            .longOpt(TerminalAction.synchronize.name())
            .desc("Synchronize folders")
            .hasArgs().numberOfArgs(2).argName("url> <directory").build());
        actionGroup.addOption(Option.builder()
            .longOpt(TerminalAction.edit.name())
            .desc("Edit file in external editor")
            .hasArg().argName("url").build());
        actionGroup.addOption(Option.builder("V")
            .longOpt(TerminalAction.version.name())
            .desc("Show version number and quit.").build());
        actionGroup.addOption(Option.builder("h")
            .longOpt(TerminalAction.help.name())
            .desc("Print this help").build());

        actionGroup.setRequired(true);
        options.addOptionGroup(actionGroup);

        options.addOption(Option.builder("u")
            .longOpt(Params.username.name())
            .desc("Username")
            .hasArg().argName("username or access key").build());
        options.addOption(Option.builder("p")
            .longOpt(Params.password.name())
            .desc("Password")
            .hasArg().argName("password or secret key").build());
        options.addOption(Option.builder()
            .longOpt(Params.profile.name())
            .desc("Use connection profile")
            .hasArg().argName("profile").build());
        options.addOption(Option.builder("i")
            .longOpt(Params.identity.name())
            .desc("Selects a file from which the identity (private key) for public key authentication is read.")
            .hasArg().argName("private key file").build());

        options.addOption(Option.builder()
            .longOpt(Params.chmod.name())
            .desc("Set explicit permission from octal mode value for uploaded file")
            .hasArg().argName("mode").build());

        options.addOption(Option.builder()
            .longOpt(Params.application.name())
            .desc("External editor application")
            .hasArg().argName("path").build());

        options.addOption(Option.builder()
            .longOpt(Params.region.name())
            .desc("Location of bucket or container")
            .hasArg().argName("location").build());

        options.addOption(Option.builder("P")
            .longOpt(Params.preserve.name())
            .desc("Preserve permissions and modificatin date for transferred files").build());
        options.addOption(Option.builder("r")
            .longOpt(Params.retry.name())
            .desc("Retry failed connection attempts")
            .optionalArg(true).argName("count").build());
        options.addOption(Option.builder()
            .longOpt(Params.udt.name())
            .desc("Use UDT protocol if applicable").build());
        options.addOption(Option.builder()
            .longOpt(Params.parallel.name())
            .desc("Number of concurrent connections to use for transfers")
            .hasArg().optionalArg(true).argName("connections").build());
        options.addOption(Option.builder()
            .longOpt(Params.throttle.name())
            .desc("Throttle bandwidth")
            .hasArg().argName("bytes per second").build());
        options.addOption(Option.builder()
            .longOpt(Params.nochecksum.name())
            .desc("Skip verifying checksum").build());
        options.addOption(Option.builder()
            .longOpt(Params.nokeychain.name())
            .desc("Do not save passwords in keychain").build());
        options.addOption(Option.builder()
            .longOpt(Params.vault.name())
            .desc("Unlock vault")
            .hasArg().argName("path").build());

        final StringBuilder actions = new StringBuilder("Transfer actions for existing files").append(StringUtils.LF);
        actions.append("Downloads and uploads:").append(StringUtils.LF);
        for(TransferAction a : TransferAction.forTransfer(Transfer.Type.download)) {
            append(actions, a);
        }
        for(TransferAction a : Collections.singletonList(TransferAction.cancel)) {
            append(actions, a);
        }
        actions.append("Synchronize:").append(StringUtils.LF);
        for(TransferAction a : TransferAction.forTransfer(Transfer.Type.sync)) {
            append(actions, a);
        }
        for(TransferAction a : Collections.singletonList(TransferAction.cancel)) {
            append(actions, a);
        }

        options.addOption(Option.builder("e")
            .longOpt(Params.existing.name())
            .desc(actions.toString())
            .hasArg().argName("action").build());
        options.addOption(Option.builder("v")
            .longOpt(Params.verbose.name())
            .desc("Print transcript").build());
        options.addOption(Option.builder()
            .longOpt(Params.debug.name())
            .desc("Print debug output").build());
        options.addOption(Option.builder("q")
            .longOpt(Params.quiet.name())
            .desc("Suppress progress messages").build());
        options.addOption(Option.builder("y")
            .longOpt(Params.assumeyes.name())
            .desc("Assume yes for all prompts").build());

        return options;
    }

    private  TerminalOptionsBuilder();

}