package jetbrains.mps.project.modules;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import jetbrains.mps.logging.Logger;
import jetbrains.mps.project.MPSProject;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.project.Solution;
import jetbrains.mps.vfs.IFile;
import jetbrains.mps.project.MPSExtentions;
import jetbrains.mps.project.structure.modules.SolutionDescriptor;
import jetbrains.mps.project.facets.JavaModuleFacet;
import jetbrains.mps.project.facets.JavaModuleFacetImpl;
import jetbrains.mps.smodel.GeneralModuleFactory;
import jetbrains.mps.smodel.ModuleDependencyVersions;
import jetbrains.mps.smodel.language.LanguageRegistry;
import jetbrains.mps.project.ModuleId;
import jetbrains.mps.persistence.DefaultModelRoot;
import jetbrains.mps.project.ProjectPathUtil;

@GeneratedClass(node = "r:7e5abd68-4144-4e78-a2a2-1346b70af9c3(jetbrains.mps.project.modules)/1723752571811373979", model = "r:7e5abd68-4144-4e78-a2a2-1346b70af9c3(jetbrains.mps.project.modules)")
public class SolutionProducer {
  private static final Logger LOG = Logger.getLogger(SolutionProducer.class);
  private final MPSProject myProject;

  private JavaFacetLevel myJavaFacetLevel = JavaFacetLevel.Regular;

  public SolutionProducer(@NotNull MPSProject mpsProject) {
    myProject = mpsProject;
  }

  public Solution create(@NotNull String namespace, @NotNull IFile moduleDir) {
    IFile descriptorFile = moduleDir.findChild(namespace + MPSExtentions.DOT_SOLUTION);
    // FIXME error reporting

    SolutionDescriptor descriptor = createSolutionDescriptor(namespace, descriptorFile);
    if (myJavaFacetLevel == JavaFacetLevel.Off) {
      descriptor.getModuleFacetDescriptors().removeIf((d) -> JavaModuleFacet.FACET_TYPE.equals(d.getType()));
    }
    if (myJavaFacetLevel == JavaFacetLevel.Regular || myJavaFacetLevel == JavaFacetLevel.Contributor) {
      // XXX would be better to have this value set inside JMFI.forNewJavaCodeModule()
      JavaModuleFacetImpl.setDefaultClassesGenLocation(descriptor, moduleDir);
    }
    Solution module = (Solution) new GeneralModuleFactory().instantiate(descriptor, descriptorFile);
    myProject.addModule(module);
    new ModuleDependencyVersions(myProject.getComponent(LanguageRegistry.class), myProject.getRepository()).update(module);
    final JavaModuleFacet jmf = module.getFacet(JavaModuleFacet.class);
    if (myJavaFacetLevel != JavaFacetLevel.Off && jmf != null) {
      switch (myJavaFacetLevel) {
        case Sandbox:
          jmf.setCompile(JavaModuleFacet.Compile.None);
          jmf.setLoadClasses(JavaModuleFacet.LoadClasses.NotAvailable);
          jmf.setLoadExtensions(JavaModuleFacet.LoadExtensions.NotAvailable);
          break;
        case Regular:
          jmf.setCompile(JavaModuleFacet.Compile.MPS);
          jmf.setLoadClasses(JavaModuleFacet.LoadClasses.ManagedByMPS);
          jmf.setLoadExtensions(JavaModuleFacet.LoadExtensions.NotAvailable);
          break;
        case Contributor:
          jmf.setCompile(JavaModuleFacet.Compile.MPS);
          jmf.setLoadClasses(JavaModuleFacet.LoadClasses.ManagedByMPS);
          jmf.setLoadExtensions(JavaModuleFacet.LoadExtensions.Plugin);
          break;
      }
    }
    module.save();
    return module;
  }

  public void withoutJavaFacet() {
    myJavaFacetLevel = JavaFacetLevel.Off;
  }
  public void withPluginJavaFacet() {
    myJavaFacetLevel = JavaFacetLevel.Contributor;
  }
  public void withSandboxJavaFacet() {
    myJavaFacetLevel = JavaFacetLevel.Sandbox;
  }

  public static SolutionDescriptor createSolutionDescriptor(String namespace, IFile descriptorFile) {
    // FIXME public until uses in NewModuleUtil gone
    SolutionDescriptor descriptor = new SolutionDescriptor();
    descriptor.setNamespace(namespace);
    descriptor.setId(ModuleId.regular());
    IFile moduleLocation = descriptorFile.getParent();
    // FIXME error reporting
    final IFile modelsDir = moduleLocation.findChild(Solution.SOLUTION_MODELS);
    if (modelsDir.exists() && modelsDir.getChildren().size() != 0) {
      if (LOG.isErrorLevel()) {
        LOG.error("Trying to create a solution in an existing solution's directory: " + moduleLocation);
      }
      throw new IllegalStateException("Trying to create a solution in an existing solution's directory: " + moduleLocation);
    } else {
      // we assume create happens under proper application write lock, would be odd to manage locks here
      modelsDir.mkdirs();
    }

    descriptor.getModelRootDescriptors().add(DefaultModelRoot.createDescriptor(modelsDir.getParent(), modelsDir));
    // keep JMF for a new descriptor as it used to be, although need for JMF is not apparent, and caller shall configure 
    // module descriptor and facet descriptors according to own needs
    descriptor.getModuleFacetDescriptors().add(JavaModuleFacetImpl.forNewJavaCodeModule());
    ProjectPathUtil.setGeneratorOutputPath(descriptor, moduleLocation.findChild("source_gen").getPath());
    return descriptor;
  }

  private enum JavaFacetLevel {
    Off(),
    Sandbox(),
    Regular(),
    Contributor()
  }
}
