package de.dhbwstuttgart.syntaxtree.statement;

import de.dhbwstuttgart.exceptions.TypeinferenceException;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
import de.dhbwstuttgart.typeinference.constraints.Constraint;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.constraints.ConstraintsFactory;
import de.dhbwstuttgart.typeinference.assumptions.MethodAssumption;
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
import org.antlr.v4.runtime.Token;

import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;

import java.util.HashSet;
import java.util.Set;


public class MethodCall extends Statement
{
    private final String name;
    private Receiver receiver;
    private ArgumentList arglist;

    public MethodCall(Receiver receiver, String methodName, ArgumentList argumentList, Token offset){
		super(TypePlaceholder.fresh(offset),offset);
		this.arglist = argumentList;
        this.name = methodName;
        this.receiver = receiver;
	}
    
    
    // Sebastian 
    public Receiver get_Receiver() {
    	return receiver; 
    }
    
    // Sebastian
    public ArgumentList get_ArgList() {
    	return arglist;
    }
    
    // Sebastian 
    public String get_Name() {
    	return name; 
    }
    
    

    @Override
    public ConstraintSet getConstraints(TypeInferenceBlockInformation info) {
        ConstraintSet ret = receiver.getConstraints(info);
        ret.addAll(receiver.getConstraints(info));
        for(int i = 0;i<arglist.getArguments().size();i++){
            ret.addAll(arglist.getArguments().get(i).getConstraints(info));
        }
        //Overloading:
        Set<Constraint> methodConstraints = new HashSet<>();
        for(MethodAssumption m : info.getMethods(name, arglist)){
            Constraint methodConstraint = new Constraint();
            methodConstraint.add(ConstraintsFactory.createPair(receiver.getType(), m.getReceiverType(), PairOperator.SMALLERDOT, info));
            methodConstraint.add(ConstraintsFactory.createPair(m.getReturnType(), this.getType(), PairOperator.SMALLERDOT, info));
            for(int i = 0;i<arglist.getArguments().size();i++){
                methodConstraint.add(ConstraintsFactory.createPair(m.getArgTypes().get(i),
                        arglist.getArguments().get(i).getType(), PairOperator.SMALLERDOT, info));
            }
            methodConstraints.add(methodConstraint);
        }
        if(methodConstraints.size()<1){
            throw new TypeinferenceException("Methode "+name+" ist nicht vorhanden!",getOffset());
        }
        ret.addOderConstraint(methodConstraints);
        return ret;
    }
}
