/*
 * Bach - Java Shell Builder
 * Copyright (C) 2019 Christian Stein
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.sormuras.bach;

import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.TRACE;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

/*BODY*/
/** Build, i.e. compile and package, a modular Java project. */
public /*STATIC*/ class JigsawBuilder implements Callable<Integer> {

  final Bach bach;
  final Path bin;
  final Path lib;
  final Path src;
  final String version;

  JigsawBuilder(Bach bach) {
    this.bach = bach;
    this.version = bach.project.version;
    this.bin = bach.run.work.resolve(bach.project.path(Project.Property.PATH_BIN));
    this.lib = bach.run.home.resolve(bach.project.path(Project.Property.PATH_LIB));
    this.src = bach.run.home.resolve(bach.project.path(Project.Property.PATH_SRC));
  }

  public Integer call() throws Exception {
    bach.run.log(TRACE, "JigsawBuilder::call()");
    compile("main");
    compile("test", "main");
    return 0;
  }

  void compile(String realm, String... requiredRealms) throws Exception {
    var modules = bach.project.modules(realm);
    if (modules.isEmpty()) {
      bach.run.log(DEBUG, "No %s modules found.", realm);
      return;
    }
    compile(realm, modules, requiredRealms);
    bach.run.log(DEBUG, "Jigsaw %s compilation successful.", realm);
  }

  void compile(String realm, List<String> modules, String... requiredRealms) throws Exception {
    bach.run.log(DEBUG, "Compiling %s modules: %s", realm, modules);

    var classes = bin.resolve(realm + "/classes");
    var binModules = Files.createDirectories(bin.resolve(realm + "/modules")); // "own" jars
    var binSources = Files.createDirectories(bin.resolve(realm + "/sources"));

    var modulePath = new ArrayList<>(bach.project.modulePath(realm, "compile", requiredRealms));
    modulePath.add(binModules);
    for (var requiredRealm : requiredRealms) {
      modulePath.add(bin.resolve(requiredRealm + "/modules"));
    }

    bach.run.run(
        new Command("javac")
            .add("-d", classes)
            .add("--module-path", modulePath)
            .add("--module-source-path", src + "/*/" + realm + "/java")
            .add("--module-version", version)
            .add("--module", String.join(",", modules)));

    for (var module : modules) {
      var resources = src.resolve(Path.of(module, realm, "resources"));
      bach.run.run(
          new Command("jar")
              .add("--create")
              .addIff(bach.run.debug, "--verbose")
              .add("--file", binModules.resolve(module + '-' + version + ".jar"))
              .add("-C", classes.resolve(module))
              .add(".")
              .addIff(Files.isDirectory(resources), cmd -> cmd.add("-C", resources).add(".")));
      bach.run.run(
          new Command("jar")
              .add("--create")
              .addIff(bach.run.debug, "--verbose")
              .add("--file", binSources.resolve(module + '-' + version + "-sources.jar"))
              .add("-C", src.resolve(Path.of(module, realm, "java")))
              .add(".")
              .addIff(Files.isDirectory(resources), cmd -> cmd.add("-C", resources).add(".")));
    }
  }
}

@@ -757,16 +757,37 @@
 TRACE;%0A%0A
+import java.io.File;%0A
 import j
@@ -1089,429 +1089,58 @@
 ch;%0A
-  final Path bin;%0A  final Path lib;%0A  final Path src;%0A  final String version;%0A%0A  JigsawBuilder(Bach bach) %7B%0A    this.bach = bach;%0A    this.version = bach.project.version;%0A    this.bin = bach.run.work.resolve(bach.project.path(Project.Property.PATH_BIN));%0A    this.lib = bach.run.home.resolve(bach.project.path(Project.Property.PATH_LIB));%0A    this.src = bach.run.home.resolve(bach.project.path(Project.Property.PATH_SRC))
+%0A  JigsawBuilder(Bach bach) %7B%0A    this.bach = bach
 ;%0A  
@@ -1813,24 +1813,56 @@
  modules);%0A%0A
+    var bin = bach.project.bin;%0A
     var clas
@@ -2322,86 +2322,590 @@
   %7D%0A
-%0A    bach.run.run(%0A        new Command(%22javac%22)%0A            .add(%22-d%22, classes
+    var src = bach.project.src;%0A    var moduleSourcePath = String.join(File.separator, src.toString(), %22*%22, realm, %22java%22);%0A%0A    var version = bach.project.version;%0A    var preview = %22enable%22.equals(bach.project.get(realm + %22.javac.preview%22));%0A    var defaultRelease = preview ? %22%22 + Runtime.version().feature() : null;%0A    var release = bach.project.get(realm + %22.javac.release%22, defaultRelease);%0A    bach.run.run(%0A        new Command(%22javac%22)%0A            .add(%22-d%22, classes)%0A            .addIff(preview,%22--enable-preview%22)%0A            .addIff(release != null, %22--release%22, release
 )%0A  
@@ -2993,37 +2993,24 @@
 h%22, 
-src + %22/*/%22 + realm + %22/java%22
+moduleSourcePath
 )%0A  

Add support for javac release and enable-preview options