package de.dhbwstuttgart.typeinference.assumptions;

import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.statement.ArgumentList;
import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.typeinference.constraints.Constraint;
import de.dhbwstuttgart.typeinference.constraints.Pair;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/*
Anmerkung:
Zwei Möglichkeiten, die TypeAssumptions zu speichern.
1. Die Klassen mit bedeutenden Informationen generieren diese und übergeben sie dann dieser Klasse.
2. Oder es werden nur Referenzen auf den SyntaxTree übergeben, welche diese Klasse hier dann verarbeitet.

Bei Änderungen des SyntaxTrees müssen beide Methoden angepasst werden.
Zweiteres hat den Vorteil, dass bei der Entwicklung leichter Dinge hinzugefügt werden können.
Die ganze Logik steckt in dieser Klasse.
 */
public class TypeInferenceInformation {
    private Collection<ClassOrInterface> classes;

    public TypeInferenceInformation(Collection<ClassOrInterface> availableClasses){
        classes = availableClasses;
    }

    public RefTypeOrTPHOrWildcardOrGeneric checkGTV(RefTypeOrTPHOrWildcardOrGeneric type){
        if(type instanceof GenericRefType){
            return TypePlaceholder.fresh(new NullToken());
        }else{
            return type;
        }
    }

    public List<FieldAssumption> getFields(String name){
        List<FieldAssumption> ret = new ArrayList<>();
        for(ClassOrInterface cl : classes){
            for(Field m : cl.getFieldDecl()){
                if(m.getName().equals(name)){

                    ret.add(new FieldAssumption(name, cl, checkGTV(m.getType()), new TypeScopeContainer(cl, m)));
                }
            }
        }
        return ret;
    }

    public Collection<ClassOrInterface> getAvailableClasses() {
        return classes;
    }

}
