package jetbrains.mps.tool.builder.make;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import jetbrains.mps.tool.builder.CoreWorker;
import jetbrains.mps.tool.common.Script;
import jetbrains.mps.tool.common.GeneratorProperties;
import jetbrains.mps.generator.IModifiableGenerationSettings;
import jetbrains.mps.generator.GenerationSettingsProvider;
import jetbrains.mps.project.Project;
import java.util.Collection;
import org.jetbrains.mps.openapi.module.SModule;
import jetbrains.mps.smodel.resources.MResource;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.make.MakeSession;
import jetbrains.mps.tool.builder.WorkerMessageHandler;
import jetbrains.mps.internal.make.cfg.JavaCompileFacetInitializer;
import jetbrains.mps.make.script.IScriptController;
import java.util.concurrent.Future;
import jetbrains.mps.make.script.IResult;
import jetbrains.mps.progress.EmptyProgressMonitor;
import java.util.concurrent.ExecutionException;
import jetbrains.mps.baseLanguage.closures.runtime.Wrappers;
import org.jetbrains.mps.openapi.model.SModel;
import java.util.List;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import jetbrains.mps.generator.ModelGenerationStatusManager;
import jetbrains.mps.smodel.resources.ModelsToResources;

@GeneratedClass(node = "r:2758abb3-4e9a-4fac-8e72-2fadd8b5c3d7(jetbrains.mps.tool.builder.make)/878521226301293996", model = "r:2758abb3-4e9a-4fac-8e72-2fadd8b5c3d7(jetbrains.mps.tool.builder.make)")
public abstract class BaseGeneratorWorker extends CoreWorker {
  private boolean mySkipUnmodifiedModels;

  public BaseGeneratorWorker(Script whatToDo) {
    super(whatToDo);
  }

  protected void setGenerationProperties() {
    GeneratorProperties gp = new GeneratorProperties(myWhatToDo);
    IModifiableGenerationSettings settings = getPlatform().findComponent(GenerationSettingsProvider.class).getGenerationSettings();
    boolean strictMode = gp.isStrictMode();
    boolean parallelMode = gp.isParallelMode();
    boolean inplace = gp.isInplaceTransform();
    boolean warnings = !(gp.isHideWarnings());
    int threadCount = gp.getParallelThreads();
    final boolean useStaticRefs = gp.isCreateStaticRefs();
    mySkipUnmodifiedModels = gp.isSkipUnmodifiedModels();

    settings.setStrictMode(strictMode);
    if (strictMode) {
      settings.setParallelGenerator(parallelMode);
      if (parallelMode) {
        settings.setNumberOfParallelThreads(threadCount);
      }
    }
    String[] onoff = new String[]{"on", "off"};
    settings.enableInplaceTransformations(inplace);
    settings.setShowBadChildWarning(warnings);
    settings.setCreateStaticReferences(useStaticRefs);
    settings.setCheckModelsBeforeGeneration(false);
    if ("info".equalsIgnoreCase(gp.getMessageLevel())) {
      settings.setShowInfo(true);
      settings.setShowWarnings(true);
    }
    if ("warn".equalsIgnoreCase(gp.getMessageLevel())) {
      settings.setShowWarnings(true);
    }
    info(String.format("Generating: strict mode is %s, parallel generation is %s (%d threads), in-place is %s, child warnings are %s, static references to replace dynamic is %s, skip unmodified models is %s", onoff[(strictMode ? 0 : 1)], onoff[(parallelMode ? 0 : 1)], (parallelMode ? threadCount : 1), onoff[(inplace ? 0 : 1)], onoff[(warnings ? 0 : 1)], onoff[(useStaticRefs ? 0 : 1)], onoff[(mySkipUnmodifiedModels ? 0 : 1)]));
  }

  protected void showStatistic() {
    failBuild("generation");
  }

  protected void generate(Project project, Collection<SModule> modules) {
    StringBuffer s = new StringBuffer("Generating:");
    for (SModule m : modules) {
      s.append("\n    ");
      s.append(m);
    }
    info(s.toString());
    Iterable<MResource> resources = Sequence.fromIterable(collectResources(project, modules)).toList();
    if (mySkipUnmodifiedModels && Sequence.fromIterable(resources).all((it) -> Sequence.fromIterable(it.models()).isEmpty())) {
      info("No models to generate. Skipping generation.");
      return;
    }

    myEnvironment.flushAllEvents();
    final MakeSession session = new MakeSession(project, new WorkerMessageHandler(this), true);
    JavaCompileFacetInitializer jcfi = new JavaCompileFacetInitializer().skipCompilation(mySkipCompilation).setJavaCompileOptions(myJavaCompilerOptions);
    IScriptController controller = new IScriptController.Stub2(session, jcfi);
    Future<IResult> res = new BuildMakeService().make(session, resources, null, controller, new EmptyProgressMonitor());

    try {
      IResult ires = res.get();
      if (ires == null || !(ires.isSucessful())) {
        myErrors.add("Make was not successful");
      }
    } catch (InterruptedException | ExecutionException e) {
      myErrors.add(e.toString());
    }
    myEnvironment.flushAllEvents();
  }

  protected Iterable<MResource> collectResources(final Project project, final Collection<SModule> modules) {
    // FIXME it's odd to have distinct set of modules but lock repository to access its modules.
    // Shall rather keem modules as part of the project
    final Wrappers._T<Iterable<SModel>> models = new Wrappers._T<Iterable<SModel>>(null);
    project.getModelAccess().runReadAction(() -> {
      for (SModule mod : modules) {
        models.value = Sequence.fromIterable(models.value).concat(Sequence.fromIterable(mod.getModels()));
      }

      if (mySkipUnmodifiedModels) {
        List<SModel> modelsList = (models.value == null ? ListSequence.fromList(new ArrayList<SModel>()) : Sequence.fromIterable(models.value).toList());
        int numberOfAllModels = ListSequence.fromList(modelsList).count();

        ModelGenerationStatusManager mgsm = project.getComponent(ModelGenerationStatusManager.class);
        models.value = mgsm.getModifiedModels(modelsList);
        info("Found " + Sequence.fromIterable(models.value).count() + " modified models out of " + numberOfAllModels + " total models.");
      }
    });

    // XXX resources() needs model access, isn't it?
    return Sequence.fromIterable(new ModelsToResources(models.value).resources()).ofType(MResource.class);
  }

}
