package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon;

import com.intellij.CommonBundle;
import com.intellij.ide.JavaUiBundle;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.ui.configuration.ModuleEditor;
import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable;
import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

public class ModuleProjectStructureElement extends ProjectStructureElement {
  private final Module myModule;

  public ModuleProjectStructureElement(@NotNull StructureConfigurableContext context, @NotNull Module module) {
    super(context);
    myModule = module;
  }

  public Module getModule() {
    return myModule;
  }

  public void checkModulesNames(ProjectStructureProblemsHolder problemsHolder) {
    final ModifiableModuleModel moduleModel = myContext.getModulesConfigurator().getModuleModel();
    final Module[] all = moduleModel.getModules();
    if (!ArrayUtil.contains(myModule, all)) {
      return;//module has been deleted
    }

    for (Module each : all) {
      if (each != myModule && myContext.getRealName(each).equals(myContext.getRealName(myModule))) {
        problemsHolder.registerProblem(JavaUiBundle.message("project.roots.module.duplicate.name.message"), null,
                                       ProjectStructureProblemType.error("duplicate-module-name"), createPlace(),
                                       null);
        break;
      }
    }
  }

  @Override
  public void check(ProjectStructureProblemsHolder problemsHolder) {
    checkModulesNames(problemsHolder);

    ModuleEditor moduleEditor = myContext.getModulesConfigurator().getModuleEditor(myModule);
    if (moduleEditor == null) return; //already disposed
    final ModuleRootModel rootModel = moduleEditor.getRootModel();
    final OrderEntry[] entries = rootModel.getOrderEntries();
    for (OrderEntry entry : entries) {
      if (!entry.isValid()){
        if (entry instanceof JdkOrderEntry && ((JdkOrderEntry)entry).getJdkName() == null) {
          if (!(entry instanceof InheritedJdkOrderEntry)) {
            problemsHolder.registerProblem(JavaUiBundle.message("project.roots.module.jdk.problem.message"), null, ProjectStructureProblemType.error("module-sdk-not-defined"), createPlace(entry),
                                           null);
          }
        }
        else {
          problemsHolder.registerProblem(JavaUiBundle.message("project.roots.library.problem.message", entry.getPresentableName()), null,
                                         ProjectStructureProblemType.error("invalid-module-dependency"), createPlace(entry),
                                         null);
        }
      }
    }
  }

  private PlaceInProjectStructure createPlace() {
    final Project project = myContext.getProject();
    return new PlaceInProjectStructureBase(project, ProjectStructureConfigurable.getInstance(project).createModulePlace(myModule), this);
  }

  private PlaceInProjectStructure createPlace(OrderEntry entry) {
    return new PlaceInModuleClasspath(myContext, myModule, this, entry);
  }

  @Override
  public List<ProjectStructureElementUsage> getUsagesInElement() {
    final List<ProjectStructureElementUsage> usages = new ArrayList<>();
    final ModuleEditor moduleEditor = myContext.getModulesConfigurator().getModuleEditor(myModule);
    if (moduleEditor != null) {
      for (OrderEntry entry : moduleEditor.getOrderEntries()) {
        if (entry instanceof ModuleOrderEntry) {
          ModuleOrderEntry moduleOrderEntry = (ModuleOrderEntry)entry;
          final Module module = moduleOrderEntry.getModule();
          if (module != null) {
            usages.add(new UsageInModuleClasspath(myContext, this, new ModuleProjectStructureElement(myContext, module), moduleOrderEntry.getScope()));
          }
        }
        else if (entry instanceof LibraryOrderEntry) {
          LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry)entry;
          final Library library = libraryOrderEntry.getLibrary();
          if (library != null) {
            usages.add(new UsageInModuleClasspath(myContext, this, new LibraryProjectStructureElement(myContext, library),
                                                  libraryOrderEntry.getScope()));
          }
        }
        else if (entry instanceof JdkOrderEntry) {
          final Sdk jdk = ((JdkOrderEntry)entry).getJdk();
          if (jdk != null) {
            usages.add(new UsageInModuleClasspath(myContext, this, new SdkProjectStructureElement(myContext, jdk), null));
          }
        }
      }
    }
    return usages;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof ModuleProjectStructureElement)) return false;

    return myModule.equals(((ModuleProjectStructureElement)o).myModule);

  }

  @Override
  public int hashCode() {
    return myModule.hashCode();
  }

  @Override
  public String getPresentableName() {
    return myModule.getName();
  }

  @Override
  public @Nls(capitalization = Nls.Capitalization.Sentence) String getTypeName() {
    return CommonBundle.message("label.module");
  }

  @Override
  public String getId() {
    return "module:" + myModule.getName();
  }
}

@@ -2046,221 +2046,111 @@
     
-ModuleEditor moduleEditor = myContext.getModulesConfigurator().getModuleEditor(myModule);%0A    if (moduleEditor == null) return; //already disposed%0A    final ModuleRootModel rootModel = moduleEditor.getRootModel();
+final ModuleRootModel rootModel = getRootModel();%0A    if (rootModel == null) return; //already disposed
 %0A   
@@ -3048,24 +3048,284 @@
 %0A    %7D%0A  %7D%0A%0A
+  private ModuleRootModel getRootModel() %7B%0A    ModuleEditor moduleEditor = myContext.getModulesConfigurator().getModuleEditor(myModule);%0A    if (moduleEditor == null) return ModuleRootManager.getInstance(myModule);%0A    return moduleEditor.getRootModel();%0A  %7D%0A%0A
   private Pl
@@ -3873,112 +3873,63 @@
 dule
-Editor moduleEditor = myContext.getModulesConfigurator().getModuleEditor(myModule);%0A    if (moduleEditor
+RootModel rootModel = getRootModel();%0A    if (rootModel
  != 
@@ -3966,28 +3966,25 @@
 entry : 
-moduleEditor
+rootModel
 .getOrde

use default way to get ModuleRootModel in ModuleProjectStructureElement if no ModuleEditor is available (IDEA-257774)