package asp.gencay;

import asp.UnifyWithoutWildcards;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.sat.asp.writer.ASPGencayFactory;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.type.ExtendsWildcardType;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.constraints.Pair;
import de.dhbwstuttgart.typeinference.unify.model.ExtendsType;
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
import de.dhbwstuttgart.typeinference.unify.model.WildcardType;
import org.junit.Test;

import java.lang.reflect.Type;
import java.util.*;

public class GeneratorTest extends UnifyWithoutWildcards{
    @Test
    public void simple() throws ClassNotFoundException {
        ConstraintSet<Pair> testSet = new ConstraintSet<>();
        List<RefTypeOrTPHOrWildcardOrGeneric> list1 = Arrays.asList(TypePlaceholder.fresh(new NullToken()));
        List<RefTypeOrTPHOrWildcardOrGeneric> list2 = Arrays.asList(TypePlaceholder.fresh(new NullToken()));
        RefType t1 = new RefType(new JavaClassName("java.util.List"), list1, new NullToken());
        RefType t2 = new RefType(new JavaClassName("java.util.List"), list2, new NullToken());
        testSet.addUndConstraint(new Pair(t1, t2, PairOperator.SMALLERDOT));
        String resultSet = ASPGencayFactory.generateASP(testSet,
                new HashSet<>(Arrays.asList(ASTFactory.createClass(List.class))));
        System.out.println(resultSet);
    }

    @Test
    public void matrix() throws ClassNotFoundException {
        ConstraintSet<Pair> testSet = new ConstraintSet<>();
        List<RefTypeOrTPHOrWildcardOrGeneric> list1 = Arrays.asList(TypePlaceholder.fresh(new NullToken()));
        List<RefTypeOrTPHOrWildcardOrGeneric> list2 = Arrays.asList(TypePlaceholder.fresh(new NullToken()),TypePlaceholder.fresh(new NullToken()));
        RefType t1 = new RefType(new JavaClassName("asp.UnifyWithoutWildcards$Matrix"), list1, new NullToken());
        RefType t2 = new RefType(new JavaClassName("java.util.HashMap"), list2, new NullToken());
        testSet.addUndConstraint(new Pair(t1, t2, PairOperator.SMALLERDOT));
        String resultSet = ASPGencayFactory.generateASP(testSet, this.getFC());
        System.out.println(resultSet);
    }

    @Test
    public void wildcardExample() throws ClassNotFoundException { //Das Beispiel aus dem Paper
        ConstraintSet<Pair> testSet = new ConstraintSet<>();

        TypePlaceholder tphA = TypePlaceholder.fresh(new NullToken());
        RefType number = new RefType(new JavaClassName(Number.class.getName()), new ArrayList<>(), new NullToken());
        ExtendsWildcardType extendsNumber = new ExtendsWildcardType(number, new NullToken());
        List<RefTypeOrTPHOrWildcardOrGeneric> list1 = Arrays.asList(tphA);
        List<RefTypeOrTPHOrWildcardOrGeneric> list2 = Arrays.asList(extendsNumber);
        RefType stack = new RefType(new JavaClassName(Stack.class.getName()), list1, new NullToken());
        RefType vector = new RefType(new JavaClassName(Vector.class.getName()), list2, new NullToken());
        testSet.addUndConstraint(new Pair(stack, vector, PairOperator.SMALLERDOT));


        Set<ClassOrInterface> fc = new HashSet<>();
        fc.add(ASTFactory.createClass(Stack.class));
        fc.add(ASTFactory.createClass(AbstractList.class));
        fc.add(ASTFactory.createClass(Integer.class));

        String resultSet = ASPGencayFactory.generateASP(testSet, fc);
        System.out.println(resultSet);
    }

    @Test
    public void example5() throws ClassNotFoundException { //Das Beispiel aus dem Paper
        ConstraintSet<Pair> testSet = new ConstraintSet<>();

        TypePlaceholder tphA = TypePlaceholder.fresh(new NullToken());
        RefType number = new RefType(new JavaClassName(Number.class.getName()), new ArrayList<>(), new NullToken());
        ExtendsWildcardType extendsNumber = new ExtendsWildcardType(number, new NullToken());
        List<RefTypeOrTPHOrWildcardOrGeneric> list1 = Arrays.asList(tphA);
        List<RefTypeOrTPHOrWildcardOrGeneric> list2 = Arrays.asList(extendsNumber);
        RefType stack = new RefType(new JavaClassName(Stack.class.getName()), list1, new NullToken());
        RefType vector = new RefType(new JavaClassName(Vector.class.getName()), list2, new NullToken());
        testSet.addUndConstraint(new Pair(stack, vector, PairOperator.SMALLERDOT));

        RefType integer = new RefType(new JavaClassName(Integer.class.getName()), new ArrayList<>(), new NullToken());
        List<RefTypeOrTPHOrWildcardOrGeneric> list3 = Arrays.asList(integer);
        List<RefTypeOrTPHOrWildcardOrGeneric> list4 = Arrays.asList(tphA);
        RefType abstractList = new RefType(new JavaClassName(AbstractList.class.getName()), list3, new NullToken());
        RefType list = new RefType(new JavaClassName(List.class.getName()), list4, new NullToken());

        testSet.addUndConstraint(new Pair(abstractList, list, PairOperator.SMALLERDOT));


        Set<ClassOrInterface> fc = new HashSet<>();
        fc.add(ASTFactory.createClass(Stack.class));
        fc.add(ASTFactory.createClass(Vector.class));
        fc.add(ASTFactory.createClass(AbstractList.class));
        fc.add(ASTFactory.createClass(List.class));
        fc.add(ASTFactory.createClass(Integer.class));
        fc.add(ASTFactory.createClass(Number.class));

        String resultSet = ASPGencayFactory.generateASP(testSet, fc);
        System.out.println(resultSet);
    }

    private Collection<ClassOrInterface> getFC() {
        Set<ClassOrInterface> ret = new HashSet<>();
        ret.add(ASTFactory.createClass(Matrix.class));
        ret.add(ASTFactory.createClass(Stack.class));
        ret.add(ASTFactory.createClass(AbstractList.class));
        //ret.add(ASTFactory.createObjectClass());
        //ret.add(ASTFactory.createClass(java.util.List.class));
        return ret;
    }
}

class Matrix extends Vector<Vector<Integer>> {}