package jetbrains.mps.debugger.java.runtime.evaluation.container;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import jetbrains.mps.module.ReloadableModuleBase;
import jetbrains.mps.project.structure.modules.ModuleDescriptor;
import java.util.Set;
import jetbrains.mps.internal.collections.runtime.SetSequence;
import java.util.HashSet;
import jetbrains.mps.components.ComponentHost;
import java.util.concurrent.atomic.AtomicInteger;
import jetbrains.mps.vfs.IFile;
import jetbrains.mps.project.facets.JavaModuleFacet;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.module.SModule;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.persistence.Memento;
import jetbrains.mps.project.facets.JavaLanguageLevel;
import java.util.Collections;
import org.jetbrains.mps.openapi.model.SModel;
import jetbrains.mps.project.ModuleId;
import java.io.File;
import java.nio.file.Files;
import jetbrains.mps.vfs.IFileSystem;
import jetbrains.mps.vfs.VFSManager;
import java.io.IOException;
import org.jetbrains.mps.openapi.module.SModuleFacet;

/**
 * This module contains a necessary information for the 'evaluate expression'
 * action during a debug session.
 * Have to be ReloadableModule as I'd like to use MPS CLM mechanism to compile code and access generated classes.
 * Alternatively, may generate plain text, compile it with JavaCompiler impl, and load classes by some URLClassLoader, which seems too
 * much pain, provided rest of MPS sticks to ReloadableModule (e.g. temp models and console)
 * Although generic GenerationTargetFacet could suffice here to control output, need JMF to facilitate compilation/classloading
 */
@GeneratedClass(node = "r:f5448de3-0d76-42bb-afa7-00b3b32de849(jetbrains.mps.debugger.java.runtime.evaluation.container)/846214144107996104", model = "r:f5448de3-0d76-42bb-afa7-00b3b32de849(jetbrains.mps.debugger.java.runtime.evaluation.container)")
public final class EvaluationModule extends ReloadableModuleBase {
  private final ModuleDescriptor myDescriptor;
  private final Set<String> myClassPaths = SetSequence.fromSet(new HashSet<String>());
  private final ComponentHost myPlatform;
  private static final AtomicInteger ourCounter = new AtomicInteger();

  private IFile myTempModuleLocation;
  /**
   * pretty much identical to NaiveJavaModuleFacet, just don't want dependency and I don't like its approach to arguments
   * (createTempDirectory() in cons ignores them)
   */
  private final JavaModuleFacet myJavaFacet = new JavaModuleFacet() {
    @Nullable
    @Override
    public SModule getModule() {
      return EvaluationModule.this;
    }

    @NotNull
    @Override
    public String getFacetType() {
      return JavaModuleFacet.FACET_TYPE;
    }

    @Override
    public void save(@NotNull Memento p1) {
      // no-op
    }

    @Override
    public void load(@NotNull Memento p1) {
      // no-op
    }

    @Override
    public JavaLanguageLevel getLanguageLevel() {
      // why not, after all?
      return JavaLanguageLevel.JAVA_10;
    }

    @Nullable
    @Override
    public IFile getClassesGen() {
      return myTempModuleLocation.findChild("cls_gen");
    }

    @Override
    public Set<String> getLibraryClassPath() {
      // none specific to this module, I guess. In case there are any debugger-specific requirement, may add it here
      // although I expect to get everything needed through module dependencies
      return Collections.emptySet();
    }

    @Override
    public Set<String> getClassPath() {
      return Collections.singleton(getClassesGen().getPath());
    }

    @Override
    public Set<String> getAdditionalSourcePaths() {
      return Collections.emptySet();
    }

    @Nullable
    @Override
    public IFile getOutputRoot() {
      // not part of GenerationTargetFacet API, rather implementation helper for JMF, but there are uses through 
      // JMF directly, don't want to bother
      // Although I don't like to depend on getOutput*Location() in JMF, it's tedious to write proper replacement here
      // as I'd need to refactor FileGenerationUtil (or copy parts thereof here), which is not what I'm inclined to do now
      return myTempModuleLocation.findChild("src_gen");
    }


    @Nullable
    @Override
    public IFile getOutputRoot(@NotNull SModel model) {
      return getOutputRoot();
    }

    @NotNull
    @Override
    public JavaModuleFacet.Compile getCompile() {
      return JavaModuleFacet.Compile.MPS;
    }
    @NotNull
    @Override
    public JavaModuleFacet.LoadClasses getLoadClasses() {
      return JavaModuleFacet.LoadClasses.ManagedByMPS;
    }
    @Override
    public JavaModuleFacet.LoadExtensions getLoadExtensions() {
      return JavaModuleFacet.LoadExtensions.NotAvailable;
    }
  };

  private static int incCounter() {
    return ourCounter.incrementAndGet();
  }

  public EvaluationModule(ComponentHost mpsPlatform) {
    super((IFile) null);
    myPlatform = mpsPlatform;
    // follow pattern of TempModule2
    myDescriptor = new ModuleDescriptor();
    myDescriptor.setId(ModuleId.regular());
    myDescriptor.setNamespace("Evaluation Container Module " + incCounter());
    setModuleReference(myDescriptor.getModuleReference());
    try {
      File tempFile = Files.createTempDirectory("MPS-EVAL").toFile();
      IFileSystem fileSystem = mpsPlatform.findComponent(VFSManager.class).getFileSystem(VFSManager.JAVA_IO_FILE_FS);
      myTempModuleLocation = fileSystem.getFile(tempFile);
    } catch (IOException ex) {
      throw new IllegalStateException(ex);
    }
  }

  @Override
  public String toString() {
    return getModuleName();
  }

  @Override
  public ModuleDescriptor getModuleDescriptor() {
    return myDescriptor;
  }


  @Override
  public void save() {
    // no-op
  }

  @Override
  protected void updateFacets() {
    // no-op
  }

  @NotNull
  @Override
  public Iterable<SModuleFacet> getFacets() {
    return Collections.<SModuleFacet>singleton(myJavaFacet);
  }

  @Override
  public boolean isReadOnly() {
    return false;
  }

  @Override
  public boolean isPackaged() {
    // just in case there's code that doesn't compile packaged modules (although ModuleMaker respects isReadOnly)
    return false;
  }
}
