package jetbrains.mps.lang.structure.migration;

/*Generated by MPS */

import jetbrains.mps.lang.migration.runtime.base.MigrationScriptBase;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.module.SModule;
import org.jetbrains.mps.openapi.module.SearchScope;
import jetbrains.mps.lang.smodel.query.runtime.CommandUtil;
import jetbrains.mps.project.EditableFilteringScope;
import jetbrains.mps.lang.smodel.query.runtime.QueryExecutionContext;
import java.util.Collection;
import jetbrains.mps.internal.collections.runtime.CollectionSequence;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.IAttributeDescriptor;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPropertyOperations;
import java.util.regex.Matcher;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import jetbrains.mps.lang.structure.behavior.AbstractConceptDeclaration__BehaviorDescriptor;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations;
import jetbrains.mps.lang.migration.runtime.base.MigrationScriptReference;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import java.util.regex.Pattern;
import java.util.Objects;
import jetbrains.mps.smodel.builder.SNodeBuilder;
import org.jetbrains.mps.openapi.language.SConcept;
import org.jetbrains.mps.openapi.language.SProperty;
import org.jetbrains.mps.openapi.language.SContainmentLink;
import org.jetbrains.mps.openapi.language.SReferenceLink;

public class IntroduceSmartRefAttribute extends MigrationScriptBase {
  private final String description = "Annotate 'smart reference' concepts";
  public String getCaption() {
    return description;
  }
  @Override
  public boolean isRerunnable() {
    return true;
  }
  public SNode execute(final SModule m) {
    doExecute(m);
    return null;
  }
  public void doExecute(final SModule m) {
    {
      SearchScope scope_nopsft_a0e = CommandUtil.createScope(m);
      final SearchScope scope_nopsft_a0e_0 = new EditableFilteringScope(scope_nopsft_a0e);
      QueryExecutionContext context = () -> scope_nopsft_a0e_0;
      Collection<SNode> conceptNodes = CommandUtil.instances(CommandUtil.selectScope(null, context), CONCEPTS.ConceptDeclaration$gH, false);

      for (SNode conceptNode : CollectionSequence.fromCollection(conceptNodes)) {

        if ((new IAttributeDescriptor.NodeAttribute(CONCEPTS.SmartReferenceAttribute$B3).get(conceptNode) != null)) {
          continue;
        }
        if (SPropertyOperations.getBoolean(conceptNode, PROPS.abstract$ibpT)) {
          continue;
        }
        if (isEmptyString(SPropertyOperations.getString(conceptNode, PROPS.conceptAlias$OL_L))) {
          continue;
        }

        Matcher smartAliasMatcher = getSmartAliasMatcher(SPropertyOperations.getString(conceptNode, PROPS.conceptAlias$OL_L));

        if (smartAliasMatcher.matches()) {
          final String role = smartAliasMatcher.group(2);
          SNode characteristicLink = ListSequence.fromList(AbstractConceptDeclaration__BehaviorDescriptor.getReferenceLinkDeclarations_idhEwILL0.invoke(conceptNode)).findFirst((it) -> hasRole(it, role));

          if ((characteristicLink != null)) {
            String prefix = smartAliasMatcher.group(1);
            String suffix = smartAliasMatcher.group(3);

            SPropertyOperations.remove(conceptNode, PROPS.conceptAlias$OL_L);

            new IAttributeDescriptor.NodeAttribute(CONCEPTS.SmartReferenceAttribute$B3).set(conceptNode, createSmartReferenceAttribute_nopsft_a0f0d0h0c0a0g(characteristicLink));
            if ((prefix != null && prefix.length() > 0) || (suffix != null && suffix.length() > 0)) {
              SLinkOperations.setTarget(new IAttributeDescriptor.NodeAttribute(CONCEPTS.SmartReferenceAttribute$B3).get(conceptNode), LINKS.refPresentationTemplate$di5B, createRefPresentationTemplate_nopsft_a0a0g0d0h0c0a0g(prefix, suffix));
            }
          }
        }
      }
    }
  }
  public MigrationScriptReference getReference() {
    return new MigrationScriptReference(MetaAdapterFactory.getLanguage(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, "jetbrains.mps.lang.structure"), 4);
  }


