package jetbrains.mps.kotlin.typesystem;

/*Generated by MPS */

import jetbrains.mps.kotlin.api.members.SuperTypesVisitor;
import java.util.Set;
import jetbrains.mps.kotlin.api.types.identifiers.TypeKey;
import java.util.HashSet;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.kotlin.behavior.IInheritExplicitly__BehaviorDescriptor;
import jetbrains.mps.kotlin.behavior.IType__BehaviorDescriptor;
import java.util.Objects;

/**
 * Check that a type is not present in its supertypes. Only check the original type, does not ensure there is not
 * circular dependencies in parent types.
 */
public class CircularDependenciesScanner implements SuperTypesVisitor {
  public boolean isCircular = false;
  public final Set<TypeKey> superTypes = new HashSet<>();
  private final TypeKey typeKeyToCheck;

  public CircularDependenciesScanner(SNode type) {
    typeKeyToCheck = IInheritExplicitly__BehaviorDescriptor.getSelfTypeKey_id9DkAreHC7z.invoke(type);
    IInheritExplicitly__BehaviorDescriptor.visitSuperTypes_id1WN66f3AYxj.invoke(type, this);
  }

  @Override
  public boolean enterType(SNode type) {
    if (!(isCircular)) {
      TypeKey key = IType__BehaviorDescriptor.typeKey_idJmO2PmZtH5.invoke(type);

      // Original type found in supertypes: circular! (not explored initially)
      if (Objects.equals(key, typeKeyToCheck)) {
        isCircular = true;
      } else if (superTypes.add(key)) {
        return true;
      }
    }

    return false;
  }

  @Override
  public void exitType(SNode clazz) {
  }

  public boolean hasCircularReference() {
    return isCircular;
  }
}
