package de.dhbwstuttgart.strucTypes4.algo;

import de.dhbwstuttgart.strucTypes4.syntaxtree.*;
import de.dhbwstuttgart.strucTypes4.syntaxtree.Class;
import de.dhbwstuttgart.strucTypes4.typeVars.TypeVarAbstract;
import de.dhbwstuttgart.strucTypes4.typeVars.TypeVarStore;
import de.dhbwstuttgart.strucTypes4.typeVars.TypeVarType;

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

/**
 * Created by sebastian on 09.04.17.
 */
public class TypeExpr {

    public static List<ConstraintAbstract> typeExpr(ExpressionAbstract exp, Map<String, TypeVarAbstract> ass , TypeVarAbstract rec , TypeVarAbstract returnType , TypeVarStore typeVarStore) {

        if (exp.getClass().equals(ExprVar.class )) {
            ExprVar exprVar = (ExprVar) exp;
            return exprVar.typeExpr(ass,typeVarStore);
        }
        else if (exp.getClass().equals(ExprMCall.class)) {
            ExprMCall exprMCall = (ExprMCall) exp;
            return exprMCall.typeExpr(ass, rec ,returnType, typeVarStore);
        }
        else if ( exp.getClass().equals(ExprField.class)) {
            ExprField exprField  = (ExprField) exp;
            List<ConstraintAbstract> constraints = new ArrayList<>();
            //constraints.add(new ConstraintField(rec,exprField.getNameField(), returnType));
            return constraints;

        }
        else if (exp.getClass().equals(Expression.class)) {
            Expression expression = (Expression) exp;
            List<ConstraintAbstract> constraints = new ArrayList<>();
            // Reihenfolge wichtig wg Rekursiven aufrufen und TypVariablen !!!
            constraints.addAll(typeExpr(expression.getReceiver(), ass, null ,null  , typeVarStore));

            TypeVarAbstract tvReceiver = typeVarStore.storeTPH(expression.getReceiver().getTypePlaceHolder());
            TypeVarAbstract tvThis = typeVarStore.storeTPH(expression.getTypePlaceHolder());
            constraints.addAll(typeExpr(expression.getCaller(),ass, tvReceiver , tvThis , typeVarStore));
            return constraints;
        }
        else if (exp.getClass().equals(ExprNew.class) ) {

            ExprNew exprNew = (ExprNew) exp;
            List<ConstraintAbstract> constraints = new ArrayList<>();


            String klassenname = exprNew.getClassType();
            String assumptionKey = "$" + klassenname;

            TypeVarAbstract tv = ass.get(assumptionKey);
            Class typeClass = ((TypeVarType) tv).getTypeClass();

            typeVarStore.addTuple(new TypeVarType(typeClass) , exprNew.getTypePlaceHolder());
            //System.out.println(typeClass.getName() + exprNew.getTypePlaceHolder());
            //System.out.println(   + typeClass.getName());


            // Auswertung der Generics und Anpassen der Klasse inkl der Constraints
            Map<String,String> generic = exprNew.getGenerics();
            for (String key : generic.keySet()) {
                //constriants.forEach((ConstraintAbstract cs) -> cs.replace(new TPH(gen)  , new TPH(generic.get(gen)) ));
                String typeVar = key;
                String klasse = generic.get(key);
                TypeVarAbstract klasseType = ass.get("$" + klasse);
                TypeVarType klasseTypeCast = (TypeVarType) klasseType;
            }


            return constraints;
        }
        return null;
    }
}


