package jetbrains.mps.baseLanguage.methodReferences.intentions;

/*Generated by MPS */

import jetbrains.mps.intentions.AbstractIntentionDescriptor;
import jetbrains.mps.openapi.intentions.IntentionFactory;
import java.util.Collection;
import jetbrains.mps.openapi.intentions.IntentionExecutable;
import jetbrains.mps.openapi.intentions.Kind;
import jetbrains.mps.smodel.SNodePointer;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.openapi.editor.EditorContext;
import java.util.Collections;
import jetbrains.mps.intentions.AbstractIntentionExecutable;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import jetbrains.mps.typechecking.TypecheckingFacade;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SConceptOperations;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import jetbrains.mps.baseLanguage.behavior.IFixableMethodReference__BehaviorDescriptor;
import jetbrains.mps.openapi.intentions.IntentionDescriptor;
import jetbrains.mps.smodel.builder.SNodeBuilder;
import org.jetbrains.mps.openapi.language.SConcept;
import org.jetbrains.mps.openapi.language.SContainmentLink;
import org.jetbrains.mps.openapi.language.SReferenceLink;

public final class ConvertToMethodReference_Intention extends AbstractIntentionDescriptor implements IntentionFactory {
  private Collection<IntentionExecutable> myCachedExecutable;

  public ConvertToMethodReference_Intention() {
    super(Kind.NORMAL, true, new SNodePointer("r:83aba8b0-caeb-440c-9f54-988b97ce933f(jetbrains.mps.baseLanguage.methodReferences.intentions)", "2055055257255713495"));
  }

  @Override
  public String getPresentation() {
    return "ConvertToMethodReference";
  }

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

  public Collection<IntentionExecutable> instances(final SNode node, final EditorContext context) {
    if (myCachedExecutable == null) {
      myCachedExecutable = Collections.<IntentionExecutable>singletonList(new IntentionImplementation());
    }
    return myCachedExecutable;
  }
  /*package*/ final class IntentionImplementation extends AbstractIntentionExecutable {
    public IntentionImplementation() {
    }

    @Override
    public String getDescription(final SNode node, final EditorContext editorContext) {
      return "Convert to Method Reference";
    }

    @Override
    public void execute(final SNode node, final EditorContext editorContext) {
      SNode expr = ClosureToMethodRefHelper.getSingleExpression(node);
      SNode methodCall = ClosureToMethodRefHelper.getSingleMethodCall(expr);
      SNode target = (SNodeOperations.isInstanceOf(expr, CONCEPTS.DotExpression$yW) ? SNodeOperations.copyNode(SLinkOperations.getTarget(SNodeOperations.cast(expr, CONCEPTS.DotExpression$yW), LINKS.operand$w6IR)) : null);

      // One special case : static call of instance method
      if (ListSequence.fromList(SLinkOperations.getChildren(methodCall, LINKS.actualArgument$pzdx)).count() + 1 == ListSequence.fromList(SLinkOperations.getChildren(node, LINKS.parameter$b4Y3)).count() && SNodeOperations.isInstanceOf(methodCall, CONCEPTS.InstanceMethodCallOperation$uu)) {
        // No need to coerce here as the method ref will coerce later on
        target = createMethodReferenceTypeTargetExpression_m6i3ny_a0b0f0a(SNodeOperations.as(TypecheckingFacade.getFromContext().getTypeOf(target), CONCEPTS.Type$bu));
      } else if (SNodeOperations.isInstanceOf(methodCall, CONCEPTS.SuperMethodCall$pW)) {
        target = SConceptOperations.createNewNode(MetaAdapterFactory.getConcept(0xacfc188dd5d64598L, 0xb3706f4a983f05b2L, 0x2f900a9ba38b01a9L, "jetbrains.mps.baseLanguage.methodReferences.structure.MethodReferenceSuperExpression"));
      }

      if ((target == null)) {
        SNode classifierType = IFixableMethodReference__BehaviorDescriptor.getInstanceType_id6WzWPTX2vuB.invoke(methodCall);
        if ((classifierType == null)) {
          // If no instance type -> get raw classifier
          classifierType = createClassifierType_m6i3ny_a0b0b0h0a(SNodeOperations.getNodeAncestor(SLinkOperations.getTarget(methodCall, LINKS.baseMethodDeclaration$pyYw), CONCEPTS.Classifier$Ix, false, false));
        }
        target = createMethodReferenceTypeTargetExpression_m6i3ny_a0c0h0a(classifierType);
      }

      SNode newMethodRef = SNodeOperations.replaceWithNewChild(node, CONCEPTS.MethodReference$G8);
      SLinkOperations.setTarget(newMethodRef, LINKS.target$Woec, target);
      SLinkOperations.setTarget(newMethodRef, LINKS.method$8Sfb, SLinkOperations.getTarget(methodCall, LINKS.baseMethodDeclaration$pyYw));
      ListSequence.fromList(SLinkOperations.getChildren(newMethodRef, LINKS.typeParameters$5Tel)).addSequence(ListSequence.fromList(SLinkOperations.getChildren(methodCall, LINKS.typeArgument$jaIN)));
    }

    @Override
    public boolean isApplicable(final SNode node, final EditorContext editorContext) {
      if (!(isApplicableToNode(node, editorContext))) {
        return false;
      }
      return true;
    }

    private boolean isApplicableToNode(final SNode node, final EditorContext editorContext) {
      return ClosureToMethodRefHelper.canBeConverted(node);
    }


    @Override
    public IntentionDescriptor getDescriptor() {
      return ConvertToMethodReference_Intention.this;
    }

  }
  private static SNode createMethodReferenceTypeTargetExpression_m6i3ny_a0b0f0a(SNode p0) {
    SNodeBuilder n0 = new SNodeBuilder().init(CONCEPTS.MethodReferenceTypeTargetExpression$a3);
    n0.forChild(LINKS.type$z9_f).initNode(p0, CONCEPTS.Type$bu, true);
    return n0.getResult();
  }
  private static SNode createClassifierType_m6i3ny_a0b0b0h0a(SNode p0) {
    SNodeBuilder n0 = new SNodeBuilder().init(CONCEPTS.ClassifierType$bL);
    n0.setReferenceTarget(LINKS.classifier$cxMr, p0);
    return n0.getResult();
  }
  private static SNode createMethodReferenceTypeTargetExpression_m6i3ny_a0c0h0a(SNode p0) {
    SNodeBuilder n0 = new SNodeBuilder().init(CONCEPTS.MethodReferenceTypeTargetExpression$a3);
    n0.forChild(LINKS.type$z9_f).initNode(p0, CONCEPTS.Type$bu, true);
    return n0.getResult();
  }

