package de.dhbwstuttgart.target.generate;

import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.target.tree.type.TargetGenericType;
import de.dhbwstuttgart.target.tree.type.TargetType;
import de.dhbwstuttgart.typeinference.result.ResultSet;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class OverlayGenerics implements IGenerics {
    private final IGenerics wrapped;
    private final ASTToTargetAST converter;
    private final Map<TypePlaceholder, TargetType> overlay;

    public OverlayGenerics(IGenerics wrapped, ASTToTargetAST converter) {
        this.wrapped = wrapped;
        this.converter = converter;
        this.overlay = new HashMap<>();
    }

    public void addOverlay(TypePlaceholder tph, TargetType type) {
        this.overlay.put(tph, type);
    }

    @Override
    public Set<GenerateGenerics.Pair> generics(ClassOrInterface classOrInterface) {
        return wrapped.generics(classOrInterface);
    }

    @Override
    public Set<GenerateGenerics.Pair> generics(ClassOrInterface owner, Method method) {
        return wrapped.generics(owner, method);
    }

    @Override
    public RefTypeOrTPHOrWildcardOrGeneric getType(RefTypeOrTPHOrWildcardOrGeneric type) {
        return wrapped.getType(type);
    }

    @Override
    public TypePlaceholder getEqualType(TypePlaceholder tph) {
        return wrapped.getEqualType(tph);
    }

    @Override
    public TargetType getTargetType(RefTypeOrTPHOrWildcardOrGeneric in) {
        if (in instanceof TypePlaceholder tph) {
            var overlay = this.overlay.get(tph);
            if (overlay != null) return overlay;
            var type = getType(tph);
            if (type == null) return new TargetGenericType(tph.getName());
            return wrapped.getTargetType(type);
        }
        return ASTToTargetAST.convert(in, this, converter.compiler);
    }

    @Override
    public ResultSet getResultSet() {
        return wrapped.getResultSet();
    }
}
