package com.github.sormuras.bach.call;

import com.github.sormuras.bach.Call;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.UnaryOperator;

public interface AnyCall<C extends AnyCall<C>> extends Call {

  C arguments(List<String> arguments);

  default C with(String argument) {
    var copy = new ArrayList<>(arguments());
    copy.add(argument);
    return arguments(List.copyOf(copy));
  }

  default C with(String option, Object value) {
    var copy = new ArrayList<>(arguments());
    copy.add(option);
    copy.add(value.toString());
    return arguments(List.copyOf(copy));
  }

  default C with(String option, Object value, Object... more) {
    var copy = new ArrayList<>(arguments());
    copy.add(option);
    copy.add(value.toString());
    for (var next : more) copy.add(next.toString());
    return arguments(List.copyOf(copy));
  }

  default C with(String option, Collection<Path> paths) {
    var strings = paths.stream().map(Path::toString).toList();
    return with(option, String.join(File.pathSeparator, strings));
  }

  default C withAll(String... arguments) {
    var copy = new ArrayList<>(arguments());
    copy.addAll(List.of(arguments));
    return arguments(List.copyOf(copy));
  }

  default C withAll(Object... arguments) {
    return withAll(List.of(arguments));
  }

  default C withAll(Collection<?> collection) {
    var copy = new ArrayList<>(arguments());
    collection.stream().map(Object::toString).forEach(copy::add);
    return arguments(List.copyOf(copy));
  }

  @SuppressWarnings("unchecked")
  default C ifTrue(boolean condition, UnaryOperator<C> operator) {
    return condition ? operator.apply((C) this) : (C) this;
  }

  @SuppressWarnings("unchecked")
  default <T extends Collection<?>> C ifPresent(T collection, BiFunction<C, T, C> function) {
    return collection.isEmpty() ? (C) this : function.apply((C) this, collection);
  }

  @SuppressWarnings({"unchecked", "OptionalUsedAsFieldOrParameterType"})
  default <T> C ifPresent(Optional<T> optional, BiFunction<C, T, C> function) {
    return optional.isPresent() ? function.apply((C) this, optional.get()) : (C) this;
  }

  @SuppressWarnings("unchecked")
  default <E> C forEach(Collection<E> collection, BiFunction<C, E, C> function) {
    var command = (C) this;
    for (var element : collection) command = function.apply(command, element);
    return command;
  }
}
@@ -195,24 +195,46 @@
 .util.List;%0A
+import java.util.Map;%0A
 import java.
@@ -2066,32 +2066,222 @@
 llection);%0A  %7D%0A%0A
+  @SuppressWarnings(%22unchecked%22)%0A  default %3CT extends Map%3C?, ?%3E%3E C ifPresent(T map, BiFunction%3CC, T, C%3E function) %7B%0A    return map.isEmpty() ? (C) this : function.apply((C) this, map);%0A  %7D%0A%0A
   @SuppressWarni

Add conditional non-empty map support