package jetbrains.mps.project.persistence;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import jetbrains.mps.vfs.IFile;
import jetbrains.mps.util.MacroHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jdom.Element;
import jetbrains.mps.project.structure.project.ProjectDescriptor;
import jetbrains.mps.project.structure.project.ModulePath;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.util.xml.XmlUtil;
import java.io.IOException;
import jetbrains.mps.util.JDOMUtil;
import org.jdom.Document;
import jetbrains.mps.vfs.path.Path;

@GeneratedClass(node = "r:a42e26eb-bbea-4e8d-a549-0d224ab71e57(jetbrains.mps.project.persistence)/842994667883032218", model = "r:a42e26eb-bbea-4e8d-a549-0d224ab71e57(jetbrains.mps.project.persistence)")
public class ProjectDescriptorPersistence {
  private static final String MPS_DOT_FOLDER = ".mps";
  private static final String MODULES_XML_LOCATION = "modules.xml";
  private static final String MODULE_PATH_TAG = "modulePath";
  private static final String FOLDER_TAG = "folder";
  private static final String PROJECT_MODULES_TAG = "projectModules";
  private static final String PATH_TAG = "path";
  /**
   * Value of StandaloneMPSProject.@State.name
   */
  private static final String COMPONENT_NAME = "MPSProject";

  private final IFile myProjectDir;
  private final MacroHelper myMacroHelper;

  /**
   * 
   * @param projectDir root of the project (location where .mps/ resides)
   */
  public ProjectDescriptorPersistence(@NotNull IFile projectDir, @NotNull MacroHelper macroHelper) {
    if (projectDir.exists() && !(projectDir.isDirectory())) {
      throw new IllegalArgumentException();
    }
    // FIXME provisional code while I deal with File cons
    myProjectDir = projectDir;
    // FIXME introduce MacroHelper alternative that shrinks/expands IFile <-> PathOutcome (or just Path)
    //     Besides, would be great to keep track of original macro to keep save/load consistent (in case
    //     there's another macro that might affect the path). Would also help to show macro in UI (there's MPS-34199)
    myMacroHelper = macroHelper;
  }

  @Nullable
  public Element save(@NotNull ProjectDescriptor descriptor) {
    Element project = new Element("project");
    Element projectModules = new Element(PROJECT_MODULES_TAG);
    for (ModulePath path : Sequence.fromIterable(((Iterable<ModulePath>) descriptor.getModulePaths())).sort((p) -> shrinkPath(p), true)) {
      // TODO: move from MacrosFactory to PathMacroUtil
      XmlUtil.tagWithAttributes(projectModules, MODULE_PATH_TAG, PATH_TAG, shrinkPath(path), FOLDER_TAG, path.getVirtualFolder());
    }
    project.addContent(projectModules);
    return project;
  }

  public void saveToFile(@NotNull ProjectDescriptor descriptor) throws IOException {
    Element pd = save(descriptor);
    if (pd == null) {
      return;
    }
    IFile projectFile = findProjectFile();
    Element top = new Element("project");
    // version="4" is what I see as of this writing in my .mps/modules.xml
    top.setAttribute("version", "4");
    Element c = new Element("component");
    c.setAttribute("name", COMPONENT_NAME);
    top.addContent(c);
    c.addContent(pd.getContent());
    JDOMUtil.writeDocument(new Document(top), projectFile);
  }

  private String shrinkPath(@NotNull ModulePath p) {
    String shrinkedPath = myMacroHelper.shrinkPath(p.getFile().getPath());
    // fixme such filepath conversion is not supported by Path (IDEA stores windows paths as C:/smth !)
    return shrinkedPath.replace(Path.WIN_SEPARATOR, Path.UNIX_SEPARATOR);
  }

  @NotNull
  public ProjectDescriptor load(@Nullable Element root) {
    // XXX is it intentional that we don't read project name from persistence?
    final String name = myProjectDir.getName();
    ProjectDescriptor descriptor = new ProjectDescriptor(name);
    if (root == null) {
      return descriptor;
    }
    ProjectDescriptor result_jnk9az_a4a91 = descriptor;
    for (Element moduleElement : Sequence.fromIterable(XmlUtil.children(XmlUtil.first(root, PROJECT_MODULES_TAG), MODULE_PATH_TAG))) {
      String path = myMacroHelper.expandPath(moduleElement.getAttributeValue(PATH_TAG));
      String virtualFolder = moduleElement.getAttributeValue(FOLDER_TAG);
      ModulePath modulePath = new ModulePath(myProjectDir.getFS().getFile(path), virtualFolder);
      result_jnk9az_a4a91.addModulePath(modulePath);
    }
    return descriptor;
  }

  @NotNull
  public ProjectDescriptor loadFromFile() {
    return load(loadProjectElement());
  }

  @Nullable
  public Element loadProjectElement() {
    try {
      IFile projectFile = findProjectFile();
      // XXX why findProjectFile throws exception when myBaseDir doesn't exist, but here we simply return null if the file there does not exist?
      if (!(projectFile.exists())) {
        return null;
      }
      Document document = JDOMUtil.loadDocument(projectFile);
      Iterable<Element> components = document.getRootElement().getChildren("component");
      return Sequence.fromIterable(components).findFirst((it) -> COMPONENT_NAME.equals(it.getAttributeValue("name")));
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  @NotNull
  private IFile findProjectFile() {
    return myProjectDir.findChild(MPS_DOT_FOLDER).findChild(MODULES_XML_LOCATION);
  }
}
