package jetbrains.mps.ide.actions;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import jetbrains.mps.project.Project;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.openapi.editor.EditorContext;
import jetbrains.mps.baseLanguage.closures.runtime.Wrappers;
import org.jetbrains.mps.openapi.model.SNodeReference;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import java.util.List;
import jetbrains.mps.smodel.behaviour.BHReflection;
import jetbrains.mps.core.aspects.behaviour.SMethodIdV2;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import jetbrains.mps.ide.project.ProjectHelper;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.smodel.ModelDependencyUpdate;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations;
import org.jetbrains.mps.openapi.language.SConcept;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import org.jetbrains.mps.openapi.language.SInterfaceConcept;
import org.jetbrains.mps.openapi.language.SContainmentLink;

@GeneratedClass(node = "r:00000000-0000-4000-0000-011c895904a4(jetbrains.mps.ide.actions)/1818770337282866379", model = "r:00000000-0000-4000-0000-011c895904a4(jetbrains.mps.ide.actions)")
public class OverrideConceptMethodsAction {
  private Project myProject;
  private SNode mySelectedNode;
  private EditorContext myEditorContext;
  private boolean myIsOverride;

  public OverrideConceptMethodsAction(Project project, SNode selectedNode, EditorContext editorContext, boolean isOverride) {
    myProject = project;
    mySelectedNode = selectedNode;
    myEditorContext = editorContext;
    myIsOverride = isOverride;
  }

  public void run() {
    final Wrappers._T<SNode> contextClass = new Wrappers._T<SNode>();
    final Wrappers._T<SNode> contextMethod = new Wrappers._T<SNode>();
    final Wrappers._T<SNodeReference[]> methods = new Wrappers._T<SNodeReference[]>();

    myProject.getModelAccess().runReadAction(() -> {
      contextClass.value = SNodeOperations.getNodeAncestor(mySelectedNode, CONCEPTS.ConceptBehavior$2, true, false);
      contextMethod.value = SNodeOperations.getNodeAncestor(mySelectedNode, CONCEPTS.ConceptMethodDeclaration$N0, true, false);
      List<SNode> methodsToOverride = ((List<SNode>) BHReflection.invoke0(contextClass.value, CONCEPTS.IMemberContainer$yM, SMethodIdV2.create("getMethodsToImplement", 5418393554803775106L, 0x5745e3015c8914d3L)));
      if (myIsOverride) {
        ListSequence.fromList(methodsToOverride).addSequence(ListSequence.fromList(((List<SNode>) BHReflection.invoke0(contextClass.value, CONCEPTS.IMemberContainer$yM, SMethodIdV2.create("getMethodsToOverride", 5418393554803767537L, 0x5745e3015c8914d3L)))));
      }
      methods.value = OverrideConceptMethodsDialog.toNodePointers(OverrideConceptMethodsDialog.sortMethods(contextClass.value, methodsToOverride));
    });

    final OverrideConceptMethodsDialog dialog = new OverrideConceptMethodsDialog(methods.value, ProjectHelper.toIdeaProject(myProject)) {
      @Override
      protected boolean showInsertOverride() {
        return myIsOverride;
      }
    };
    dialog.setTitle((myIsOverride ? "Select Behavior Methods to Override/Implement" : "Select Behavior Methods to Implement"));
    dialog.show();

    if (dialog.isOK()) {
      final Iterable<SNodeReference> selectedElements = (Iterable<SNodeReference>) dialog.getSelectedElements();

      myProject.getModelAccess().executeCommandInEDT(() -> {
        List<SNode> selection = Sequence.fromIterable(selectedElements).select((it) -> SNodeOperations.cast(it.resolve(myProject.getRepository()), CONCEPTS.BaseMethodDeclaration$kD)).toList();
        OverrideConceptMethodsHelper helper = new OverrideConceptMethodsHelper(myProject, contextClass.value, contextMethod.value, dialog.isRemoveAttributes(), dialog.isAddReturn());
        List<SNode> insertedMethods = helper.insertMethods(selection);
        if (insertedMethods.isEmpty()) {
          return;
        }

        ModelDependencyUpdate mdu = new ModelDependencyUpdate(SNodeOperations.getModel(contextClass.value), contextClass.value);
        // XXX MoveRefactoringUtils.fixImports didn't bother to update used languages, is it correct?
        mdu.updateImportedModels(myProject.getRepository());
        mdu.updateModuleDependencies(myProject.getRepository());

        SNode firstMethod = ListSequence.fromList(insertedMethods).first();
        SNode nodeToSelect;
        if (ListSequence.fromList(SLinkOperations.getChildren(SLinkOperations.getTarget(firstMethod, LINKS.body$5xQk), LINKS.statement$53DE)).isNotEmpty()) {
          nodeToSelect = ListSequence.fromList(SLinkOperations.getChildren(SLinkOperations.getTarget(firstMethod, LINKS.body$5xQk), LINKS.statement$53DE)).first();
        } else {
          nodeToSelect = firstMethod;
        }
        myEditorContext.flushEvents();
        myEditorContext.getSelectionManager().setSelection(nodeToSelect);
      });
    }
  }

  private static final class CONCEPTS {
    /*package*/ static final SConcept ConceptBehavior$2 = MetaAdapterFactory.getConcept(0xaf65afd8f0dd4942L, 0x87d963a55f2a9db1L, 0x11d43447b1aL, "jetbrains.mps.lang.behavior.structure.ConceptBehavior");
    /*package*/ static final SConcept ConceptMethodDeclaration$N0 = MetaAdapterFactory.getConcept(0xaf65afd8f0dd4942L, 0x87d963a55f2a9db1L, 0x11d4348057eL, "jetbrains.mps.lang.behavior.structure.ConceptMethodDeclaration");
    /*package*/ static final SInterfaceConcept IMemberContainer$yM = MetaAdapterFactory.getInterfaceConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x11638b31955L, "jetbrains.mps.baseLanguage.structure.IMemberContainer");
    /*package*/ static final SConcept BaseMethodDeclaration$kD = MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8cc56b1fcL, "jetbrains.mps.baseLanguage.structure.BaseMethodDeclaration");
  }

  private static final class LINKS {
    /*package*/ static final SContainmentLink body$5xQk = MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8cc56b1fcL, 0xf8cc56b1ffL, "body");
    /*package*/ static final SContainmentLink statement$53DE = MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8cc56b200L, 0xf8cc6bf961L, "statement");
  }
}
