package jetbrains.mps.lang.test.generator.rt;

/*Generated by MPS */

import org.jetbrains.mps.openapi.module.SRepository;
import jetbrains.mps.messages.IMessageHandler;
import org.jetbrains.mps.openapi.model.SModel;
import jetbrains.mps.generator.ModelGenerationPlan;
import jetbrains.mps.generator.GenerationStatus;
import jetbrains.mps.generator.TransientModelsProvider;
import jetbrains.mps.generator.GenerationOptions;
import jetbrains.mps.generator.GenerationFacade;
import jetbrains.mps.generator.GenerationTaskRecorder;
import jetbrains.mps.generator.GeneratorTask;
import jetbrains.mps.progress.EmptyProgressMonitor;
import java.util.Collection;

public final class TransformHelper {
  private final SRepository myRepository;
  private final IMessageHandler myMessages;
  private SModel myInputModel;
  private ModelGenerationPlan.Provider myPlanProvider;
  private GenerationStatus myGenOutcome;
  private TransientModelsProvider myTransientsProvider;

  /*package*/ TransformHelper(SRepository repository, IMessageHandler messages) {
    myRepository = repository;
    myMessages = messages;
  }
  public TransformHelper setInput(SModel inputModel) {
    myInputModel = inputModel;
    return this;
  }
  public TransformHelper setPlan(ModelGenerationPlan generationPlan) {
    return this;
  }

  public TransformHelper setPlanProvider(ModelGenerationPlan.Provider gpProvider) {
    myPlanProvider = gpProvider;
    return this;
  }

  public TransformHelper transform() {
    // XXX Guess, I shall re-use TMP if TransformHelper is reused.
    myTransientsProvider = new TransientModelsProvider(myRepository, null);
    myTransientsProvider.getRepository().getModelAccess().runWriteAction(() -> {
      GenerationOptions.OptionsBuilder optBuilder = GenerationOptions.getDefaults();
      ModelGenerationPlan plan = (myPlanProvider == null ? null : myPlanProvider.getPlan(myInputModel));
      if (plan != null) {
        optBuilder.customPlan(myInputModel, plan);
        myTransientsProvider.initCheckpointModule();
      }
      GenerationFacade genFacade = new GenerationFacade(myRepository, optBuilder.create());
      final GenerationTaskRecorder<GeneratorTask> taskHandler = new GenerationTaskRecorder<GeneratorTask>(null);
      genFacade.transients(myTransientsProvider).messages(myMessages).taskHandler(taskHandler);
      genFacade.process(new EmptyProgressMonitor(), myInputModel);
      myGenOutcome = taskHandler.getAllRecorded().get(0);
    });
    return this;

  }

  public GenerationStatus getResult() {
    assert myGenOutcome != null : "invoke() transform first!";
    return myGenOutcome;
  }

  public SModel getOutputModel() {
    return getResult().getOutputModel();
  }

  public Collection<SModel> getOutputModels() {
    return getResult().getOutputModels();
  }

  public void dispose() {
    myTransientsProvider.removeAllTransients(true);
    myTransientsProvider = null;
    myInputModel = null;
    myPlanProvider = null;
    myGenOutcome = null;
  }
}