  private static final Pattern SMART_ALIAS_PATTERN = Pattern.compile("(.*)<\\{(.+)\\}>(.*)");

  private Matcher getSmartAliasMatcher(String alias) {
    return SMART_ALIAS_PATTERN.matcher(alias);
  }

  private boolean hasRole(SNode link, String role) {
    if (Objects.equals(SPropertyOperations.getString(link, PROPS.role$Nsjf), role)) {
      return true;
    }
    if ((SLinkOperations.getTarget(link, LINKS.specializedLink$7ZCN) != null)) {
      return hasRole(SLinkOperations.getTarget(link, LINKS.specializedLink$7ZCN), role);
    }
    return false;
  }
  private static SNode createSmartReferenceAttribute_nopsft_a0f0d0h0c0a0g(SNode p0) {
    SNodeBuilder n0 = new SNodeBuilder().init(CONCEPTS.SmartReferenceAttribute$B3);
    n0.setReferenceTarget(LINKS.charactersticReference$41pR, p0);
    return n0.getResult();
  }
  private static SNode createRefPresentationTemplate_nopsft_a0a0g0d0h0c0a0g(String p0, String p1) {
    SNodeBuilder n0 = new SNodeBuilder().init(CONCEPTS.RefPresentationTemplate$UU);
    n0.setProperty(PROPS.prefix$cFJ6, p0);
    n0.setProperty(PROPS.suffix$cLnu, p1);
    return n0.getResult();
  }
  private static boolean isEmptyString(String str) {
    return str == null || str.isEmpty();
  }

  private static final class CONCEPTS {
    /*package*/ static final SConcept ConceptDeclaration$gH = MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, "jetbrains.mps.lang.structure.structure.ConceptDeclaration");
    /*package*/ static final SConcept SmartReferenceAttribute$B3 = MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x7ab7b29c4d6297e8L, "jetbrains.mps.lang.structure.structure.SmartReferenceAttribute");
    /*package*/ static final SConcept RefPresentationTemplate$UU = MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x7ab7b29c4d66855eL, "jetbrains.mps.lang.structure.structure.RefPresentationTemplate");
  }

  private static final class PROPS {
    /*package*/ static final SProperty abstract$ibpT = MetaAdapterFactory.getProperty(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103553c5ffL, 0x403a32c5772c7ec2L, "abstract");
    /*package*/ static final SProperty conceptAlias$OL_L = MetaAdapterFactory.getProperty(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103553c5ffL, 0x46ab0ad5826c74caL, "conceptAlias");
    /*package*/ static final SProperty role$Nsjf = MetaAdapterFactory.getProperty(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979bd086aL, 0xf98052f333L, "role");
    /*package*/ static final SProperty prefix$cFJ6 = MetaAdapterFactory.getProperty(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x7ab7b29c4d66855eL, 0x3bc83bac475c4b59L, "prefix");
    /*package*/ static final SProperty suffix$cLnu = MetaAdapterFactory.getProperty(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x7ab7b29c4d66855eL, 0x3bc83bac475c4b5cL, "suffix");
  }

  private static final class LINKS {
    /*package*/ static final SContainmentLink refPresentationTemplate$di5B = MetaAdapterFactory.getContainmentLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x7ab7b29c4d6297e8L, 0x7ab7b29c4d66ac37L, "refPresentationTemplate");
    /*package*/ static final SReferenceLink specializedLink$7ZCN = MetaAdapterFactory.getReferenceLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979bd086aL, 0xf98051c244L, "specializedLink");
    /*package*/ static final SReferenceLink charactersticReference$41pR = MetaAdapterFactory.getReferenceLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x7ab7b29c4d6297e8L, 0x7ab7b29c4d6297edL, "charactersticReference");
  }
}