  private static final class CONCEPTS {
    /*package*/ static final SConcept DotExpression$yW = MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x116b46a08c4L, "jetbrains.mps.baseLanguage.structure.DotExpression");
    /*package*/ static final SConcept Type$bu = MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8c37f506dL, "jetbrains.mps.baseLanguage.structure.Type");
    /*package*/ static final SConcept InstanceMethodCallOperation$uu = MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x118154a6332L, "jetbrains.mps.baseLanguage.structure.InstanceMethodCallOperation");
    /*package*/ static final SConcept SuperMethodCall$pW = MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf9d78b55aaL, "jetbrains.mps.baseLanguage.structure.SuperMethodCall");
    /*package*/ static final SConcept Classifier$Ix = MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101d9d3ca30L, "jetbrains.mps.baseLanguage.structure.Classifier");
    /*package*/ static final SConcept MethodReference$G8 = MetaAdapterFactory.getConcept(0xacfc188dd5d64598L, 0xb3706f4a983f05b2L, 0x34d254ec4f4136fL, "jetbrains.mps.baseLanguage.methodReferences.structure.MethodReference");
    /*package*/ static final SConcept MethodReferenceTypeTargetExpression$a3 = MetaAdapterFactory.getConcept(0xacfc188dd5d64598L, 0xb3706f4a983f05b2L, 0x6dd7c320c6fc97cdL, "jetbrains.mps.baseLanguage.methodReferences.structure.MethodReferenceTypeTargetExpression");
    /*package*/ static final SConcept ClassifierType$bL = MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101de48bf9eL, "jetbrains.mps.baseLanguage.structure.ClassifierType");
  }

  private static final class LINKS {
    /*package*/ static final SContainmentLink operand$w6IR = MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x116b46a08c4L, 0x116b46a4416L, "operand");
    /*package*/ static final SContainmentLink parameter$b4Y3 = MetaAdapterFactory.getContainmentLink(0xfd3920347849419dL, 0x907112563d152375L, 0x1174bed3125L, 0x1174bf02c34L, "parameter");
    /*package*/ static final SContainmentLink actualArgument$pzdx = MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x11857355952L, 0xf8c78301aeL, "actualArgument");
    /*package*/ static final SReferenceLink baseMethodDeclaration$pyYw = MetaAdapterFactory.getReferenceLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x11857355952L, 0xf8c78301adL, "baseMethodDeclaration");
    /*package*/ static final SContainmentLink target$Woec = MetaAdapterFactory.getContainmentLink(0xacfc188dd5d64598L, 0xb3706f4a983f05b2L, 0x30ab9441ca549e7bL, 0xd5ab3252daa1c07L, "target");
    /*package*/ static final SReferenceLink method$8Sfb = MetaAdapterFactory.getReferenceLink(0xacfc188dd5d64598L, 0xb3706f4a983f05b2L, 0x30ab9441ca549e7bL, 0x34d254ec4f413c1L, "method");
    /*package*/ static final SContainmentLink typeParameters$5Tel = MetaAdapterFactory.getContainmentLink(0xacfc188dd5d64598L, 0xb3706f4a983f05b2L, 0x30ab9441ca549e7bL, 0x2120da84c4733f2eL, "typeParameters");
    /*package*/ static final SContainmentLink typeArgument$jaIN = MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x11857355952L, 0x4500f31eb02a7788L, "typeArgument");
    /*package*/ static final SContainmentLink type$z9_f = MetaAdapterFactory.getContainmentLink(0xacfc188dd5d64598L, 0xb3706f4a983f05b2L, 0x6dd7c320c6fc97cdL, 0x6dd7c320c6fca4b8L, "type");
    /*package*/ static final SReferenceLink classifier$cxMr = MetaAdapterFactory.getReferenceLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101de48bf9eL, 0x101de490babL, "classifier");
  }
}
