package com.github.sormuras.bach.core;

import com.github.sormuras.bach.Bach;
import com.github.sormuras.bach.ToolOperator;
import java.io.PrintWriter;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Optional;

public class Load implements ToolOperator {

  record Options(Optional<Boolean> reload, Path target, String source) {
    static final String USAGE = """
        Usage: load [--reload] TARGET SOURCE
        """;

    static Optional<Options> of(String... args) {
      if (args.length < 2 || args.length > 3) return Optional.empty();
      var reload = "--reload".equals(args[0]);
      return Optional.of(
          new Options(
              reload ? Optional.of(Boolean.TRUE) : Optional.empty(),
              Path.of(args[reload ? 1 : 0]),
              args[reload ? 2 : 1]));
    }
  }

  @Override
  public int run(Bach bach, PrintWriter out, PrintWriter err, String... args) {
    var optionalOptions = Options.of(args);
    if (optionalOptions.isEmpty()) {
      err.println(Options.USAGE);
      return 1;
    }
    var options = optionalOptions.get();
    var reload = options.reload().orElse(Boolean.FALSE);
    var target = options.target();
    if (Files.exists(target) && !reload) return 0;

    var source = options.source();
    if (source.startsWith("string:")) {
      try {
        var parent = target.getParent();
        if (parent != null) Files.createDirectories(parent);
        var string = source.substring(7);
        Files.writeString(target, string);
        out.printf("Wrote %,12d %s%n", string.length(), target.getFileName());
        return 0;
      } catch (Exception exception) {
        exception.printStackTrace(err);
        return 2;
      }
    }

    var paths = bach.configuration().paths();
    var from = URI.create(source);
    var scheme = from.getScheme();
    var uri = scheme == null ? paths.root(source).normalize().toAbsolutePath().toUri() : from;
    out.printf("Loading %s...%n", uri);
    try (var stream = uri.toURL().openStream()) {
      var parent = target.getParent();
      if (parent != null) Files.createDirectories(parent);
      var size = Files.copy(stream, target, StandardCopyOption.REPLACE_EXISTING);
      out.printf("Loaded %,12d %s%n", size, target.getFileName());
      return 0;
    } catch (Exception exception) {
      exception.printStackTrace(err);
      return 3;
    }
  }
}

@@ -117,16 +117,74 @@
 erator;%0A
+import com.github.sormuras.bach.internal.ArgumentsParser;%0A
 import j
@@ -392,18 +392,24 @@
 rator %7B%0A
-%0A
  
+ public
  record 
@@ -420,806 +420,224 @@
 ons(
-Optional%3CBoolean%3E reload, Path target, String source) %7B%0A    static final String USAGE = %22%22%22%0A        Usage: load %5B--reload%5D TARGET SOURCE%0A        %22%22%22;%0A%0A    static Optional%3COptions%3E of(String... args) %7B%0A      if (args.length %3C 2 %7C%7C args.length %3E 3) return Optional.empty();%0A      var reload = %22--reload%22.equals(args%5B0%5D);%0A      return Optional.of(%0A          new Options(%0A              reload ? Optional.of(Boolean.TRUE) : Optional.empty(),%0A              Path.of(args%5Breload ? 1 : 0%5D),%0A              args%5Breload ? 2 : 1%5D));%0A    %7D%0A  %7D%0A%0A  @Override%0A  public int run(Bach bach, PrintWriter out, PrintWriter err, String... args) %7B%0A    var optionalOptions = Options.of(args);%0A    if (optionalOptions.isEmpty()) %7B%0A      err.println(Options.USAGE);%0A      return 1;%0A    %7D%0A    var options = optionalOptions.get(
+Path target, String source, Optional%3CBoolean%3E reload) %7B%7D%0A%0A  @Override%0A  public int run(Bach bach, PrintWriter out, PrintWriter err, String... args) %7B%0A    var options = ArgumentsParser.create(Options.class).parse(args
 );%0A 

Replace custom argument parsing with record-based parsing