package de.dhbwstuttgart.syntaxtree;

import de.dhbwstuttgart.core.IItemWithOffset;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.typecheck.JavaClassName;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation;
import org.antlr.v4.runtime.Token;

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

/**
 * Stellt jede Art von Klasse dar. Auch abstrakte Klassen und Interfaces
 */
public class ClassOrInterface extends GTVDeclarationContext implements IItemWithOffset, Generic{
  protected int modifiers;
  protected JavaClassName name;
  private List<Field> fields = new ArrayList<>();
  private List<Method> methods = new ArrayList<>();
  private GenericDeclarationList genericClassParameters;
  private Token offset;
  private RefTypeOrTPHOrWildcardOrGeneric superClass;
  protected boolean isInterface;
  private List<? extends RefTypeOrTPHOrWildcardOrGeneric> implementedInterfaces;
  
  public ClassOrInterface(int modifiers, JavaClassName name, List<Field> fielddecl, List<Method> methods, GenericDeclarationList genericClassParameters,
                          RefTypeOrTPHOrWildcardOrGeneric superClass, Boolean isInterface, List<? extends RefTypeOrTPHOrWildcardOrGeneric> implementedInterfaces, Token offset){
    super(offset);
      this.modifiers = modifiers;
    if(name != null){
      this.name = name;
    }
    if(fielddecl != null){
      this.fields = fielddecl;
    }
    if(genericClassParameters != null){
      this.genericClassParameters = genericClassParameters;
    }
    this.offset = offset;
    if(superClass != null){
      this.superClass = superClass;
    }
    this.isInterface = isInterface;
    if(implementedInterfaces != null){
      this.implementedInterfaces = implementedInterfaces;
    }
    this.methods = methods;
  }
  
  // Gets class name
  public JavaClassName getClassName(){
    return this.name;
  }
  
  public GenericDeclarationList getGenericDeclarationList() {
	  return this.genericClassParameters; 
  }
  
  // Get modifiers
  public int getModifiers(){
    return this.modifiers;
  }

  public List<Field> getFieldDecl(){
    return this.fields;
  }
  public List<Method> getMethods(){
    return this.methods;
  }

  public ConstraintSet getConstraints(TypeInferenceInformation info) {
    ConstraintSet ret = new ConstraintSet();
    for(Method m : this.getMethods()){
      ret.addAll(m.getConstraints(info, this));
    }
    return ret;
  }

  public RefType getType() {
    return new RefType(this.getClassName(), this.getOffset());
  }

  public RefTypeOrTPHOrWildcardOrGeneric getSuperClass() {
    return superClass;
  }

  public Iterable<? extends GenericTypeVar> getGenerics() {
    return this.genericClassParameters;
  }
}
